Completed
Branch FET/11399/verify-paypal-creden... (c7ad03)
by
unknown
66:22 queued 52:43
created
modules/ticket_selector/ProcessTicketSelector.php 3 patches
Doc Comments   +4 added lines, -4 removed lines patch added patch discarded remove patch
@@ -42,7 +42,7 @@  discard block
 block discarded – undo
42 42
     /**
43 43
      * cancelTicketSelections
44 44
      *
45
-     * @return        string
45
+     * @return        false|null
46 46
      * @throws EE_Error
47 47
      * @throws InvalidArgumentException
48 48
      * @throws InvalidInterfaceException
@@ -114,7 +114,7 @@  discard block
 block discarded – undo
114 114
     /**
115 115
      * process_ticket_selections
116 116
      *
117
-     * @return array|bool
117
+     * @return null|boolean
118 118
      * @throws \ReflectionException
119 119
      * @throws InvalidArgumentException
120 120
      * @throws InvalidInterfaceException
@@ -298,7 +298,7 @@  discard block
 block discarded – undo
298 298
      * validate_post_data
299 299
      *
300 300
      * @param int $id
301
-     * @return array|FALSE
301
+     * @return string
302 302
      * @throws \ReflectionException
303 303
      * @throws InvalidArgumentException
304 304
      * @throws InvalidInterfaceException
@@ -421,7 +421,7 @@  discard block
 block discarded – undo
421 421
      *
422 422
      * @param EE_Ticket $ticket
423 423
      * @param int        $qty
424
-     * @return TRUE on success, FALSE on fail
424
+     * @return boolean on success, FALSE on fail
425 425
      * @throws InvalidArgumentException
426 426
      * @throws InvalidInterfaceException
427 427
      * @throws InvalidDataTypeException
Please login to merge, or discard this patch.
Indentation   +579 added lines, -579 removed lines patch added patch discarded remove patch
@@ -14,7 +14,7 @@  discard block
 block discarded – undo
14 14
 use InvalidArgumentException;
15 15
 
16 16
 if (! defined('EVENT_ESPRESSO_VERSION')) {
17
-    exit('No direct script access allowed');
17
+	exit('No direct script access allowed');
18 18
 }
19 19
 
20 20
 
@@ -31,602 +31,602 @@  discard block
 block discarded – undo
31 31
 class ProcessTicketSelector
32 32
 {
33 33
 
34
-    /**
35
-     * array of datetimes and the spaces available for them
36
-     *
37
-     * @var array[][]
38
-     */
39
-    private static $_available_spaces = array();
34
+	/**
35
+	 * array of datetimes and the spaces available for them
36
+	 *
37
+	 * @var array[][]
38
+	 */
39
+	private static $_available_spaces = array();
40 40
 
41 41
 
42
-    /**
43
-     * cancelTicketSelections
44
-     *
45
-     * @return        string
46
-     * @throws EE_Error
47
-     * @throws InvalidArgumentException
48
-     * @throws InvalidInterfaceException
49
-     * @throws InvalidDataTypeException
50
-     */
51
-    public function cancelTicketSelections()
52
-    {
53
-        // check nonce
54
-        if (! $this->processTicketSelectorNonce('cancel_ticket_selections')) {
55
-            return false;
56
-        }
57
-        EE_Registry::instance()->SSN->clear_session(__CLASS__, __FUNCTION__);
58
-        if (EE_Registry::instance()->REQ->is_set('event_id')) {
59
-            wp_safe_redirect(
60
-                EEH_Event_View::event_link_url(
61
-                    EE_Registry::instance()->REQ->get('event_id')
62
-                )
63
-            );
64
-        } else {
65
-            wp_safe_redirect(
66
-                site_url('/' . EE_Registry::instance()->CFG->core->event_cpt_slug . '/')
67
-            );
68
-        }
69
-        exit();
70
-    }
42
+	/**
43
+	 * cancelTicketSelections
44
+	 *
45
+	 * @return        string
46
+	 * @throws EE_Error
47
+	 * @throws InvalidArgumentException
48
+	 * @throws InvalidInterfaceException
49
+	 * @throws InvalidDataTypeException
50
+	 */
51
+	public function cancelTicketSelections()
52
+	{
53
+		// check nonce
54
+		if (! $this->processTicketSelectorNonce('cancel_ticket_selections')) {
55
+			return false;
56
+		}
57
+		EE_Registry::instance()->SSN->clear_session(__CLASS__, __FUNCTION__);
58
+		if (EE_Registry::instance()->REQ->is_set('event_id')) {
59
+			wp_safe_redirect(
60
+				EEH_Event_View::event_link_url(
61
+					EE_Registry::instance()->REQ->get('event_id')
62
+				)
63
+			);
64
+		} else {
65
+			wp_safe_redirect(
66
+				site_url('/' . EE_Registry::instance()->CFG->core->event_cpt_slug . '/')
67
+			);
68
+		}
69
+		exit();
70
+	}
71 71
 
72 72
 
73
-    /**
74
-     * processTicketSelectorNonce
75
-     *
76
-     * @param  string $nonce_name
77
-     * @param string  $id
78
-     * @return bool
79
-     * @throws InvalidArgumentException
80
-     * @throws InvalidInterfaceException
81
-     * @throws InvalidDataTypeException
82
-     */
83
-    private function processTicketSelectorNonce($nonce_name, $id = '')
84
-    {
85
-        $nonce_name_with_id = ! empty($id) ? "{$nonce_name}_nonce_{$id}" : "{$nonce_name}_nonce";
86
-        if (
87
-            ! is_admin()
88
-            && (
89
-                ! EE_Registry::instance()->REQ->is_set($nonce_name_with_id)
90
-                || ! wp_verify_nonce(
91
-                    EE_Registry::instance()->REQ->get($nonce_name_with_id),
92
-                    $nonce_name
93
-                )
94
-            )
95
-        ) {
96
-            EE_Error::add_error(
97
-                sprintf(
98
-                    __(
99
-                        'We\'re sorry but your request failed to pass a security check.%sPlease click the back button on your browser and try again.',
100
-                        'event_espresso'
101
-                    ),
102
-                    '<br/>'
103
-                ),
104
-                __FILE__,
105
-                __FUNCTION__,
106
-                __LINE__
107
-            );
108
-            return false;
109
-        }
110
-        return true;
111
-    }
73
+	/**
74
+	 * processTicketSelectorNonce
75
+	 *
76
+	 * @param  string $nonce_name
77
+	 * @param string  $id
78
+	 * @return bool
79
+	 * @throws InvalidArgumentException
80
+	 * @throws InvalidInterfaceException
81
+	 * @throws InvalidDataTypeException
82
+	 */
83
+	private function processTicketSelectorNonce($nonce_name, $id = '')
84
+	{
85
+		$nonce_name_with_id = ! empty($id) ? "{$nonce_name}_nonce_{$id}" : "{$nonce_name}_nonce";
86
+		if (
87
+			! is_admin()
88
+			&& (
89
+				! EE_Registry::instance()->REQ->is_set($nonce_name_with_id)
90
+				|| ! wp_verify_nonce(
91
+					EE_Registry::instance()->REQ->get($nonce_name_with_id),
92
+					$nonce_name
93
+				)
94
+			)
95
+		) {
96
+			EE_Error::add_error(
97
+				sprintf(
98
+					__(
99
+						'We\'re sorry but your request failed to pass a security check.%sPlease click the back button on your browser and try again.',
100
+						'event_espresso'
101
+					),
102
+					'<br/>'
103
+				),
104
+				__FILE__,
105
+				__FUNCTION__,
106
+				__LINE__
107
+			);
108
+			return false;
109
+		}
110
+		return true;
111
+	}
112 112
 
113 113
 
114
-    /**
115
-     * process_ticket_selections
116
-     *
117
-     * @return array|bool
118
-     * @throws \ReflectionException
119
-     * @throws InvalidArgumentException
120
-     * @throws InvalidInterfaceException
121
-     * @throws InvalidDataTypeException
122
-     * @throws EE_Error
123
-     */
124
-    public function processTicketSelections()
125
-    {
126
-        do_action('EED_Ticket_Selector__process_ticket_selections__before');
127
-        $request = LoaderFactory::getLoader()->getShared('EventEspresso\core\services\request\Request');
128
-        if($request->isBot()) {
129
-            wp_safe_redirect(
130
-                apply_filters(
131
-                    'FHEE__EE_Ticket_Selector__process_ticket_selections__bot_redirect_url',
132
-                    site_url()
133
-                )
134
-            );
135
-            exit();
136
-        }
137
-        // do we have an event id?
138
-        if (! EE_Registry::instance()->REQ->is_set('tkt-slctr-event-id')) {
139
-            // $_POST['tkt-slctr-event-id'] was not set ?!?!?!?
140
-            EE_Error::add_error(
141
-                sprintf(
142
-                    __(
143
-                        'An event id was not provided or was not received.%sPlease click the back button on your browser and try again.',
144
-                        'event_espresso'
145
-                    ),
146
-                    '<br/>'
147
-                ),
148
-                __FILE__,
149
-                __FUNCTION__,
150
-                __LINE__
151
-            );
152
-        }
153
-        //if event id is valid
154
-        $id = absint(EE_Registry::instance()->REQ->get('tkt-slctr-event-id'));
155
-        //		d( \EE_Registry::instance()->REQ );
156
-        self::$_available_spaces = array(
157
-            'tickets'   => array(),
158
-            'datetimes' => array(),
159
-        );
160
-        //we should really only have 1 registration in the works now (ie, no MER) so clear any previous items in the cart.
161
-        // When MER happens this will probably need to be tweaked, possibly wrapped in a conditional checking for some constant defined in MER etc.
162
-        EE_Registry::instance()->load_core('Session');
163
-        // unless otherwise requested, clear the session
164
-        if (apply_filters('FHEE__EE_Ticket_Selector__process_ticket_selections__clear_session', true)) {
165
-            EE_Registry::instance()->SSN->clear_session(__CLASS__, __FUNCTION__);
166
-        }
167
-        //d( \EE_Registry::instance()->SSN );
168
-        do_action('AHEE_log', __FILE__, __FUNCTION__, '');
169
-        // validate/sanitize data
170
-        $valid = $this->validatePostData($id);
171
-        //EEH_Debug_Tools::printr( $_REQUEST, '$_REQUEST', __FILE__, __LINE__ );
172
-        //EEH_Debug_Tools::printr( $valid, '$valid', __FILE__, __LINE__ );
173
-        //EEH_Debug_Tools::printr( $valid[ 'total_tickets' ], 'total_tickets', __FILE__, __LINE__ );
174
-        //EEH_Debug_Tools::printr( $valid[ 'max_atndz' ], 'max_atndz', __FILE__, __LINE__ );
175
-        //check total tickets ordered vs max number of attendees that can register
176
-        if ($valid['total_tickets'] > $valid['max_atndz']) {
177
-            // ordering too many tickets !!!
178
-            $total_tickets_string = _n(
179
-                'You have attempted to purchase %s ticket.',
180
-                'You have attempted to purchase %s tickets.',
181
-                $valid['total_tickets'],
182
-                'event_espresso'
183
-            );
184
-            $limit_error_1        = sprintf($total_tickets_string, $valid['total_tickets']);
185
-            // dev only message
186
-            $max_atndz_string = _n(
187
-                'The registration limit for this event is %s ticket per registration, therefore the total number of tickets you may purchase at a time can not exceed %s.',
188
-                'The registration limit for this event is %s tickets per registration, therefore the total number of tickets you may purchase at a time can not exceed %s.',
189
-                $valid['max_atndz'],
190
-                'event_espresso'
191
-            );
192
-            $limit_error_2    = sprintf($max_atndz_string, $valid['max_atndz'], $valid['max_atndz']);
193
-            EE_Error::add_error($limit_error_1 . '<br/>' . $limit_error_2, __FILE__, __FUNCTION__, __LINE__);
194
-        } else {
195
-            // all data appears to be valid
196
-            $tckts_slctd   = false;
197
-            $tickets_added = 0;
198
-            $valid         = apply_filters('FHEE__EED_Ticket_Selector__process_ticket_selections__valid_post_data',
199
-                $valid);
200
-            if ($valid['total_tickets'] > 0) {
201
-                // load cart
202
-                EE_Registry::instance()->load_core('Cart');
203
-                // cycle thru the number of data rows sent from the event listing
204
-                for ($x = 0; $x < $valid['rows']; $x++) {
205
-                    // does this row actually contain a ticket quantity?
206
-                    if (isset($valid['qty'][ $x ]) && $valid['qty'][ $x ] > 0) {
207
-                        // YES we have a ticket quantity
208
-                        $tckts_slctd = true;
209
-                        //						d( $valid['ticket_obj'][$x] );
210
-                        if ($valid['ticket_obj'][ $x ] instanceof EE_Ticket) {
211
-                            // then add ticket to cart
212
-                            $tickets_added += $this->addTicketToCart(
213
-                                $valid['ticket_obj'][ $x ],
214
-                                $valid['qty'][ $x ]
215
-                            );
216
-                            if (EE_Error::has_error()) {
217
-                                break;
218
-                            }
219
-                        } else {
220
-                            // nothing added to cart retrieved
221
-                            EE_Error::add_error(
222
-                                sprintf(
223
-                                    __(
224
-                                        'A valid ticket could not be retrieved for the event.%sPlease click the back button on your browser and try again.',
225
-                                        'event_espresso'
226
-                                    ),
227
-                                    '<br/>'
228
-                                ),
229
-                                __FILE__, __FUNCTION__, __LINE__
230
-                            );
231
-                        }
232
-                    }
233
-                }
234
-            }
235
-            do_action(
236
-                'AHEE__EE_Ticket_Selector__process_ticket_selections__after_tickets_added_to_cart',
237
-                EE_Registry::instance()->CART,
238
-                $this
239
-            );
240
-            //d( \EE_Registry::instance()->CART );
241
-            //die(); // <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<< KILL REDIRECT HERE BEFORE CART UPDATE
242
-            if (apply_filters('FHEE__EED_Ticket_Selector__process_ticket_selections__tckts_slctd', $tckts_slctd)) {
243
-                if (apply_filters('FHEE__EED_Ticket_Selector__process_ticket_selections__success', $tickets_added)) {
244
-                    do_action(
245
-                        'FHEE__EE_Ticket_Selector__process_ticket_selections__before_redirecting_to_checkout',
246
-                        EE_Registry::instance()->CART,
247
-                        $this
248
-                    );
249
-                    EE_Registry::instance()->CART->recalculate_all_cart_totals();
250
-                    EE_Registry::instance()->CART->save_cart(false);
251
-                    // exit('KILL REDIRECT AFTER CART UPDATE'); // <<<<<<<<  OR HERE TO KILL REDIRECT AFTER CART UPDATE
252
-                    // just return TRUE for registrations being made from admin
253
-                    if (is_admin()) {
254
-                        return true;
255
-                    }
256
-                    EE_Error::get_notices(false, true);
257
-                    wp_safe_redirect(
258
-                        apply_filters(
259
-                            'FHEE__EE_Ticket_Selector__process_ticket_selections__success_redirect_url',
260
-                            EE_Registry::instance()->CFG->core->reg_page_url()
261
-                        )
262
-                    );
263
-                    exit();
264
-                } else {
265
-                    if (! EE_Error::has_error() && ! EE_Error::has_error(true, 'attention')) {
266
-                        // nothing added to cart
267
-                        EE_Error::add_attention(__('No tickets were added for the event', 'event_espresso'),
268
-                            __FILE__, __FUNCTION__, __LINE__);
269
-                    }
270
-                }
271
-            } else {
272
-                // no ticket quantities were selected
273
-                EE_Error::add_error(__('You need to select a ticket quantity before you can proceed.',
274
-                    'event_espresso'), __FILE__, __FUNCTION__, __LINE__);
275
-            }
276
-        }
277
-        //die(); // <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<< KILL BEFORE REDIRECT
278
-        // at this point, just return if registration is being made from admin
279
-        if (is_admin()) {
280
-            return false;
281
-        }
282
-        if ($valid['return_url']) {
283
-            EE_Error::get_notices(false, true);
284
-            wp_safe_redirect($valid['return_url']);
285
-            exit();
286
-        } elseif (isset($event_to_add['id'])) {
287
-            EE_Error::get_notices(false, true);
288
-            wp_safe_redirect(get_permalink($event_to_add['id']));
289
-            exit();
290
-        } else {
291
-            echo EE_Error::get_notices();
292
-        }
293
-        return false;
294
-    }
114
+	/**
115
+	 * process_ticket_selections
116
+	 *
117
+	 * @return array|bool
118
+	 * @throws \ReflectionException
119
+	 * @throws InvalidArgumentException
120
+	 * @throws InvalidInterfaceException
121
+	 * @throws InvalidDataTypeException
122
+	 * @throws EE_Error
123
+	 */
124
+	public function processTicketSelections()
125
+	{
126
+		do_action('EED_Ticket_Selector__process_ticket_selections__before');
127
+		$request = LoaderFactory::getLoader()->getShared('EventEspresso\core\services\request\Request');
128
+		if($request->isBot()) {
129
+			wp_safe_redirect(
130
+				apply_filters(
131
+					'FHEE__EE_Ticket_Selector__process_ticket_selections__bot_redirect_url',
132
+					site_url()
133
+				)
134
+			);
135
+			exit();
136
+		}
137
+		// do we have an event id?
138
+		if (! EE_Registry::instance()->REQ->is_set('tkt-slctr-event-id')) {
139
+			// $_POST['tkt-slctr-event-id'] was not set ?!?!?!?
140
+			EE_Error::add_error(
141
+				sprintf(
142
+					__(
143
+						'An event id was not provided or was not received.%sPlease click the back button on your browser and try again.',
144
+						'event_espresso'
145
+					),
146
+					'<br/>'
147
+				),
148
+				__FILE__,
149
+				__FUNCTION__,
150
+				__LINE__
151
+			);
152
+		}
153
+		//if event id is valid
154
+		$id = absint(EE_Registry::instance()->REQ->get('tkt-slctr-event-id'));
155
+		//		d( \EE_Registry::instance()->REQ );
156
+		self::$_available_spaces = array(
157
+			'tickets'   => array(),
158
+			'datetimes' => array(),
159
+		);
160
+		//we should really only have 1 registration in the works now (ie, no MER) so clear any previous items in the cart.
161
+		// When MER happens this will probably need to be tweaked, possibly wrapped in a conditional checking for some constant defined in MER etc.
162
+		EE_Registry::instance()->load_core('Session');
163
+		// unless otherwise requested, clear the session
164
+		if (apply_filters('FHEE__EE_Ticket_Selector__process_ticket_selections__clear_session', true)) {
165
+			EE_Registry::instance()->SSN->clear_session(__CLASS__, __FUNCTION__);
166
+		}
167
+		//d( \EE_Registry::instance()->SSN );
168
+		do_action('AHEE_log', __FILE__, __FUNCTION__, '');
169
+		// validate/sanitize data
170
+		$valid = $this->validatePostData($id);
171
+		//EEH_Debug_Tools::printr( $_REQUEST, '$_REQUEST', __FILE__, __LINE__ );
172
+		//EEH_Debug_Tools::printr( $valid, '$valid', __FILE__, __LINE__ );
173
+		//EEH_Debug_Tools::printr( $valid[ 'total_tickets' ], 'total_tickets', __FILE__, __LINE__ );
174
+		//EEH_Debug_Tools::printr( $valid[ 'max_atndz' ], 'max_atndz', __FILE__, __LINE__ );
175
+		//check total tickets ordered vs max number of attendees that can register
176
+		if ($valid['total_tickets'] > $valid['max_atndz']) {
177
+			// ordering too many tickets !!!
178
+			$total_tickets_string = _n(
179
+				'You have attempted to purchase %s ticket.',
180
+				'You have attempted to purchase %s tickets.',
181
+				$valid['total_tickets'],
182
+				'event_espresso'
183
+			);
184
+			$limit_error_1        = sprintf($total_tickets_string, $valid['total_tickets']);
185
+			// dev only message
186
+			$max_atndz_string = _n(
187
+				'The registration limit for this event is %s ticket per registration, therefore the total number of tickets you may purchase at a time can not exceed %s.',
188
+				'The registration limit for this event is %s tickets per registration, therefore the total number of tickets you may purchase at a time can not exceed %s.',
189
+				$valid['max_atndz'],
190
+				'event_espresso'
191
+			);
192
+			$limit_error_2    = sprintf($max_atndz_string, $valid['max_atndz'], $valid['max_atndz']);
193
+			EE_Error::add_error($limit_error_1 . '<br/>' . $limit_error_2, __FILE__, __FUNCTION__, __LINE__);
194
+		} else {
195
+			// all data appears to be valid
196
+			$tckts_slctd   = false;
197
+			$tickets_added = 0;
198
+			$valid         = apply_filters('FHEE__EED_Ticket_Selector__process_ticket_selections__valid_post_data',
199
+				$valid);
200
+			if ($valid['total_tickets'] > 0) {
201
+				// load cart
202
+				EE_Registry::instance()->load_core('Cart');
203
+				// cycle thru the number of data rows sent from the event listing
204
+				for ($x = 0; $x < $valid['rows']; $x++) {
205
+					// does this row actually contain a ticket quantity?
206
+					if (isset($valid['qty'][ $x ]) && $valid['qty'][ $x ] > 0) {
207
+						// YES we have a ticket quantity
208
+						$tckts_slctd = true;
209
+						//						d( $valid['ticket_obj'][$x] );
210
+						if ($valid['ticket_obj'][ $x ] instanceof EE_Ticket) {
211
+							// then add ticket to cart
212
+							$tickets_added += $this->addTicketToCart(
213
+								$valid['ticket_obj'][ $x ],
214
+								$valid['qty'][ $x ]
215
+							);
216
+							if (EE_Error::has_error()) {
217
+								break;
218
+							}
219
+						} else {
220
+							// nothing added to cart retrieved
221
+							EE_Error::add_error(
222
+								sprintf(
223
+									__(
224
+										'A valid ticket could not be retrieved for the event.%sPlease click the back button on your browser and try again.',
225
+										'event_espresso'
226
+									),
227
+									'<br/>'
228
+								),
229
+								__FILE__, __FUNCTION__, __LINE__
230
+							);
231
+						}
232
+					}
233
+				}
234
+			}
235
+			do_action(
236
+				'AHEE__EE_Ticket_Selector__process_ticket_selections__after_tickets_added_to_cart',
237
+				EE_Registry::instance()->CART,
238
+				$this
239
+			);
240
+			//d( \EE_Registry::instance()->CART );
241
+			//die(); // <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<< KILL REDIRECT HERE BEFORE CART UPDATE
242
+			if (apply_filters('FHEE__EED_Ticket_Selector__process_ticket_selections__tckts_slctd', $tckts_slctd)) {
243
+				if (apply_filters('FHEE__EED_Ticket_Selector__process_ticket_selections__success', $tickets_added)) {
244
+					do_action(
245
+						'FHEE__EE_Ticket_Selector__process_ticket_selections__before_redirecting_to_checkout',
246
+						EE_Registry::instance()->CART,
247
+						$this
248
+					);
249
+					EE_Registry::instance()->CART->recalculate_all_cart_totals();
250
+					EE_Registry::instance()->CART->save_cart(false);
251
+					// exit('KILL REDIRECT AFTER CART UPDATE'); // <<<<<<<<  OR HERE TO KILL REDIRECT AFTER CART UPDATE
252
+					// just return TRUE for registrations being made from admin
253
+					if (is_admin()) {
254
+						return true;
255
+					}
256
+					EE_Error::get_notices(false, true);
257
+					wp_safe_redirect(
258
+						apply_filters(
259
+							'FHEE__EE_Ticket_Selector__process_ticket_selections__success_redirect_url',
260
+							EE_Registry::instance()->CFG->core->reg_page_url()
261
+						)
262
+					);
263
+					exit();
264
+				} else {
265
+					if (! EE_Error::has_error() && ! EE_Error::has_error(true, 'attention')) {
266
+						// nothing added to cart
267
+						EE_Error::add_attention(__('No tickets were added for the event', 'event_espresso'),
268
+							__FILE__, __FUNCTION__, __LINE__);
269
+					}
270
+				}
271
+			} else {
272
+				// no ticket quantities were selected
273
+				EE_Error::add_error(__('You need to select a ticket quantity before you can proceed.',
274
+					'event_espresso'), __FILE__, __FUNCTION__, __LINE__);
275
+			}
276
+		}
277
+		//die(); // <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<< KILL BEFORE REDIRECT
278
+		// at this point, just return if registration is being made from admin
279
+		if (is_admin()) {
280
+			return false;
281
+		}
282
+		if ($valid['return_url']) {
283
+			EE_Error::get_notices(false, true);
284
+			wp_safe_redirect($valid['return_url']);
285
+			exit();
286
+		} elseif (isset($event_to_add['id'])) {
287
+			EE_Error::get_notices(false, true);
288
+			wp_safe_redirect(get_permalink($event_to_add['id']));
289
+			exit();
290
+		} else {
291
+			echo EE_Error::get_notices();
292
+		}
293
+		return false;
294
+	}
295 295
 
296 296
 
297
-    /**
298
-     * validate_post_data
299
-     *
300
-     * @param int $id
301
-     * @return array|FALSE
302
-     * @throws \ReflectionException
303
-     * @throws InvalidArgumentException
304
-     * @throws InvalidInterfaceException
305
-     * @throws InvalidDataTypeException
306
-     * @throws EE_Error
307
-     */
308
-    private function validatePostData($id = 0)
309
-    {
310
-        do_action('AHEE_log', __FILE__, __FUNCTION__, '');
311
-        if (! $id) {
312
-            EE_Error::add_error(
313
-                __('The event id provided was not valid.', 'event_espresso'),
314
-                __FILE__,
315
-                __FUNCTION__,
316
-                __LINE__
317
-            );
318
-            return false;
319
-        }
320
-        // start with an empty array()
321
-        $valid_data = array();
322
-        // grab valid id
323
-        $valid_data['id'] = $id;
324
-        // array of other form names
325
-        $inputs_to_clean = array(
326
-            'event_id'   => 'tkt-slctr-event-id',
327
-            'max_atndz'  => 'tkt-slctr-max-atndz-',
328
-            'rows'       => 'tkt-slctr-rows-',
329
-            'qty'        => 'tkt-slctr-qty-',
330
-            'ticket_id'  => 'tkt-slctr-ticket-id-',
331
-            'return_url' => 'tkt-slctr-return-url-',
332
-        );
333
-        // let's track the total number of tickets ordered.'
334
-        $valid_data['total_tickets'] = 0;
335
-        // cycle through $inputs_to_clean array
336
-        foreach ($inputs_to_clean as $what => $input_to_clean) {
337
-            // check for POST data
338
-            if (EE_Registry::instance()->REQ->is_set($input_to_clean . $id)) {
339
-                // grab value
340
-                $input_value = EE_Registry::instance()->REQ->get($input_to_clean . $id);
341
-                switch ($what) {
342
-                    // integers
343
-                    case 'event_id':
344
-                        $valid_data[ $what ] = absint($input_value);
345
-                        // get event via the event id we put in the form
346
-                        $valid_data['event'] = EE_Registry::instance()
347
-                                                           ->load_model('Event')
348
-                                                           ->get_one_by_ID($valid_data['event_id']);
349
-                        break;
350
-                    case 'rows':
351
-                    case 'max_atndz':
352
-                        $valid_data[ $what ] = absint($input_value);
353
-                        break;
354
-                    // arrays of integers
355
-                    case 'qty':
356
-                        /** @var array $row_qty */
357
-                        $row_qty = $input_value;
358
-                        // if qty is coming from a radio button input, then we need to assemble an array of rows
359
-                        if (! is_array($row_qty)) {
360
-                            // get number of rows
361
-                            $rows = EE_Registry::instance()->REQ->is_set('tkt-slctr-rows-' . $id)
362
-                                ? absint(EE_Registry::instance()->REQ->get('tkt-slctr-rows-' . $id))
363
-                                : 1;
364
-                            // explode ints by the dash
365
-                            $row_qty = explode('-', $row_qty);
366
-                            $row     = isset($row_qty[0]) ? absint($row_qty[0]) : 1;
367
-                            $qty     = isset($row_qty[1]) ? absint($row_qty[1]) : 0;
368
-                            $row_qty = array($row => $qty);
369
-                            for ($x = 1; $x <= $rows; $x++) {
370
-                                if (! isset($row_qty[ $x ])) {
371
-                                    $row_qty[ $x ] = 0;
372
-                                }
373
-                            }
374
-                        }
375
-                        ksort($row_qty);
376
-                        // cycle thru values
377
-                        foreach ($row_qty as $qty) {
378
-                            $qty = absint($qty);
379
-                            // sanitize as integers
380
-                            $valid_data[ $what ][]       = $qty;
381
-                            $valid_data['total_tickets'] += $qty;
382
-                        }
383
-                        break;
384
-                    // array of integers
385
-                    case 'ticket_id':
386
-                        $value_array = array();
387
-                        // cycle thru values
388
-                        foreach ((array) $input_value as $key => $value) {
389
-                            // allow only numbers, letters,  spaces, commas and dashes
390
-                            $value_array[ $key ] = wp_strip_all_tags($value);
391
-                            // get ticket via the ticket id we put in the form
392
-                            $ticket_obj                       = EE_Registry::instance()
393
-                                                                            ->load_model('Ticket')
394
-                                                                            ->get_one_by_ID($value);
395
-                            $valid_data['ticket_obj'][ $key ] = $ticket_obj;
396
-                        }
397
-                        $valid_data[ $what ] = $value_array;
398
-                        break;
399
-                    case 'return_url' :
400
-                        // grab and sanitize return-url
401
-                        $input_value = esc_url_raw($input_value);
402
-                        // was the request coming from an iframe ? if so, then:
403
-                        if (strpos($input_value, 'event_list=iframe')) {
404
-                            // get anchor fragment
405
-                            $input_value = explode('#', $input_value);
406
-                            $input_value = end($input_value);
407
-                            // use event list url instead, but append anchor
408
-                            $input_value = EEH_Event_View::event_archive_url() . '#' . $input_value;
409
-                        }
410
-                        $valid_data[ $what ] = $input_value;
411
-                        break;
412
-                }    // end switch $what
413
-            }
414
-        }    // end foreach $inputs_to_clean
415
-        return $valid_data;
416
-    }
297
+	/**
298
+	 * validate_post_data
299
+	 *
300
+	 * @param int $id
301
+	 * @return array|FALSE
302
+	 * @throws \ReflectionException
303
+	 * @throws InvalidArgumentException
304
+	 * @throws InvalidInterfaceException
305
+	 * @throws InvalidDataTypeException
306
+	 * @throws EE_Error
307
+	 */
308
+	private function validatePostData($id = 0)
309
+	{
310
+		do_action('AHEE_log', __FILE__, __FUNCTION__, '');
311
+		if (! $id) {
312
+			EE_Error::add_error(
313
+				__('The event id provided was not valid.', 'event_espresso'),
314
+				__FILE__,
315
+				__FUNCTION__,
316
+				__LINE__
317
+			);
318
+			return false;
319
+		}
320
+		// start with an empty array()
321
+		$valid_data = array();
322
+		// grab valid id
323
+		$valid_data['id'] = $id;
324
+		// array of other form names
325
+		$inputs_to_clean = array(
326
+			'event_id'   => 'tkt-slctr-event-id',
327
+			'max_atndz'  => 'tkt-slctr-max-atndz-',
328
+			'rows'       => 'tkt-slctr-rows-',
329
+			'qty'        => 'tkt-slctr-qty-',
330
+			'ticket_id'  => 'tkt-slctr-ticket-id-',
331
+			'return_url' => 'tkt-slctr-return-url-',
332
+		);
333
+		// let's track the total number of tickets ordered.'
334
+		$valid_data['total_tickets'] = 0;
335
+		// cycle through $inputs_to_clean array
336
+		foreach ($inputs_to_clean as $what => $input_to_clean) {
337
+			// check for POST data
338
+			if (EE_Registry::instance()->REQ->is_set($input_to_clean . $id)) {
339
+				// grab value
340
+				$input_value = EE_Registry::instance()->REQ->get($input_to_clean . $id);
341
+				switch ($what) {
342
+					// integers
343
+					case 'event_id':
344
+						$valid_data[ $what ] = absint($input_value);
345
+						// get event via the event id we put in the form
346
+						$valid_data['event'] = EE_Registry::instance()
347
+														   ->load_model('Event')
348
+														   ->get_one_by_ID($valid_data['event_id']);
349
+						break;
350
+					case 'rows':
351
+					case 'max_atndz':
352
+						$valid_data[ $what ] = absint($input_value);
353
+						break;
354
+					// arrays of integers
355
+					case 'qty':
356
+						/** @var array $row_qty */
357
+						$row_qty = $input_value;
358
+						// if qty is coming from a radio button input, then we need to assemble an array of rows
359
+						if (! is_array($row_qty)) {
360
+							// get number of rows
361
+							$rows = EE_Registry::instance()->REQ->is_set('tkt-slctr-rows-' . $id)
362
+								? absint(EE_Registry::instance()->REQ->get('tkt-slctr-rows-' . $id))
363
+								: 1;
364
+							// explode ints by the dash
365
+							$row_qty = explode('-', $row_qty);
366
+							$row     = isset($row_qty[0]) ? absint($row_qty[0]) : 1;
367
+							$qty     = isset($row_qty[1]) ? absint($row_qty[1]) : 0;
368
+							$row_qty = array($row => $qty);
369
+							for ($x = 1; $x <= $rows; $x++) {
370
+								if (! isset($row_qty[ $x ])) {
371
+									$row_qty[ $x ] = 0;
372
+								}
373
+							}
374
+						}
375
+						ksort($row_qty);
376
+						// cycle thru values
377
+						foreach ($row_qty as $qty) {
378
+							$qty = absint($qty);
379
+							// sanitize as integers
380
+							$valid_data[ $what ][]       = $qty;
381
+							$valid_data['total_tickets'] += $qty;
382
+						}
383
+						break;
384
+					// array of integers
385
+					case 'ticket_id':
386
+						$value_array = array();
387
+						// cycle thru values
388
+						foreach ((array) $input_value as $key => $value) {
389
+							// allow only numbers, letters,  spaces, commas and dashes
390
+							$value_array[ $key ] = wp_strip_all_tags($value);
391
+							// get ticket via the ticket id we put in the form
392
+							$ticket_obj                       = EE_Registry::instance()
393
+																			->load_model('Ticket')
394
+																			->get_one_by_ID($value);
395
+							$valid_data['ticket_obj'][ $key ] = $ticket_obj;
396
+						}
397
+						$valid_data[ $what ] = $value_array;
398
+						break;
399
+					case 'return_url' :
400
+						// grab and sanitize return-url
401
+						$input_value = esc_url_raw($input_value);
402
+						// was the request coming from an iframe ? if so, then:
403
+						if (strpos($input_value, 'event_list=iframe')) {
404
+							// get anchor fragment
405
+							$input_value = explode('#', $input_value);
406
+							$input_value = end($input_value);
407
+							// use event list url instead, but append anchor
408
+							$input_value = EEH_Event_View::event_archive_url() . '#' . $input_value;
409
+						}
410
+						$valid_data[ $what ] = $input_value;
411
+						break;
412
+				}    // end switch $what
413
+			}
414
+		}    // end foreach $inputs_to_clean
415
+		return $valid_data;
416
+	}
417 417
 
418 418
 
419
-    /**
420
-     * adds a ticket to the cart
421
-     *
422
-     * @param EE_Ticket $ticket
423
-     * @param int        $qty
424
-     * @return TRUE on success, FALSE on fail
425
-     * @throws InvalidArgumentException
426
-     * @throws InvalidInterfaceException
427
-     * @throws InvalidDataTypeException
428
-     * @throws EE_Error
429
-     */
430
-    private function addTicketToCart(EE_Ticket $ticket = null, $qty = 1)
431
-    {
432
-        do_action('AHEE_log', __FILE__, __FUNCTION__, '');
433
-        // get the number of spaces left for this datetime ticket
434
-        $available_spaces = $this->ticketDatetimeAvailability($ticket);
435
-        // compare available spaces against the number of tickets being purchased
436
-        if ($available_spaces >= $qty) {
437
-            // allow addons to prevent a ticket from being added to cart
438
-            if (
439
-            ! apply_filters(
440
-                'FHEE__EE_Ticket_Selector___add_ticket_to_cart__allow_add_to_cart',
441
-                true,
442
-                $ticket,
443
-                $qty,
444
-                $available_spaces
445
-            )
446
-            ) {
447
-                return false;
448
-            }
449
-            $qty = absint(apply_filters('FHEE__EE_Ticket_Selector___add_ticket_to_cart__ticket_qty', $qty, $ticket));
450
-            // add event to cart
451
-            if (EE_Registry::instance()->CART->add_ticket_to_cart($ticket, $qty)) {
452
-                $this->recalculateTicketDatetimeAvailability($ticket, $qty);
453
-                return true;
454
-            }
455
-            return false;
456
-        }
457
-        // tickets can not be purchased but let's find the exact number left
458
-        // for the last ticket selected PRIOR to subtracting tickets
459
-        $available_spaces = $this->ticketDatetimeAvailability($ticket, true);
460
-        // greedy greedy greedy eh?
461
-        if ($available_spaces > 0) {
462
-            if (
463
-            apply_filters(
464
-                'FHEE__EE_Ticket_Selector___add_ticket_to_cart__allow_display_availability_error',
465
-                true,
466
-                $ticket,
467
-                $qty,
468
-                $available_spaces
469
-            )
470
-            ) {
471
-                $this->displayAvailabilityError($available_spaces);
472
-            }
473
-        } else {
474
-            EE_Error::add_error(
475
-                __(
476
-                    'We\'re sorry, but there are no available spaces left for this event at this particular date and time.',
477
-                    'event_espresso'
478
-                ),
479
-                __FILE__, __FUNCTION__, __LINE__
480
-            );
481
-        }
482
-        return false;
483
-    }
419
+	/**
420
+	 * adds a ticket to the cart
421
+	 *
422
+	 * @param EE_Ticket $ticket
423
+	 * @param int        $qty
424
+	 * @return TRUE on success, FALSE on fail
425
+	 * @throws InvalidArgumentException
426
+	 * @throws InvalidInterfaceException
427
+	 * @throws InvalidDataTypeException
428
+	 * @throws EE_Error
429
+	 */
430
+	private function addTicketToCart(EE_Ticket $ticket = null, $qty = 1)
431
+	{
432
+		do_action('AHEE_log', __FILE__, __FUNCTION__, '');
433
+		// get the number of spaces left for this datetime ticket
434
+		$available_spaces = $this->ticketDatetimeAvailability($ticket);
435
+		// compare available spaces against the number of tickets being purchased
436
+		if ($available_spaces >= $qty) {
437
+			// allow addons to prevent a ticket from being added to cart
438
+			if (
439
+			! apply_filters(
440
+				'FHEE__EE_Ticket_Selector___add_ticket_to_cart__allow_add_to_cart',
441
+				true,
442
+				$ticket,
443
+				$qty,
444
+				$available_spaces
445
+			)
446
+			) {
447
+				return false;
448
+			}
449
+			$qty = absint(apply_filters('FHEE__EE_Ticket_Selector___add_ticket_to_cart__ticket_qty', $qty, $ticket));
450
+			// add event to cart
451
+			if (EE_Registry::instance()->CART->add_ticket_to_cart($ticket, $qty)) {
452
+				$this->recalculateTicketDatetimeAvailability($ticket, $qty);
453
+				return true;
454
+			}
455
+			return false;
456
+		}
457
+		// tickets can not be purchased but let's find the exact number left
458
+		// for the last ticket selected PRIOR to subtracting tickets
459
+		$available_spaces = $this->ticketDatetimeAvailability($ticket, true);
460
+		// greedy greedy greedy eh?
461
+		if ($available_spaces > 0) {
462
+			if (
463
+			apply_filters(
464
+				'FHEE__EE_Ticket_Selector___add_ticket_to_cart__allow_display_availability_error',
465
+				true,
466
+				$ticket,
467
+				$qty,
468
+				$available_spaces
469
+			)
470
+			) {
471
+				$this->displayAvailabilityError($available_spaces);
472
+			}
473
+		} else {
474
+			EE_Error::add_error(
475
+				__(
476
+					'We\'re sorry, but there are no available spaces left for this event at this particular date and time.',
477
+					'event_espresso'
478
+				),
479
+				__FILE__, __FUNCTION__, __LINE__
480
+			);
481
+		}
482
+		return false;
483
+	}
484 484
 
485 485
 
486
-    /**
487
-     * @param int $available_spaces
488
-     * @throws InvalidArgumentException
489
-     * @throws InvalidInterfaceException
490
-     * @throws InvalidDataTypeException
491
-     * @throws EE_Error
492
-     */
493
-    private function displayAvailabilityError($available_spaces = 1)
494
-    {
495
-        // add error messaging - we're using the _n function that will generate
496
-        // the appropriate singular or plural message based on the number of $available_spaces
497
-        if (EE_Registry::instance()->CART->all_ticket_quantity_count()) {
498
-            $msg = sprintf(
499
-                _n(
500
-                    'We\'re sorry, but there is only %1$s available space left for this event at this particular date and time. Please select a different number (or different combination) of tickets by cancelling the current selection and choosing again, or proceed to registration.',
501
-                    'We\'re sorry, but there are only %1$s available spaces left for this event at this particular date and time. Please select a different number (or different combination) of tickets by cancelling the current selection and choosing again, or proceed to registration.',
502
-                    $available_spaces,
503
-                    'event_espresso'
504
-                ),
505
-                $available_spaces,
506
-                '<br />'
507
-            );
508
-        } else {
509
-            $msg = sprintf(
510
-                _n(
511
-                    'We\'re sorry, but there is only %1$s available space left for this event at this particular date and time. Please select a different number (or different combination) of tickets.',
512
-                    'We\'re sorry, but there are only %1$s available spaces left for this event at this particular date and time. Please select a different number (or different combination) of tickets.',
513
-                    $available_spaces,
514
-                    'event_espresso'
515
-                ),
516
-                $available_spaces,
517
-                '<br />'
518
-            );
519
-        }
520
-        EE_Error::add_error($msg, __FILE__, __FUNCTION__, __LINE__);
521
-    }
486
+	/**
487
+	 * @param int $available_spaces
488
+	 * @throws InvalidArgumentException
489
+	 * @throws InvalidInterfaceException
490
+	 * @throws InvalidDataTypeException
491
+	 * @throws EE_Error
492
+	 */
493
+	private function displayAvailabilityError($available_spaces = 1)
494
+	{
495
+		// add error messaging - we're using the _n function that will generate
496
+		// the appropriate singular or plural message based on the number of $available_spaces
497
+		if (EE_Registry::instance()->CART->all_ticket_quantity_count()) {
498
+			$msg = sprintf(
499
+				_n(
500
+					'We\'re sorry, but there is only %1$s available space left for this event at this particular date and time. Please select a different number (or different combination) of tickets by cancelling the current selection and choosing again, or proceed to registration.',
501
+					'We\'re sorry, but there are only %1$s available spaces left for this event at this particular date and time. Please select a different number (or different combination) of tickets by cancelling the current selection and choosing again, or proceed to registration.',
502
+					$available_spaces,
503
+					'event_espresso'
504
+				),
505
+				$available_spaces,
506
+				'<br />'
507
+			);
508
+		} else {
509
+			$msg = sprintf(
510
+				_n(
511
+					'We\'re sorry, but there is only %1$s available space left for this event at this particular date and time. Please select a different number (or different combination) of tickets.',
512
+					'We\'re sorry, but there are only %1$s available spaces left for this event at this particular date and time. Please select a different number (or different combination) of tickets.',
513
+					$available_spaces,
514
+					'event_espresso'
515
+				),
516
+				$available_spaces,
517
+				'<br />'
518
+			);
519
+		}
520
+		EE_Error::add_error($msg, __FILE__, __FUNCTION__, __LINE__);
521
+	}
522 522
 
523 523
 
524
-    /**
525
-     * ticketDatetimeAvailability
526
-     * creates an array of tickets plus all of the datetimes available to each ticket
527
-     * and tracks the spaces remaining for each of those datetimes
528
-     *
529
-     * @param EE_Ticket $ticket - selected ticket
530
-     * @param bool      $get_original_ticket_spaces
531
-     * @return int
532
-     * @throws InvalidArgumentException
533
-     * @throws InvalidInterfaceException
534
-     * @throws InvalidDataTypeException
535
-     * @throws EE_Error
536
-     */
537
-    private function ticketDatetimeAvailability(EE_Ticket $ticket, $get_original_ticket_spaces = false)
538
-    {
539
-        // if the $_available_spaces array has not been set up yet...
540
-        if (! isset(self::$_available_spaces['tickets'][ $ticket->ID() ])) {
541
-            $this->setInitialTicketDatetimeAvailability($ticket);
542
-        }
543
-        $available_spaces = $ticket->qty() - $ticket->sold();
544
-        if (isset(self::$_available_spaces['tickets'][ $ticket->ID() ])) {
545
-            // loop thru tickets, which will ALSO include individual ticket records AND a total
546
-            foreach (self::$_available_spaces['tickets'][ $ticket->ID() ] as $DTD_ID => $spaces) {
547
-                // if we want the original datetime availability BEFORE we started subtracting tickets ?
548
-                if ($get_original_ticket_spaces) {
549
-                    // then grab the available spaces from the "tickets" array
550
-                    // and compare with the above to get the lowest number
551
-                    $available_spaces = min(
552
-                        $available_spaces,
553
-                        self::$_available_spaces['tickets'][ $ticket->ID() ][ $DTD_ID ]
554
-                    );
555
-                } else {
556
-                    // we want the updated ticket availability as stored in the "datetimes" array
557
-                    $available_spaces = min($available_spaces, self::$_available_spaces['datetimes'][ $DTD_ID ]);
558
-                }
559
-            }
560
-        }
561
-        return $available_spaces;
562
-    }
524
+	/**
525
+	 * ticketDatetimeAvailability
526
+	 * creates an array of tickets plus all of the datetimes available to each ticket
527
+	 * and tracks the spaces remaining for each of those datetimes
528
+	 *
529
+	 * @param EE_Ticket $ticket - selected ticket
530
+	 * @param bool      $get_original_ticket_spaces
531
+	 * @return int
532
+	 * @throws InvalidArgumentException
533
+	 * @throws InvalidInterfaceException
534
+	 * @throws InvalidDataTypeException
535
+	 * @throws EE_Error
536
+	 */
537
+	private function ticketDatetimeAvailability(EE_Ticket $ticket, $get_original_ticket_spaces = false)
538
+	{
539
+		// if the $_available_spaces array has not been set up yet...
540
+		if (! isset(self::$_available_spaces['tickets'][ $ticket->ID() ])) {
541
+			$this->setInitialTicketDatetimeAvailability($ticket);
542
+		}
543
+		$available_spaces = $ticket->qty() - $ticket->sold();
544
+		if (isset(self::$_available_spaces['tickets'][ $ticket->ID() ])) {
545
+			// loop thru tickets, which will ALSO include individual ticket records AND a total
546
+			foreach (self::$_available_spaces['tickets'][ $ticket->ID() ] as $DTD_ID => $spaces) {
547
+				// if we want the original datetime availability BEFORE we started subtracting tickets ?
548
+				if ($get_original_ticket_spaces) {
549
+					// then grab the available spaces from the "tickets" array
550
+					// and compare with the above to get the lowest number
551
+					$available_spaces = min(
552
+						$available_spaces,
553
+						self::$_available_spaces['tickets'][ $ticket->ID() ][ $DTD_ID ]
554
+					);
555
+				} else {
556
+					// we want the updated ticket availability as stored in the "datetimes" array
557
+					$available_spaces = min($available_spaces, self::$_available_spaces['datetimes'][ $DTD_ID ]);
558
+				}
559
+			}
560
+		}
561
+		return $available_spaces;
562
+	}
563 563
 
564 564
 
565
-    /**
566
-     * @param EE_Ticket $ticket
567
-     * @return void
568
-     * @throws InvalidArgumentException
569
-     * @throws InvalidInterfaceException
570
-     * @throws InvalidDataTypeException
571
-     * @throws EE_Error
572
-     */
573
-    private function setInitialTicketDatetimeAvailability(EE_Ticket $ticket)
574
-    {
575
-        // first, get all of the datetimes that are available to this ticket
576
-        $datetimes = $ticket->get_many_related(
577
-            'Datetime',
578
-            array(
579
-                array(
580
-                    'DTT_EVT_end' => array(
581
-                        '>=',
582
-                        EEM_Datetime::instance()->current_time_for_query('DTT_EVT_end'),
583
-                    ),
584
-                ),
585
-                'order_by' => array('DTT_EVT_start' => 'ASC'),
586
-            )
587
-        );
588
-        if (! empty($datetimes)) {
589
-            // now loop thru all of the datetimes
590
-            foreach ($datetimes as $datetime) {
591
-                if ($datetime instanceof EE_Datetime) {
592
-                    // the number of spaces available for the datetime without considering individual ticket quantities
593
-                    $spaces_remaining = $datetime->spaces_remaining();
594
-                    // save the total available spaces ( the lesser of the ticket qty minus the number of tickets sold
595
-                    // or the datetime spaces remaining) to this ticket using the datetime ID as the key
596
-                    self::$_available_spaces['tickets'][ $ticket->ID() ][ $datetime->ID() ] = min(
597
-                        $ticket->qty() - $ticket->sold(),
598
-                        $spaces_remaining
599
-                    );
600
-                    // if the remaining spaces for this datetime is already set,
601
-                    // then compare that against the datetime spaces remaining, and take the lowest number,
602
-                    // else just take the datetime spaces remaining, and assign to the datetimes array
603
-                    self::$_available_spaces['datetimes'][ $datetime->ID() ] = isset(
604
-                        self::$_available_spaces['datetimes'][ $datetime->ID() ]
605
-                    )
606
-                        ? min(self::$_available_spaces['datetimes'][ $datetime->ID() ], $spaces_remaining)
607
-                        : $spaces_remaining;
608
-                }
609
-            }
610
-        }
611
-    }
565
+	/**
566
+	 * @param EE_Ticket $ticket
567
+	 * @return void
568
+	 * @throws InvalidArgumentException
569
+	 * @throws InvalidInterfaceException
570
+	 * @throws InvalidDataTypeException
571
+	 * @throws EE_Error
572
+	 */
573
+	private function setInitialTicketDatetimeAvailability(EE_Ticket $ticket)
574
+	{
575
+		// first, get all of the datetimes that are available to this ticket
576
+		$datetimes = $ticket->get_many_related(
577
+			'Datetime',
578
+			array(
579
+				array(
580
+					'DTT_EVT_end' => array(
581
+						'>=',
582
+						EEM_Datetime::instance()->current_time_for_query('DTT_EVT_end'),
583
+					),
584
+				),
585
+				'order_by' => array('DTT_EVT_start' => 'ASC'),
586
+			)
587
+		);
588
+		if (! empty($datetimes)) {
589
+			// now loop thru all of the datetimes
590
+			foreach ($datetimes as $datetime) {
591
+				if ($datetime instanceof EE_Datetime) {
592
+					// the number of spaces available for the datetime without considering individual ticket quantities
593
+					$spaces_remaining = $datetime->spaces_remaining();
594
+					// save the total available spaces ( the lesser of the ticket qty minus the number of tickets sold
595
+					// or the datetime spaces remaining) to this ticket using the datetime ID as the key
596
+					self::$_available_spaces['tickets'][ $ticket->ID() ][ $datetime->ID() ] = min(
597
+						$ticket->qty() - $ticket->sold(),
598
+						$spaces_remaining
599
+					);
600
+					// if the remaining spaces for this datetime is already set,
601
+					// then compare that against the datetime spaces remaining, and take the lowest number,
602
+					// else just take the datetime spaces remaining, and assign to the datetimes array
603
+					self::$_available_spaces['datetimes'][ $datetime->ID() ] = isset(
604
+						self::$_available_spaces['datetimes'][ $datetime->ID() ]
605
+					)
606
+						? min(self::$_available_spaces['datetimes'][ $datetime->ID() ], $spaces_remaining)
607
+						: $spaces_remaining;
608
+				}
609
+			}
610
+		}
611
+	}
612 612
 
613 613
 
614
-    /**
615
-     * @param    EE_Ticket $ticket
616
-     * @param    int        $qty
617
-     * @return    void
618
-     * @throws EE_Error
619
-     */
620
-    private function recalculateTicketDatetimeAvailability(EE_Ticket $ticket, $qty = 0)
621
-    {
622
-        if (isset(self::$_available_spaces['tickets'][ $ticket->ID() ])) {
623
-            // loop thru tickets, which will ALSO include individual ticket records AND a total
624
-            foreach (self::$_available_spaces['tickets'][ $ticket->ID() ] as $DTD_ID => $spaces) {
625
-                // subtract the qty of selected tickets from each datetime's available spaces this ticket has access to,
626
-                self::$_available_spaces['datetimes'][ $DTD_ID ] -= $qty;
627
-            }
628
-        }
629
-    }
614
+	/**
615
+	 * @param    EE_Ticket $ticket
616
+	 * @param    int        $qty
617
+	 * @return    void
618
+	 * @throws EE_Error
619
+	 */
620
+	private function recalculateTicketDatetimeAvailability(EE_Ticket $ticket, $qty = 0)
621
+	{
622
+		if (isset(self::$_available_spaces['tickets'][ $ticket->ID() ])) {
623
+			// loop thru tickets, which will ALSO include individual ticket records AND a total
624
+			foreach (self::$_available_spaces['tickets'][ $ticket->ID() ] as $DTD_ID => $spaces) {
625
+				// subtract the qty of selected tickets from each datetime's available spaces this ticket has access to,
626
+				self::$_available_spaces['datetimes'][ $DTD_ID ] -= $qty;
627
+			}
628
+		}
629
+	}
630 630
 }
631 631
 // End of file ProcessTicketSelector.php
632 632
 // Location: /ProcessTicketSelector.php
Please login to merge, or discard this patch.
Spacing   +42 added lines, -42 removed lines patch added patch discarded remove patch
@@ -13,7 +13,7 @@  discard block
 block discarded – undo
13 13
 use EventEspresso\core\services\loaders\LoaderFactory;
14 14
 use InvalidArgumentException;
15 15
 
16
-if (! defined('EVENT_ESPRESSO_VERSION')) {
16
+if ( ! defined('EVENT_ESPRESSO_VERSION')) {
17 17
     exit('No direct script access allowed');
18 18
 }
19 19
 
@@ -51,7 +51,7 @@  discard block
 block discarded – undo
51 51
     public function cancelTicketSelections()
52 52
     {
53 53
         // check nonce
54
-        if (! $this->processTicketSelectorNonce('cancel_ticket_selections')) {
54
+        if ( ! $this->processTicketSelectorNonce('cancel_ticket_selections')) {
55 55
             return false;
56 56
         }
57 57
         EE_Registry::instance()->SSN->clear_session(__CLASS__, __FUNCTION__);
@@ -63,7 +63,7 @@  discard block
 block discarded – undo
63 63
             );
64 64
         } else {
65 65
             wp_safe_redirect(
66
-                site_url('/' . EE_Registry::instance()->CFG->core->event_cpt_slug . '/')
66
+                site_url('/'.EE_Registry::instance()->CFG->core->event_cpt_slug.'/')
67 67
             );
68 68
         }
69 69
         exit();
@@ -125,7 +125,7 @@  discard block
 block discarded – undo
125 125
     {
126 126
         do_action('EED_Ticket_Selector__process_ticket_selections__before');
127 127
         $request = LoaderFactory::getLoader()->getShared('EventEspresso\core\services\request\Request');
128
-        if($request->isBot()) {
128
+        if ($request->isBot()) {
129 129
             wp_safe_redirect(
130 130
                 apply_filters(
131 131
                     'FHEE__EE_Ticket_Selector__process_ticket_selections__bot_redirect_url',
@@ -135,7 +135,7 @@  discard block
 block discarded – undo
135 135
             exit();
136 136
         }
137 137
         // do we have an event id?
138
-        if (! EE_Registry::instance()->REQ->is_set('tkt-slctr-event-id')) {
138
+        if ( ! EE_Registry::instance()->REQ->is_set('tkt-slctr-event-id')) {
139 139
             // $_POST['tkt-slctr-event-id'] was not set ?!?!?!?
140 140
             EE_Error::add_error(
141 141
                 sprintf(
@@ -181,7 +181,7 @@  discard block
 block discarded – undo
181 181
                 $valid['total_tickets'],
182 182
                 'event_espresso'
183 183
             );
184
-            $limit_error_1        = sprintf($total_tickets_string, $valid['total_tickets']);
184
+            $limit_error_1 = sprintf($total_tickets_string, $valid['total_tickets']);
185 185
             // dev only message
186 186
             $max_atndz_string = _n(
187 187
                 'The registration limit for this event is %s ticket per registration, therefore the total number of tickets you may purchase at a time can not exceed %s.',
@@ -189,8 +189,8 @@  discard block
 block discarded – undo
189 189
                 $valid['max_atndz'],
190 190
                 'event_espresso'
191 191
             );
192
-            $limit_error_2    = sprintf($max_atndz_string, $valid['max_atndz'], $valid['max_atndz']);
193
-            EE_Error::add_error($limit_error_1 . '<br/>' . $limit_error_2, __FILE__, __FUNCTION__, __LINE__);
192
+            $limit_error_2 = sprintf($max_atndz_string, $valid['max_atndz'], $valid['max_atndz']);
193
+            EE_Error::add_error($limit_error_1.'<br/>'.$limit_error_2, __FILE__, __FUNCTION__, __LINE__);
194 194
         } else {
195 195
             // all data appears to be valid
196 196
             $tckts_slctd   = false;
@@ -203,15 +203,15 @@  discard block
 block discarded – undo
203 203
                 // cycle thru the number of data rows sent from the event listing
204 204
                 for ($x = 0; $x < $valid['rows']; $x++) {
205 205
                     // does this row actually contain a ticket quantity?
206
-                    if (isset($valid['qty'][ $x ]) && $valid['qty'][ $x ] > 0) {
206
+                    if (isset($valid['qty'][$x]) && $valid['qty'][$x] > 0) {
207 207
                         // YES we have a ticket quantity
208 208
                         $tckts_slctd = true;
209 209
                         //						d( $valid['ticket_obj'][$x] );
210
-                        if ($valid['ticket_obj'][ $x ] instanceof EE_Ticket) {
210
+                        if ($valid['ticket_obj'][$x] instanceof EE_Ticket) {
211 211
                             // then add ticket to cart
212 212
                             $tickets_added += $this->addTicketToCart(
213
-                                $valid['ticket_obj'][ $x ],
214
-                                $valid['qty'][ $x ]
213
+                                $valid['ticket_obj'][$x],
214
+                                $valid['qty'][$x]
215 215
                             );
216 216
                             if (EE_Error::has_error()) {
217 217
                                 break;
@@ -262,7 +262,7 @@  discard block
 block discarded – undo
262 262
                     );
263 263
                     exit();
264 264
                 } else {
265
-                    if (! EE_Error::has_error() && ! EE_Error::has_error(true, 'attention')) {
265
+                    if ( ! EE_Error::has_error() && ! EE_Error::has_error(true, 'attention')) {
266 266
                         // nothing added to cart
267 267
                         EE_Error::add_attention(__('No tickets were added for the event', 'event_espresso'),
268 268
                             __FILE__, __FUNCTION__, __LINE__);
@@ -308,7 +308,7 @@  discard block
 block discarded – undo
308 308
     private function validatePostData($id = 0)
309 309
     {
310 310
         do_action('AHEE_log', __FILE__, __FUNCTION__, '');
311
-        if (! $id) {
311
+        if ( ! $id) {
312 312
             EE_Error::add_error(
313 313
                 __('The event id provided was not valid.', 'event_espresso'),
314 314
                 __FILE__,
@@ -335,13 +335,13 @@  discard block
 block discarded – undo
335 335
         // cycle through $inputs_to_clean array
336 336
         foreach ($inputs_to_clean as $what => $input_to_clean) {
337 337
             // check for POST data
338
-            if (EE_Registry::instance()->REQ->is_set($input_to_clean . $id)) {
338
+            if (EE_Registry::instance()->REQ->is_set($input_to_clean.$id)) {
339 339
                 // grab value
340
-                $input_value = EE_Registry::instance()->REQ->get($input_to_clean . $id);
340
+                $input_value = EE_Registry::instance()->REQ->get($input_to_clean.$id);
341 341
                 switch ($what) {
342 342
                     // integers
343 343
                     case 'event_id':
344
-                        $valid_data[ $what ] = absint($input_value);
344
+                        $valid_data[$what] = absint($input_value);
345 345
                         // get event via the event id we put in the form
346 346
                         $valid_data['event'] = EE_Registry::instance()
347 347
                                                            ->load_model('Event')
@@ -349,17 +349,17 @@  discard block
 block discarded – undo
349 349
                         break;
350 350
                     case 'rows':
351 351
                     case 'max_atndz':
352
-                        $valid_data[ $what ] = absint($input_value);
352
+                        $valid_data[$what] = absint($input_value);
353 353
                         break;
354 354
                     // arrays of integers
355 355
                     case 'qty':
356 356
                         /** @var array $row_qty */
357 357
                         $row_qty = $input_value;
358 358
                         // if qty is coming from a radio button input, then we need to assemble an array of rows
359
-                        if (! is_array($row_qty)) {
359
+                        if ( ! is_array($row_qty)) {
360 360
                             // get number of rows
361
-                            $rows = EE_Registry::instance()->REQ->is_set('tkt-slctr-rows-' . $id)
362
-                                ? absint(EE_Registry::instance()->REQ->get('tkt-slctr-rows-' . $id))
361
+                            $rows = EE_Registry::instance()->REQ->is_set('tkt-slctr-rows-'.$id)
362
+                                ? absint(EE_Registry::instance()->REQ->get('tkt-slctr-rows-'.$id))
363 363
                                 : 1;
364 364
                             // explode ints by the dash
365 365
                             $row_qty = explode('-', $row_qty);
@@ -367,8 +367,8 @@  discard block
 block discarded – undo
367 367
                             $qty     = isset($row_qty[1]) ? absint($row_qty[1]) : 0;
368 368
                             $row_qty = array($row => $qty);
369 369
                             for ($x = 1; $x <= $rows; $x++) {
370
-                                if (! isset($row_qty[ $x ])) {
371
-                                    $row_qty[ $x ] = 0;
370
+                                if ( ! isset($row_qty[$x])) {
371
+                                    $row_qty[$x] = 0;
372 372
                                 }
373 373
                             }
374 374
                         }
@@ -377,7 +377,7 @@  discard block
 block discarded – undo
377 377
                         foreach ($row_qty as $qty) {
378 378
                             $qty = absint($qty);
379 379
                             // sanitize as integers
380
-                            $valid_data[ $what ][]       = $qty;
380
+                            $valid_data[$what][] = $qty;
381 381
                             $valid_data['total_tickets'] += $qty;
382 382
                         }
383 383
                         break;
@@ -387,14 +387,14 @@  discard block
 block discarded – undo
387 387
                         // cycle thru values
388 388
                         foreach ((array) $input_value as $key => $value) {
389 389
                             // allow only numbers, letters,  spaces, commas and dashes
390
-                            $value_array[ $key ] = wp_strip_all_tags($value);
390
+                            $value_array[$key] = wp_strip_all_tags($value);
391 391
                             // get ticket via the ticket id we put in the form
392 392
                             $ticket_obj                       = EE_Registry::instance()
393 393
                                                                             ->load_model('Ticket')
394 394
                                                                             ->get_one_by_ID($value);
395
-                            $valid_data['ticket_obj'][ $key ] = $ticket_obj;
395
+                            $valid_data['ticket_obj'][$key] = $ticket_obj;
396 396
                         }
397
-                        $valid_data[ $what ] = $value_array;
397
+                        $valid_data[$what] = $value_array;
398 398
                         break;
399 399
                     case 'return_url' :
400 400
                         // grab and sanitize return-url
@@ -405,9 +405,9 @@  discard block
 block discarded – undo
405 405
                             $input_value = explode('#', $input_value);
406 406
                             $input_value = end($input_value);
407 407
                             // use event list url instead, but append anchor
408
-                            $input_value = EEH_Event_View::event_archive_url() . '#' . $input_value;
408
+                            $input_value = EEH_Event_View::event_archive_url().'#'.$input_value;
409 409
                         }
410
-                        $valid_data[ $what ] = $input_value;
410
+                        $valid_data[$what] = $input_value;
411 411
                         break;
412 412
                 }    // end switch $what
413 413
             }
@@ -537,24 +537,24 @@  discard block
 block discarded – undo
537 537
     private function ticketDatetimeAvailability(EE_Ticket $ticket, $get_original_ticket_spaces = false)
538 538
     {
539 539
         // if the $_available_spaces array has not been set up yet...
540
-        if (! isset(self::$_available_spaces['tickets'][ $ticket->ID() ])) {
540
+        if ( ! isset(self::$_available_spaces['tickets'][$ticket->ID()])) {
541 541
             $this->setInitialTicketDatetimeAvailability($ticket);
542 542
         }
543 543
         $available_spaces = $ticket->qty() - $ticket->sold();
544
-        if (isset(self::$_available_spaces['tickets'][ $ticket->ID() ])) {
544
+        if (isset(self::$_available_spaces['tickets'][$ticket->ID()])) {
545 545
             // loop thru tickets, which will ALSO include individual ticket records AND a total
546
-            foreach (self::$_available_spaces['tickets'][ $ticket->ID() ] as $DTD_ID => $spaces) {
546
+            foreach (self::$_available_spaces['tickets'][$ticket->ID()] as $DTD_ID => $spaces) {
547 547
                 // if we want the original datetime availability BEFORE we started subtracting tickets ?
548 548
                 if ($get_original_ticket_spaces) {
549 549
                     // then grab the available spaces from the "tickets" array
550 550
                     // and compare with the above to get the lowest number
551 551
                     $available_spaces = min(
552 552
                         $available_spaces,
553
-                        self::$_available_spaces['tickets'][ $ticket->ID() ][ $DTD_ID ]
553
+                        self::$_available_spaces['tickets'][$ticket->ID()][$DTD_ID]
554 554
                     );
555 555
                 } else {
556 556
                     // we want the updated ticket availability as stored in the "datetimes" array
557
-                    $available_spaces = min($available_spaces, self::$_available_spaces['datetimes'][ $DTD_ID ]);
557
+                    $available_spaces = min($available_spaces, self::$_available_spaces['datetimes'][$DTD_ID]);
558 558
                 }
559 559
             }
560 560
         }
@@ -585,7 +585,7 @@  discard block
 block discarded – undo
585 585
                 'order_by' => array('DTT_EVT_start' => 'ASC'),
586 586
             )
587 587
         );
588
-        if (! empty($datetimes)) {
588
+        if ( ! empty($datetimes)) {
589 589
             // now loop thru all of the datetimes
590 590
             foreach ($datetimes as $datetime) {
591 591
                 if ($datetime instanceof EE_Datetime) {
@@ -593,17 +593,17 @@  discard block
 block discarded – undo
593 593
                     $spaces_remaining = $datetime->spaces_remaining();
594 594
                     // save the total available spaces ( the lesser of the ticket qty minus the number of tickets sold
595 595
                     // or the datetime spaces remaining) to this ticket using the datetime ID as the key
596
-                    self::$_available_spaces['tickets'][ $ticket->ID() ][ $datetime->ID() ] = min(
596
+                    self::$_available_spaces['tickets'][$ticket->ID()][$datetime->ID()] = min(
597 597
                         $ticket->qty() - $ticket->sold(),
598 598
                         $spaces_remaining
599 599
                     );
600 600
                     // if the remaining spaces for this datetime is already set,
601 601
                     // then compare that against the datetime spaces remaining, and take the lowest number,
602 602
                     // else just take the datetime spaces remaining, and assign to the datetimes array
603
-                    self::$_available_spaces['datetimes'][ $datetime->ID() ] = isset(
604
-                        self::$_available_spaces['datetimes'][ $datetime->ID() ]
603
+                    self::$_available_spaces['datetimes'][$datetime->ID()] = isset(
604
+                        self::$_available_spaces['datetimes'][$datetime->ID()]
605 605
                     )
606
-                        ? min(self::$_available_spaces['datetimes'][ $datetime->ID() ], $spaces_remaining)
606
+                        ? min(self::$_available_spaces['datetimes'][$datetime->ID()], $spaces_remaining)
607 607
                         : $spaces_remaining;
608 608
                 }
609 609
             }
@@ -619,11 +619,11 @@  discard block
 block discarded – undo
619 619
      */
620 620
     private function recalculateTicketDatetimeAvailability(EE_Ticket $ticket, $qty = 0)
621 621
     {
622
-        if (isset(self::$_available_spaces['tickets'][ $ticket->ID() ])) {
622
+        if (isset(self::$_available_spaces['tickets'][$ticket->ID()])) {
623 623
             // loop thru tickets, which will ALSO include individual ticket records AND a total
624
-            foreach (self::$_available_spaces['tickets'][ $ticket->ID() ] as $DTD_ID => $spaces) {
624
+            foreach (self::$_available_spaces['tickets'][$ticket->ID()] as $DTD_ID => $spaces) {
625 625
                 // subtract the qty of selected tickets from each datetime's available spaces this ticket has access to,
626
-                self::$_available_spaces['datetimes'][ $DTD_ID ] -= $qty;
626
+                self::$_available_spaces['datetimes'][$DTD_ID] -= $qty;
627 627
             }
628 628
         }
629 629
     }
Please login to merge, or discard this patch.
core/EE_Error.core.php 1 patch
Indentation   +1030 added lines, -1030 removed lines patch added patch discarded remove patch
@@ -11,8 +11,8 @@  discard block
 block discarded – undo
11 11
 // if you're a dev and want to receive all errors via email
12 12
 // add this to your wp-config.php: define( 'EE_ERROR_EMAILS', TRUE );
13 13
 if (defined('WP_DEBUG') && WP_DEBUG === true && defined('EE_ERROR_EMAILS') && EE_ERROR_EMAILS === true) {
14
-    set_error_handler(array('EE_Error', 'error_handler'));
15
-    register_shutdown_function(array('EE_Error', 'fatal_error_handler'));
14
+	set_error_handler(array('EE_Error', 'error_handler'));
15
+	register_shutdown_function(array('EE_Error', 'fatal_error_handler'));
16 16
 }
17 17
 
18 18
 
@@ -27,256 +27,256 @@  discard block
 block discarded – undo
27 27
 class EE_Error extends Exception
28 28
 {
29 29
 
30
-    const OPTIONS_KEY_NOTICES = 'ee_notices';
31
-
32
-
33
-    /**
34
-     * name of the file to log exceptions to
35
-     *
36
-     * @var string
37
-     */
38
-    private static $_exception_log_file = 'espresso_error_log.txt';
39
-
40
-    /**
41
-     *    stores details for all exception
42
-     *
43
-     * @var array
44
-     */
45
-    private static $_all_exceptions = array();
46
-
47
-    /**
48
-     *    tracks number of errors
49
-     *
50
-     * @var int
51
-     */
52
-    private static $_error_count = 0;
53
-
54
-    /**
55
-     * @var array $_espresso_notices
56
-     */
57
-    private static $_espresso_notices = array('success' => false, 'errors' => false, 'attention' => false);
58
-
59
-
60
-
61
-    /**
62
-     * @override default exception handling
63
-     * @param string         $message
64
-     * @param int            $code
65
-     * @param Exception|null $previous
66
-     */
67
-    public function __construct($message, $code = 0, Exception $previous = null)
68
-    {
69
-        if (version_compare(PHP_VERSION, '5.3.0', '<')) {
70
-            parent::__construct($message, $code);
71
-        } else {
72
-            parent::__construct($message, $code, $previous);
73
-        }
74
-    }
75
-
76
-
77
-
78
-    /**
79
-     *    error_handler
80
-     *
81
-     * @param $code
82
-     * @param $message
83
-     * @param $file
84
-     * @param $line
85
-     * @return void
86
-     */
87
-    public static function error_handler($code, $message, $file, $line)
88
-    {
89
-        $type = EE_Error::error_type($code);
90
-        $site = site_url();
91
-        switch ($site) {
92
-            case 'http://ee4.eventespresso.com/' :
93
-            case 'http://ee4decaf.eventespresso.com/' :
94
-            case 'http://ee4hf.eventespresso.com/' :
95
-            case 'http://ee4a.eventespresso.com/' :
96
-            case 'http://ee4ad.eventespresso.com/' :
97
-            case 'http://ee4b.eventespresso.com/' :
98
-            case 'http://ee4bd.eventespresso.com/' :
99
-            case 'http://ee4d.eventespresso.com/' :
100
-            case 'http://ee4dd.eventespresso.com/' :
101
-                $to = '[email protected]';
102
-                break;
103
-            default :
104
-                $to = get_option('admin_email');
105
-        }
106
-        $subject = $type . ' ' . $message . ' in ' . EVENT_ESPRESSO_VERSION . ' on ' . site_url();
107
-        $msg = EE_Error::_format_error($type, $message, $file, $line);
108
-        if (function_exists('wp_mail')) {
109
-            add_filter('wp_mail_content_type', array('EE_Error', 'set_content_type'));
110
-            wp_mail($to, $subject, $msg);
111
-        }
112
-        echo '<div id="message" class="espresso-notices error"><p>';
113
-        echo $type . ': ' . $message . '<br />' . $file . ' line ' . $line;
114
-        echo '<br /></p></div>';
115
-    }
116
-
117
-
118
-
119
-    /**
120
-     * error_type
121
-     * http://www.php.net/manual/en/errorfunc.constants.php#109430
122
-     *
123
-     * @param $code
124
-     * @return string
125
-     */
126
-    public static function error_type($code)
127
-    {
128
-        switch ($code) {
129
-            case E_ERROR: // 1 //
130
-                return 'E_ERROR';
131
-            case E_WARNING: // 2 //
132
-                return 'E_WARNING';
133
-            case E_PARSE: // 4 //
134
-                return 'E_PARSE';
135
-            case E_NOTICE: // 8 //
136
-                return 'E_NOTICE';
137
-            case E_CORE_ERROR: // 16 //
138
-                return 'E_CORE_ERROR';
139
-            case E_CORE_WARNING: // 32 //
140
-                return 'E_CORE_WARNING';
141
-            case E_COMPILE_ERROR: // 64 //
142
-                return 'E_COMPILE_ERROR';
143
-            case E_COMPILE_WARNING: // 128 //
144
-                return 'E_COMPILE_WARNING';
145
-            case E_USER_ERROR: // 256 //
146
-                return 'E_USER_ERROR';
147
-            case E_USER_WARNING: // 512 //
148
-                return 'E_USER_WARNING';
149
-            case E_USER_NOTICE: // 1024 //
150
-                return 'E_USER_NOTICE';
151
-            case E_STRICT: // 2048 //
152
-                return 'E_STRICT';
153
-            case E_RECOVERABLE_ERROR: // 4096 //
154
-                return 'E_RECOVERABLE_ERROR';
155
-            case E_DEPRECATED: // 8192 //
156
-                return 'E_DEPRECATED';
157
-            case E_USER_DEPRECATED: // 16384 //
158
-                return 'E_USER_DEPRECATED';
159
-            case E_ALL: // 16384 //
160
-                return 'E_ALL';
161
-        }
162
-        return '';
163
-    }
164
-
165
-
166
-
167
-    /**
168
-     *    fatal_error_handler
169
-     *
170
-     * @return void
171
-     */
172
-    public static function fatal_error_handler()
173
-    {
174
-        $last_error = error_get_last();
175
-        if ($last_error['type'] === E_ERROR) {
176
-            EE_Error::error_handler(E_ERROR, $last_error['message'], $last_error['file'], $last_error['line']);
177
-        }
178
-    }
179
-
180
-
181
-
182
-    /**
183
-     * _format_error
184
-     *
185
-     * @param $code
186
-     * @param $message
187
-     * @param $file
188
-     * @param $line
189
-     * @return string
190
-     */
191
-    private static function _format_error($code, $message, $file, $line)
192
-    {
193
-        $html = "<table cellpadding='5'><thead bgcolor='#f8f8f8'><th>Item</th><th align='left'>Details</th></thead><tbody>";
194
-        $html .= "<tr valign='top'><td><b>Code</b></td><td>$code</td></tr>";
195
-        $html .= "<tr valign='top'><td><b>Error</b></td><td>$message</td></tr>";
196
-        $html .= "<tr valign='top'><td><b>File</b></td><td>$file</td></tr>";
197
-        $html .= "<tr valign='top'><td><b>Line</b></td><td>$line</td></tr>";
198
-        $html .= '</tbody></table>';
199
-        return $html;
200
-    }
201
-
202
-
203
-
204
-    /**
205
-     * set_content_type
206
-     *
207
-     * @param $content_type
208
-     * @return string
209
-     */
210
-    public static function set_content_type($content_type)
211
-    {
212
-        return 'text/html';
213
-    }
214
-
215
-
216
-
217
-    /**
218
-     * @return void
219
-     * @throws EE_Error
220
-     * @throws ReflectionException
221
-     */
222
-    public function get_error()
223
-    {
224
-        if (apply_filters('FHEE__EE_Error__get_error__show_normal_exceptions', false)) {
225
-            throw $this;
226
-        }
227
-        // get separate user and developer messages if they exist
228
-        $msg = explode('||', $this->getMessage());
229
-        $user_msg = $msg[0];
230
-        $dev_msg = isset($msg[1]) ? $msg[1] : $msg[0];
231
-        $msg = WP_DEBUG ? $dev_msg : $user_msg;
232
-        // add details to _all_exceptions array
233
-        $x_time = time();
234
-        self::$_all_exceptions[$x_time]['name'] = get_class($this);
235
-        self::$_all_exceptions[$x_time]['file'] = $this->getFile();
236
-        self::$_all_exceptions[$x_time]['line'] = $this->getLine();
237
-        self::$_all_exceptions[$x_time]['msg'] = $msg;
238
-        self::$_all_exceptions[$x_time]['code'] = $this->getCode();
239
-        self::$_all_exceptions[$x_time]['trace'] = $this->getTrace();
240
-        self::$_all_exceptions[$x_time]['string'] = $this->getTraceAsString();
241
-        self::$_error_count++;
242
-        //add_action( 'shutdown', array( $this, 'display_errors' ));
243
-        $this->display_errors();
244
-    }
245
-
246
-
247
-
248
-    /**
249
-     * @param bool   $check_stored
250
-     * @param string $type_to_check
251
-     * @return bool
252
-     */
253
-    public static function has_error($check_stored = false, $type_to_check = 'errors')
254
-    {
255
-        $has_error = isset(self::$_espresso_notices[$type_to_check])
256
-                     && ! empty(self::$_espresso_notices[$type_to_check])
257
-            ? true
258
-            : false;
259
-        if ($check_stored && ! $has_error) {
260
-            $notices = (array)get_option(EE_Error::OPTIONS_KEY_NOTICES, array());
261
-            foreach ($notices as $type => $notice) {
262
-                if ($type === $type_to_check && $notice) {
263
-                    return true;
264
-                }
265
-            }
266
-        }
267
-        return $has_error;
268
-    }
269
-
270
-
271
-
272
-    /**
273
-     * @echo string
274
-     * @throws \ReflectionException
275
-     */
276
-    public function display_errors()
277
-    {
278
-        $trace_details = '';
279
-        $output = '
30
+	const OPTIONS_KEY_NOTICES = 'ee_notices';
31
+
32
+
33
+	/**
34
+	 * name of the file to log exceptions to
35
+	 *
36
+	 * @var string
37
+	 */
38
+	private static $_exception_log_file = 'espresso_error_log.txt';
39
+
40
+	/**
41
+	 *    stores details for all exception
42
+	 *
43
+	 * @var array
44
+	 */
45
+	private static $_all_exceptions = array();
46
+
47
+	/**
48
+	 *    tracks number of errors
49
+	 *
50
+	 * @var int
51
+	 */
52
+	private static $_error_count = 0;
53
+
54
+	/**
55
+	 * @var array $_espresso_notices
56
+	 */
57
+	private static $_espresso_notices = array('success' => false, 'errors' => false, 'attention' => false);
58
+
59
+
60
+
61
+	/**
62
+	 * @override default exception handling
63
+	 * @param string         $message
64
+	 * @param int            $code
65
+	 * @param Exception|null $previous
66
+	 */
67
+	public function __construct($message, $code = 0, Exception $previous = null)
68
+	{
69
+		if (version_compare(PHP_VERSION, '5.3.0', '<')) {
70
+			parent::__construct($message, $code);
71
+		} else {
72
+			parent::__construct($message, $code, $previous);
73
+		}
74
+	}
75
+
76
+
77
+
78
+	/**
79
+	 *    error_handler
80
+	 *
81
+	 * @param $code
82
+	 * @param $message
83
+	 * @param $file
84
+	 * @param $line
85
+	 * @return void
86
+	 */
87
+	public static function error_handler($code, $message, $file, $line)
88
+	{
89
+		$type = EE_Error::error_type($code);
90
+		$site = site_url();
91
+		switch ($site) {
92
+			case 'http://ee4.eventespresso.com/' :
93
+			case 'http://ee4decaf.eventespresso.com/' :
94
+			case 'http://ee4hf.eventespresso.com/' :
95
+			case 'http://ee4a.eventespresso.com/' :
96
+			case 'http://ee4ad.eventespresso.com/' :
97
+			case 'http://ee4b.eventespresso.com/' :
98
+			case 'http://ee4bd.eventespresso.com/' :
99
+			case 'http://ee4d.eventespresso.com/' :
100
+			case 'http://ee4dd.eventespresso.com/' :
101
+				$to = '[email protected]';
102
+				break;
103
+			default :
104
+				$to = get_option('admin_email');
105
+		}
106
+		$subject = $type . ' ' . $message . ' in ' . EVENT_ESPRESSO_VERSION . ' on ' . site_url();
107
+		$msg = EE_Error::_format_error($type, $message, $file, $line);
108
+		if (function_exists('wp_mail')) {
109
+			add_filter('wp_mail_content_type', array('EE_Error', 'set_content_type'));
110
+			wp_mail($to, $subject, $msg);
111
+		}
112
+		echo '<div id="message" class="espresso-notices error"><p>';
113
+		echo $type . ': ' . $message . '<br />' . $file . ' line ' . $line;
114
+		echo '<br /></p></div>';
115
+	}
116
+
117
+
118
+
119
+	/**
120
+	 * error_type
121
+	 * http://www.php.net/manual/en/errorfunc.constants.php#109430
122
+	 *
123
+	 * @param $code
124
+	 * @return string
125
+	 */
126
+	public static function error_type($code)
127
+	{
128
+		switch ($code) {
129
+			case E_ERROR: // 1 //
130
+				return 'E_ERROR';
131
+			case E_WARNING: // 2 //
132
+				return 'E_WARNING';
133
+			case E_PARSE: // 4 //
134
+				return 'E_PARSE';
135
+			case E_NOTICE: // 8 //
136
+				return 'E_NOTICE';
137
+			case E_CORE_ERROR: // 16 //
138
+				return 'E_CORE_ERROR';
139
+			case E_CORE_WARNING: // 32 //
140
+				return 'E_CORE_WARNING';
141
+			case E_COMPILE_ERROR: // 64 //
142
+				return 'E_COMPILE_ERROR';
143
+			case E_COMPILE_WARNING: // 128 //
144
+				return 'E_COMPILE_WARNING';
145
+			case E_USER_ERROR: // 256 //
146
+				return 'E_USER_ERROR';
147
+			case E_USER_WARNING: // 512 //
148
+				return 'E_USER_WARNING';
149
+			case E_USER_NOTICE: // 1024 //
150
+				return 'E_USER_NOTICE';
151
+			case E_STRICT: // 2048 //
152
+				return 'E_STRICT';
153
+			case E_RECOVERABLE_ERROR: // 4096 //
154
+				return 'E_RECOVERABLE_ERROR';
155
+			case E_DEPRECATED: // 8192 //
156
+				return 'E_DEPRECATED';
157
+			case E_USER_DEPRECATED: // 16384 //
158
+				return 'E_USER_DEPRECATED';
159
+			case E_ALL: // 16384 //
160
+				return 'E_ALL';
161
+		}
162
+		return '';
163
+	}
164
+
165
+
166
+
167
+	/**
168
+	 *    fatal_error_handler
169
+	 *
170
+	 * @return void
171
+	 */
172
+	public static function fatal_error_handler()
173
+	{
174
+		$last_error = error_get_last();
175
+		if ($last_error['type'] === E_ERROR) {
176
+			EE_Error::error_handler(E_ERROR, $last_error['message'], $last_error['file'], $last_error['line']);
177
+		}
178
+	}
179
+
180
+
181
+
182
+	/**
183
+	 * _format_error
184
+	 *
185
+	 * @param $code
186
+	 * @param $message
187
+	 * @param $file
188
+	 * @param $line
189
+	 * @return string
190
+	 */
191
+	private static function _format_error($code, $message, $file, $line)
192
+	{
193
+		$html = "<table cellpadding='5'><thead bgcolor='#f8f8f8'><th>Item</th><th align='left'>Details</th></thead><tbody>";
194
+		$html .= "<tr valign='top'><td><b>Code</b></td><td>$code</td></tr>";
195
+		$html .= "<tr valign='top'><td><b>Error</b></td><td>$message</td></tr>";
196
+		$html .= "<tr valign='top'><td><b>File</b></td><td>$file</td></tr>";
197
+		$html .= "<tr valign='top'><td><b>Line</b></td><td>$line</td></tr>";
198
+		$html .= '</tbody></table>';
199
+		return $html;
200
+	}
201
+
202
+
203
+
204
+	/**
205
+	 * set_content_type
206
+	 *
207
+	 * @param $content_type
208
+	 * @return string
209
+	 */
210
+	public static function set_content_type($content_type)
211
+	{
212
+		return 'text/html';
213
+	}
214
+
215
+
216
+
217
+	/**
218
+	 * @return void
219
+	 * @throws EE_Error
220
+	 * @throws ReflectionException
221
+	 */
222
+	public function get_error()
223
+	{
224
+		if (apply_filters('FHEE__EE_Error__get_error__show_normal_exceptions', false)) {
225
+			throw $this;
226
+		}
227
+		// get separate user and developer messages if they exist
228
+		$msg = explode('||', $this->getMessage());
229
+		$user_msg = $msg[0];
230
+		$dev_msg = isset($msg[1]) ? $msg[1] : $msg[0];
231
+		$msg = WP_DEBUG ? $dev_msg : $user_msg;
232
+		// add details to _all_exceptions array
233
+		$x_time = time();
234
+		self::$_all_exceptions[$x_time]['name'] = get_class($this);
235
+		self::$_all_exceptions[$x_time]['file'] = $this->getFile();
236
+		self::$_all_exceptions[$x_time]['line'] = $this->getLine();
237
+		self::$_all_exceptions[$x_time]['msg'] = $msg;
238
+		self::$_all_exceptions[$x_time]['code'] = $this->getCode();
239
+		self::$_all_exceptions[$x_time]['trace'] = $this->getTrace();
240
+		self::$_all_exceptions[$x_time]['string'] = $this->getTraceAsString();
241
+		self::$_error_count++;
242
+		//add_action( 'shutdown', array( $this, 'display_errors' ));
243
+		$this->display_errors();
244
+	}
245
+
246
+
247
+
248
+	/**
249
+	 * @param bool   $check_stored
250
+	 * @param string $type_to_check
251
+	 * @return bool
252
+	 */
253
+	public static function has_error($check_stored = false, $type_to_check = 'errors')
254
+	{
255
+		$has_error = isset(self::$_espresso_notices[$type_to_check])
256
+					 && ! empty(self::$_espresso_notices[$type_to_check])
257
+			? true
258
+			: false;
259
+		if ($check_stored && ! $has_error) {
260
+			$notices = (array)get_option(EE_Error::OPTIONS_KEY_NOTICES, array());
261
+			foreach ($notices as $type => $notice) {
262
+				if ($type === $type_to_check && $notice) {
263
+					return true;
264
+				}
265
+			}
266
+		}
267
+		return $has_error;
268
+	}
269
+
270
+
271
+
272
+	/**
273
+	 * @echo string
274
+	 * @throws \ReflectionException
275
+	 */
276
+	public function display_errors()
277
+	{
278
+		$trace_details = '';
279
+		$output = '
280 280
 <style type="text/css">
281 281
 	#ee-error-message {
282 282
 		max-width:90% !important;
@@ -332,21 +332,21 @@  discard block
 block discarded – undo
332 332
 	}
333 333
 </style>
334 334
 <div id="ee-error-message" class="error">';
335
-        if (! WP_DEBUG) {
336
-            $output .= '
335
+		if (! WP_DEBUG) {
336
+			$output .= '
337 337
 	<p>';
338
-        }
339
-        // cycle thru errors
340
-        foreach (self::$_all_exceptions as $time => $ex) {
341
-            $error_code = '';
342
-            // process trace info
343
-            if (empty($ex['trace'])) {
344
-                $trace_details .= __(
345
-                    'Sorry, but no trace information was available for this exception.',
346
-                    'event_espresso'
347
-                );
348
-            } else {
349
-                $trace_details .= '
338
+		}
339
+		// cycle thru errors
340
+		foreach (self::$_all_exceptions as $time => $ex) {
341
+			$error_code = '';
342
+			// process trace info
343
+			if (empty($ex['trace'])) {
344
+				$trace_details .= __(
345
+					'Sorry, but no trace information was available for this exception.',
346
+					'event_espresso'
347
+				);
348
+			} else {
349
+				$trace_details .= '
350 350
 			<div id="ee-trace-details">
351 351
 			<table width="100%" border="0" cellpadding="5" cellspacing="0">
352 352
 				<tr>
@@ -356,43 +356,43 @@  discard block
 block discarded – undo
356 356
 					<th scope="col" align="left">Class</th>
357 357
 					<th scope="col" align="left">Method( arguments )</th>
358 358
 				</tr>';
359
-                $last_on_stack = count($ex['trace']) - 1;
360
-                // reverse array so that stack is in proper chronological order
361
-                $sorted_trace = array_reverse($ex['trace']);
362
-                foreach ($sorted_trace as $nmbr => $trace) {
363
-                    $file = isset($trace['file']) ? $trace['file'] : '';
364
-                    $class = isset($trace['class']) ? $trace['class'] : '';
365
-                    $type = isset($trace['type']) ? $trace['type'] : '';
366
-                    $function = isset($trace['function']) ? $trace['function'] : '';
367
-                    $args = isset($trace['args']) ? $this->_convert_args_to_string($trace['args']) : '';
368
-                    $line = isset($trace['line']) ? $trace['line'] : '';
369
-                    $zebra = ($nmbr % 2) ? ' odd' : '';
370
-                    if (empty($file) && ! empty($class)) {
371
-                        $a = new ReflectionClass($class);
372
-                        $file = $a->getFileName();
373
-                        if (empty($line) && ! empty($function)) {
374
-                            try {
375
-                                //if $function is a closure, this throws an exception
376
-                                $b = new ReflectionMethod($class, $function);
377
-                                $line = $b->getStartLine();
378
-                            } catch (Exception $closure_exception) {
379
-                                $line = 'unknown';
380
-                            }
381
-                        }
382
-                    }
383
-                    if ($nmbr === $last_on_stack) {
384
-                        $file = $ex['file'] !== '' ? $ex['file'] : $file;
385
-                        $line = $ex['line'] !== '' ? $ex['line'] : $line;
386
-                        $error_code = self::generate_error_code($file, $trace['function'], $line);
387
-                    }
388
-                    $nmbr_dsply = ! empty($nmbr) ? $nmbr : '&nbsp;';
389
-                    $line_dsply = ! empty($line) ? $line : '&nbsp;';
390
-                    $file_dsply = ! empty($file) ? $file : '&nbsp;';
391
-                    $class_dsply = ! empty($class) ? $class : '&nbsp;';
392
-                    $type_dsply = ! empty($type) ? $type : '&nbsp;';
393
-                    $function_dsply = ! empty($function) ? $function : '&nbsp;';
394
-                    $args_dsply = ! empty($args) ? '( ' . $args . ' )' : '';
395
-                    $trace_details .= '
359
+				$last_on_stack = count($ex['trace']) - 1;
360
+				// reverse array so that stack is in proper chronological order
361
+				$sorted_trace = array_reverse($ex['trace']);
362
+				foreach ($sorted_trace as $nmbr => $trace) {
363
+					$file = isset($trace['file']) ? $trace['file'] : '';
364
+					$class = isset($trace['class']) ? $trace['class'] : '';
365
+					$type = isset($trace['type']) ? $trace['type'] : '';
366
+					$function = isset($trace['function']) ? $trace['function'] : '';
367
+					$args = isset($trace['args']) ? $this->_convert_args_to_string($trace['args']) : '';
368
+					$line = isset($trace['line']) ? $trace['line'] : '';
369
+					$zebra = ($nmbr % 2) ? ' odd' : '';
370
+					if (empty($file) && ! empty($class)) {
371
+						$a = new ReflectionClass($class);
372
+						$file = $a->getFileName();
373
+						if (empty($line) && ! empty($function)) {
374
+							try {
375
+								//if $function is a closure, this throws an exception
376
+								$b = new ReflectionMethod($class, $function);
377
+								$line = $b->getStartLine();
378
+							} catch (Exception $closure_exception) {
379
+								$line = 'unknown';
380
+							}
381
+						}
382
+					}
383
+					if ($nmbr === $last_on_stack) {
384
+						$file = $ex['file'] !== '' ? $ex['file'] : $file;
385
+						$line = $ex['line'] !== '' ? $ex['line'] : $line;
386
+						$error_code = self::generate_error_code($file, $trace['function'], $line);
387
+					}
388
+					$nmbr_dsply = ! empty($nmbr) ? $nmbr : '&nbsp;';
389
+					$line_dsply = ! empty($line) ? $line : '&nbsp;';
390
+					$file_dsply = ! empty($file) ? $file : '&nbsp;';
391
+					$class_dsply = ! empty($class) ? $class : '&nbsp;';
392
+					$type_dsply = ! empty($type) ? $type : '&nbsp;';
393
+					$function_dsply = ! empty($function) ? $function : '&nbsp;';
394
+					$args_dsply = ! empty($args) ? '( ' . $args . ' )' : '';
395
+					$trace_details .= '
396 396
 					<tr>
397 397
 						<td align="right" class="' . $zebra . '">' . $nmbr_dsply . '</td>
398 398
 						<td align="right" class="' . $zebra . '">' . $line_dsply . '</td>
@@ -400,523 +400,523 @@  discard block
 block discarded – undo
400 400
 						<td align="left" class="' . $zebra . '">' . $class_dsply . '</td>
401 401
 						<td align="left" class="' . $zebra . '">' . $type_dsply . $function_dsply . $args_dsply . '</td>
402 402
 					</tr>';
403
-                }
404
-                $trace_details .= '
403
+				}
404
+				$trace_details .= '
405 405
 			 </table>
406 406
 			</div>';
407
-            }
408
-            $ex['code'] = $ex['code'] ? $ex['code'] : $error_code;
409
-            // add generic non-identifying messages for non-privileged users
410
-            if (! WP_DEBUG) {
411
-                $output .= '<span class="ee-error-user-msg-spn">'
412
-                           . trim($ex['msg'])
413
-                           . '</span> &nbsp; <sup>'
414
-                           . $ex['code']
415
-                           . '</sup><br />';
416
-            } else {
417
-                // or helpful developer messages if debugging is on
418
-                $output .= '
407
+			}
408
+			$ex['code'] = $ex['code'] ? $ex['code'] : $error_code;
409
+			// add generic non-identifying messages for non-privileged users
410
+			if (! WP_DEBUG) {
411
+				$output .= '<span class="ee-error-user-msg-spn">'
412
+						   . trim($ex['msg'])
413
+						   . '</span> &nbsp; <sup>'
414
+						   . $ex['code']
415
+						   . '</sup><br />';
416
+			} else {
417
+				// or helpful developer messages if debugging is on
418
+				$output .= '
419 419
 		<div class="ee-error-dev-msg-dv">
420 420
 			<p class="ee-error-dev-msg-pg">
421 421
 				<strong class="ee-error-dev-msg-str">An '
422
-                           . $ex['name']
423
-                           . ' exception was thrown!</strong>  &nbsp; <span>code: '
424
-                           . $ex['code']
425
-                           . '</span><br />
422
+						   . $ex['name']
423
+						   . ' exception was thrown!</strong>  &nbsp; <span>code: '
424
+						   . $ex['code']
425
+						   . '</span><br />
426 426
 				<span class="big-text">"'
427
-                           . trim($ex['msg'])
428
-                           . '"</span><br/>
427
+						   . trim($ex['msg'])
428
+						   . '"</span><br/>
429 429
 				<a id="display-ee-error-trace-'
430
-                           . self::$_error_count
431
-                           . $time
432
-                           . '" class="display-ee-error-trace-lnk small-text" rel="ee-error-trace-'
433
-                           . self::$_error_count
434
-                           . $time
435
-                           . '">
430
+						   . self::$_error_count
431
+						   . $time
432
+						   . '" class="display-ee-error-trace-lnk small-text" rel="ee-error-trace-'
433
+						   . self::$_error_count
434
+						   . $time
435
+						   . '">
436 436
 					'
437
-                           . __('click to view backtrace and class/method details', 'event_espresso')
438
-                           . '
437
+						   . __('click to view backtrace and class/method details', 'event_espresso')
438
+						   . '
439 439
 				</a><br />
440 440
 				<span class="small-text lt-grey-text">'
441
-                           . $ex['file']
442
-                           . ' &nbsp; ( line no: '
443
-                           . $ex['line']
444
-                           . ' )</span>
441
+						   . $ex['file']
442
+						   . ' &nbsp; ( line no: '
443
+						   . $ex['line']
444
+						   . ' )</span>
445 445
 			</p>
446 446
 			<div id="ee-error-trace-'
447
-                           . self::$_error_count
448
-                           . $time
449
-                           . '-dv" class="ee-error-trace-dv" style="display: none;">
447
+						   . self::$_error_count
448
+						   . $time
449
+						   . '-dv" class="ee-error-trace-dv" style="display: none;">
450 450
 				'
451
-                           . $trace_details;
452
-                if (! empty($class)) {
453
-                    $output .= '
451
+						   . $trace_details;
452
+				if (! empty($class)) {
453
+					$output .= '
454 454
 				<div style="padding:3px; margin:0 0 1em; border:1px solid #666; background:#fff; border-radius:3px;">
455 455
 					<div style="padding:1em 2em; border:1px solid #666; background:#f9f9f9;">
456 456
 						<h3>Class Details</h3>';
457
-                    $a = new ReflectionClass($class);
458
-                    $output .= '
457
+					$a = new ReflectionClass($class);
458
+					$output .= '
459 459
 						<pre>' . $a . '</pre>
460 460
 					</div>
461 461
 				</div>';
462
-                }
463
-                $output .= '
462
+				}
463
+				$output .= '
464 464
 			</div>
465 465
 		</div>
466 466
 		<br />';
467
-            }
468
-            $this->write_to_error_log($time, $ex);
469
-        }
470
-        // remove last linebreak
471
-        $output = substr($output, 0, -6);
472
-        if (! WP_DEBUG) {
473
-            $output .= '
467
+			}
468
+			$this->write_to_error_log($time, $ex);
469
+		}
470
+		// remove last linebreak
471
+		$output = substr($output, 0, -6);
472
+		if (! WP_DEBUG) {
473
+			$output .= '
474 474
 	</p>';
475
-        }
476
-        $output .= '
475
+		}
476
+		$output .= '
477 477
 </div>';
478
-        $output .= self::_print_scripts(true);
479
-        if (defined('DOING_AJAX')) {
480
-            echo wp_json_encode(array('error' => $output));
481
-            exit();
482
-        }
483
-        echo $output;
484
-        die();
485
-    }
486
-
487
-
488
-
489
-    /**
490
-     *    generate string from exception trace args
491
-     *
492
-     * @param array $arguments
493
-     * @param bool  $array
494
-     * @return string
495
-     */
496
-    private function _convert_args_to_string($arguments = array(), $array = false)
497
-    {
498
-        $arg_string = '';
499
-        if (! empty($arguments)) {
500
-            $args = array();
501
-            foreach ($arguments as $arg) {
502
-                if (! empty($arg)) {
503
-                    if (is_string($arg)) {
504
-                        $args[] = " '" . $arg . "'";
505
-                    } elseif (is_array($arg)) {
506
-                        $args[] = 'ARRAY(' . $this->_convert_args_to_string($arg, true);
507
-                    } elseif ($arg === null) {
508
-                        $args[] = ' NULL';
509
-                    } elseif (is_bool($arg)) {
510
-                        $args[] = ($arg) ? ' TRUE' : ' FALSE';
511
-                    } elseif (is_object($arg)) {
512
-                        $args[] = ' OBJECT ' . get_class($arg);
513
-                    } elseif (is_resource($arg)) {
514
-                        $args[] = get_resource_type($arg);
515
-                    } else {
516
-                        $args[] = $arg;
517
-                    }
518
-                }
519
-            }
520
-            $arg_string = implode(', ', $args);
521
-        }
522
-        if ($array) {
523
-            $arg_string .= ' )';
524
-        }
525
-        return $arg_string;
526
-    }
527
-
528
-
529
-
530
-    /**
531
-     *    add error message
532
-     *
533
-     * @param        string $msg  the message to display to users or developers - adding a double pipe || (OR) creates
534
-     *                            separate messages for user || dev
535
-     * @param        string $file the file that the error occurred in - just use __FILE__
536
-     * @param        string $func the function/method that the error occurred in - just use __FUNCTION__
537
-     * @param        string $line the line number where the error occurred - just use __LINE__
538
-     * @return        void
539
-     */
540
-    public static function add_error($msg = null, $file = null, $func = null, $line = null)
541
-    {
542
-        self::_add_notice('errors', $msg, $file, $func, $line);
543
-        self::$_error_count++;
544
-    }
545
-
546
-
547
-
548
-    /**
549
-     * If WP_DEBUG is active, throws an exception. If WP_DEBUG is off, just
550
-     * adds an error
551
-     *
552
-     * @param string $msg
553
-     * @param string $file
554
-     * @param string $func
555
-     * @param string $line
556
-     * @throws EE_Error
557
-     */
558
-    public static function throw_exception_if_debugging($msg = null, $file = null, $func = null, $line = null)
559
-    {
560
-        if (WP_DEBUG) {
561
-            throw new EE_Error($msg);
562
-        }
563
-        EE_Error::add_error($msg, $file, $func, $line);
564
-    }
565
-
566
-
567
-
568
-    /**
569
-     *    add success message
570
-     *
571
-     * @param        string $msg  the message to display to users or developers - adding a double pipe || (OR) creates
572
-     *                            separate messages for user || dev
573
-     * @param        string $file the file that the error occurred in - just use __FILE__
574
-     * @param        string $func the function/method that the error occurred in - just use __FUNCTION__
575
-     * @param        string $line the line number where the error occurred - just use __LINE__
576
-     * @return        void
577
-     */
578
-    public static function add_success($msg = null, $file = null, $func = null, $line = null)
579
-    {
580
-        self::_add_notice('success', $msg, $file, $func, $line);
581
-    }
582
-
583
-
584
-
585
-    /**
586
-     *    add attention message
587
-     *
588
-     * @param        string $msg  the message to display to users or developers - adding a double pipe || (OR) creates
589
-     *                            separate messages for user || dev
590
-     * @param        string $file the file that the error occurred in - just use __FILE__
591
-     * @param        string $func the function/method that the error occurred in - just use __FUNCTION__
592
-     * @param        string $line the line number where the error occurred - just use __LINE__
593
-     * @return        void
594
-     */
595
-    public static function add_attention($msg = null, $file = null, $func = null, $line = null)
596
-    {
597
-        self::_add_notice('attention', $msg, $file, $func, $line);
598
-    }
599
-
600
-
601
-
602
-    /**
603
-     * @param string $type whether the message is for a success or error notification
604
-     * @param string $msg the message to display to users or developers
605
-     *                    - adding a double pipe || (OR) creates separate messages for user || dev
606
-     * @param string $file the file that the error occurred in - just use __FILE__
607
-     * @param string $func the function/method that the error occurred in - just use __FUNCTION__
608
-     * @param string $line the line number where the error occurred - just use __LINE__
609
-     * @return void
610
-     */
611
-    private static function _add_notice($type = 'success', $msg = '', $file = '', $func = '', $line = '')
612
-    {
613
-        if (empty($msg)) {
614
-            EE_Error::doing_it_wrong(
615
-                'EE_Error::add_' . $type . '()',
616
-                sprintf(
617
-                    __('Notifications are not much use without a message! Please add a message to the EE_Error::add_%s() call made in %s on line %d',
618
-                        'event_espresso'),
619
-                    $type,
620
-                    $file,
621
-                    $line
622
-                ),
623
-                EVENT_ESPRESSO_VERSION
624
-            );
625
-        }
626
-        if ($type === 'errors' && (empty($file) || empty($func) || empty($line))) {
627
-            EE_Error::doing_it_wrong(
628
-                'EE_Error::add_error()',
629
-                __('You need to provide the file name, function name, and line number that the error occurred on in order to better assist with debugging.',
630
-                    'event_espresso'),
631
-                EVENT_ESPRESSO_VERSION
632
-            );
633
-        }
634
-        // get separate user and developer messages if they exist
635
-        $msg      = explode('||', $msg);
636
-        $user_msg = $msg[0];
637
-        $dev_msg  = isset($msg[1]) ? $msg[1] : $msg[0];
638
-        /**
639
-         * Do an action so other code can be triggered when a notice is created
640
-         *
641
-         * @param string $type     can be 'errors', 'attention', or 'success'
642
-         * @param string $user_msg message displayed to user when WP_DEBUG is off
643
-         * @param string $user_msg message displayed to user when WP_DEBUG is on
644
-         * @param string $file     file where error was generated
645
-         * @param string $func     function where error was generated
646
-         * @param string $line     line where error was generated
647
-         */
648
-        do_action('AHEE__EE_Error___add_notice', $type, $user_msg, $dev_msg, $file, $func, $line);
649
-        $msg = WP_DEBUG ? $dev_msg : $user_msg;
650
-        // add notice if message exists
651
-        if (! empty($msg)) {
652
-            // get error code
653
-            $notice_code = EE_Error::generate_error_code($file, $func, $line);
654
-            if (WP_DEBUG && $type === 'errors') {
655
-                $msg .= '<br/><span class="tiny-text">' . $notice_code . '</span>';
656
-            }
657
-            // add notice. Index by code if it's not blank
658
-            if ($notice_code) {
659
-                self::$_espresso_notices[$type][$notice_code] = $msg;
660
-            } else {
661
-                self::$_espresso_notices[$type][] = $msg;
662
-            }
663
-            add_action('wp_footer', array('EE_Error', 'enqueue_error_scripts'), 1);
664
-        }
665
-    }
666
-
667
-
668
-    /**
669
-     * in some case it may be necessary to overwrite the existing success messages
670
-     *
671
-     * @return        void
672
-     */
673
-    public static function overwrite_success()
674
-    {
675
-        self::$_espresso_notices['success'] = false;
676
-    }
677
-
678
-
679
-
680
-    /**
681
-     * in some case it may be necessary to overwrite the existing attention messages
682
-     *
683
-     * @return void
684
-     */
685
-    public static function overwrite_attention()
686
-    {
687
-        self::$_espresso_notices['attention'] = false;
688
-    }
689
-
690
-
691
-
692
-    /**
693
-     * in some case it may be necessary to overwrite the existing error messages
694
-     *
695
-     * @return void
696
-     */
697
-    public static function overwrite_errors()
698
-    {
699
-        self::$_espresso_notices['errors'] = false;
700
-    }
701
-
702
-
703
-
704
-    /**
705
-     * @return void
706
-     */
707
-    public static function reset_notices()
708
-    {
709
-        self::$_espresso_notices['success']   = false;
710
-        self::$_espresso_notices['attention'] = false;
711
-        self::$_espresso_notices['errors']    = false;
712
-    }
713
-
714
-
715
-
716
-    /**
717
-     * @return int
718
-     */
719
-    public static function has_notices()
720
-    {
721
-        $has_notices = 0;
722
-        // check for success messages
723
-        $has_notices = self::$_espresso_notices['success'] && ! empty(self::$_espresso_notices['success'])
724
-            ? 3
725
-            : $has_notices;
726
-        // check for attention messages
727
-        $has_notices = self::$_espresso_notices['attention'] && ! empty(self::$_espresso_notices['attention'])
728
-            ? 2
729
-            : $has_notices;
730
-        // check for error messages
731
-        $has_notices = self::$_espresso_notices['errors'] && ! empty(self::$_espresso_notices['errors'])
732
-            ? 1
733
-            : $has_notices;
734
-        return $has_notices;
735
-    }
736
-
737
-
738
-    /**
739
-     * This simply returns non formatted error notices as they were sent into the EE_Error object.
740
-     *
741
-     * @since 4.9.0
742
-     * @return array
743
-     */
744
-    public static function get_vanilla_notices()
745
-    {
746
-        return array(
747
-            'success'   => isset(self::$_espresso_notices['success'])
748
-                ? self::$_espresso_notices['success']
749
-                : array(),
750
-            'attention' => isset(self::$_espresso_notices['attention'])
751
-                ? self::$_espresso_notices['attention']
752
-                : array(),
753
-            'errors'    => isset(self::$_espresso_notices['errors'])
754
-                ? self::$_espresso_notices['errors']
755
-                : array(),
756
-        );
757
-    }
758
-
759
-
760
-
761
-    /**
762
-     * compile all error or success messages into one string
763
-     *
764
-     * @see EE_Error::get_raw_notices if you want the raw notices without any preparations made to them
765
-     * @param boolean $format_output     whether or not to format the messages for display in the WP admin
766
-     * @param boolean $save_to_transient whether or not to save notices to the db for retrieval on next request
767
-     *                                          - ONLY do this just before redirecting
768
-     * @param boolean $remove_empty      whether or not to unset empty messages
769
-     * @return array
770
-     */
771
-    public static function get_notices($format_output = true, $save_to_transient = false, $remove_empty = true)
772
-    {
773
-        // do_action('AHEE_log', __FILE__, __FUNCTION__, '');
774
-        $success_messages   = '';
775
-        $attention_messages = '';
776
-        $error_messages     = '';
777
-        $print_scripts      = false;
778
-        // EEH_Debug_Tools::printr( self::$_espresso_notices, 'espresso_notices  <br /><span style="font-size:10px;font-weight:normal;">' . __FILE__ . '<br />line no: ' . __LINE__ . '</span>', 'auto' );
779
-        // either save notices to the db
780
-        if ($save_to_transient || isset($_REQUEST['activate-selected'])) {
781
-            $existing_notices  = get_option(EE_Error::OPTIONS_KEY_NOTICES, array());
782
-            $existing_notices = is_array($existing_notices) ? $existing_notices : array();
783
-            self::$_espresso_notices = array_merge(
784
-                $existing_notices,
785
-                self::$_espresso_notices
786
-            );
787
-            update_option(EE_Error::OPTIONS_KEY_NOTICES, self::$_espresso_notices);
788
-            return array();
789
-        }
790
-        // grab any notices that have been previously saved
791
-        if ($notices = get_option(EE_Error::OPTIONS_KEY_NOTICES, array())) {
792
-            foreach ($notices as $type => $notice) {
793
-                if (is_array($notice) && ! empty($notice)) {
794
-                    // make sure that existing notice type is an array
795
-                    self::$_espresso_notices[$type] = is_array(self::$_espresso_notices[$type])
796
-                                                      && ! empty(self::$_espresso_notices[$type])
797
-                        ? self::$_espresso_notices[$type]
798
-                        : array();
799
-                    // merge stored notices with any newly created ones
800
-                    self::$_espresso_notices[$type] = array_merge(self::$_espresso_notices[$type], $notice);
801
-                    $print_scripts                  = true;
802
-                }
803
-            }
804
-            // now clear any stored notices
805
-            update_option(EE_Error::OPTIONS_KEY_NOTICES, array());
806
-        }
807
-        // check for success messages
808
-        if (self::$_espresso_notices['success'] && ! empty(self::$_espresso_notices['success'])) {
809
-            // combine messages
810
-            $success_messages .= implode(self::$_espresso_notices['success'], '<br />');
811
-            $print_scripts    = true;
812
-        }
813
-        // check for attention messages
814
-        if (self::$_espresso_notices['attention'] && ! empty(self::$_espresso_notices['attention'])) {
815
-            // combine messages
816
-            $attention_messages .= implode(self::$_espresso_notices['attention'], '<br />');
817
-            $print_scripts      = true;
818
-        }
819
-        // check for error messages
820
-        if (self::$_espresso_notices['errors'] && ! empty(self::$_espresso_notices['errors'])) {
821
-            $error_messages .= count(self::$_espresso_notices['errors']) > 1
822
-                ? __('The following errors have occurred:<br />', 'event_espresso')
823
-                : __('An error has occurred:<br />', 'event_espresso');
824
-            // combine messages
825
-            $error_messages .= implode(self::$_espresso_notices['errors'], '<br />');
826
-            $print_scripts  = true;
827
-        }
828
-        if ($format_output) {
829
-
830
-            $notices = '<div id="espresso-notices">';
831
-            $close = is_admin() ? ''
832
-                : '<a class="close-espresso-notice hide-if-no-js"><span class="dashicons dashicons-no"></span></a>';
833
-            if ($success_messages !== '') {
834
-                $css_id    = is_admin() ? 'ee-success-message' : 'espresso-notices-success';
835
-                $css_class = is_admin() ? 'updated fade' : 'success fade-away';
836
-                //showMessage( $success_messages );
837
-                $notices .= '<div id="'
838
-                            . $css_id
839
-                            . '" class="espresso-notices '
840
-                            . $css_class
841
-                            . '" style="display:none;"><p>'
842
-                            . $success_messages
843
-                            . '</p>'
844
-                            . $close
845
-                            . '</div>';
846
-            }
847
-            if ($attention_messages !== '') {
848
-                $css_id    = is_admin() ? 'ee-attention-message' : 'espresso-notices-attention';
849
-                $css_class = is_admin() ? 'updated ee-notices-attention' : 'attention fade-away';
850
-                //showMessage( $error_messages, TRUE );
851
-                $notices .= '<div id="'
852
-                            . $css_id
853
-                            . '" class="espresso-notices '
854
-                            . $css_class
855
-                            . '" style="display:none;"><p>'
856
-                            . $attention_messages
857
-                            . '</p>'
858
-                            . $close
859
-                            . '</div>';
860
-            }
861
-            if ($error_messages !== '') {
862
-                $css_id    = is_admin() ? 'ee-error-message' : 'espresso-notices-error';
863
-                $css_class = is_admin() ? 'error' : 'error fade-away';
864
-                //showMessage( $error_messages, TRUE );
865
-                $notices .= '<div id="'
866
-                            . $css_id
867
-                            . '" class="espresso-notices '
868
-                            . $css_class
869
-                            . '" style="display:none;"><p>'
870
-                            . $error_messages
871
-                            . '</p>'
872
-                            . $close
873
-                            . '</div>';
874
-            }
875
-            $notices .= '</div>';
876
-        } else {
877
-
878
-            $notices = array(
879
-                'success'   => $success_messages,
880
-                'attention' => $attention_messages,
881
-                'errors'    => $error_messages,
882
-            );
883
-            if ($remove_empty) {
884
-                // remove empty notices
885
-                foreach ($notices as $type => $notice) {
886
-                    if (empty($notice)) {
887
-                        unset($notices[$type]);
888
-                    }
889
-                }
890
-            }
891
-        }
892
-        if ($print_scripts) {
893
-            self::_print_scripts();
894
-        }
895
-        return $notices;
896
-    }
897
-
898
-
899
-
900
-    /**
901
-     * _print_scripts
902
-     *
903
-     * @param    bool $force_print
904
-     * @return    string
905
-     */
906
-    private static function _print_scripts($force_print = false)
907
-    {
908
-        if (! $force_print && (did_action('admin_enqueue_scripts') || did_action('wp_enqueue_scripts'))) {
909
-            if (wp_script_is('ee_error_js', 'enqueued')) {
910
-                return '';
911
-            }
912
-            if (wp_script_is('ee_error_js', 'registered')) {
913
-                wp_enqueue_style('espresso_default');
914
-                wp_enqueue_style('espresso_custom_css');
915
-                wp_enqueue_script('ee_error_js');
916
-                wp_localize_script('ee_error_js', 'ee_settings', array('wp_debug' => WP_DEBUG));
917
-            }
918
-        } else {
919
-            return '
478
+		$output .= self::_print_scripts(true);
479
+		if (defined('DOING_AJAX')) {
480
+			echo wp_json_encode(array('error' => $output));
481
+			exit();
482
+		}
483
+		echo $output;
484
+		die();
485
+	}
486
+
487
+
488
+
489
+	/**
490
+	 *    generate string from exception trace args
491
+	 *
492
+	 * @param array $arguments
493
+	 * @param bool  $array
494
+	 * @return string
495
+	 */
496
+	private function _convert_args_to_string($arguments = array(), $array = false)
497
+	{
498
+		$arg_string = '';
499
+		if (! empty($arguments)) {
500
+			$args = array();
501
+			foreach ($arguments as $arg) {
502
+				if (! empty($arg)) {
503
+					if (is_string($arg)) {
504
+						$args[] = " '" . $arg . "'";
505
+					} elseif (is_array($arg)) {
506
+						$args[] = 'ARRAY(' . $this->_convert_args_to_string($arg, true);
507
+					} elseif ($arg === null) {
508
+						$args[] = ' NULL';
509
+					} elseif (is_bool($arg)) {
510
+						$args[] = ($arg) ? ' TRUE' : ' FALSE';
511
+					} elseif (is_object($arg)) {
512
+						$args[] = ' OBJECT ' . get_class($arg);
513
+					} elseif (is_resource($arg)) {
514
+						$args[] = get_resource_type($arg);
515
+					} else {
516
+						$args[] = $arg;
517
+					}
518
+				}
519
+			}
520
+			$arg_string = implode(', ', $args);
521
+		}
522
+		if ($array) {
523
+			$arg_string .= ' )';
524
+		}
525
+		return $arg_string;
526
+	}
527
+
528
+
529
+
530
+	/**
531
+	 *    add error message
532
+	 *
533
+	 * @param        string $msg  the message to display to users or developers - adding a double pipe || (OR) creates
534
+	 *                            separate messages for user || dev
535
+	 * @param        string $file the file that the error occurred in - just use __FILE__
536
+	 * @param        string $func the function/method that the error occurred in - just use __FUNCTION__
537
+	 * @param        string $line the line number where the error occurred - just use __LINE__
538
+	 * @return        void
539
+	 */
540
+	public static function add_error($msg = null, $file = null, $func = null, $line = null)
541
+	{
542
+		self::_add_notice('errors', $msg, $file, $func, $line);
543
+		self::$_error_count++;
544
+	}
545
+
546
+
547
+
548
+	/**
549
+	 * If WP_DEBUG is active, throws an exception. If WP_DEBUG is off, just
550
+	 * adds an error
551
+	 *
552
+	 * @param string $msg
553
+	 * @param string $file
554
+	 * @param string $func
555
+	 * @param string $line
556
+	 * @throws EE_Error
557
+	 */
558
+	public static function throw_exception_if_debugging($msg = null, $file = null, $func = null, $line = null)
559
+	{
560
+		if (WP_DEBUG) {
561
+			throw new EE_Error($msg);
562
+		}
563
+		EE_Error::add_error($msg, $file, $func, $line);
564
+	}
565
+
566
+
567
+
568
+	/**
569
+	 *    add success message
570
+	 *
571
+	 * @param        string $msg  the message to display to users or developers - adding a double pipe || (OR) creates
572
+	 *                            separate messages for user || dev
573
+	 * @param        string $file the file that the error occurred in - just use __FILE__
574
+	 * @param        string $func the function/method that the error occurred in - just use __FUNCTION__
575
+	 * @param        string $line the line number where the error occurred - just use __LINE__
576
+	 * @return        void
577
+	 */
578
+	public static function add_success($msg = null, $file = null, $func = null, $line = null)
579
+	{
580
+		self::_add_notice('success', $msg, $file, $func, $line);
581
+	}
582
+
583
+
584
+
585
+	/**
586
+	 *    add attention message
587
+	 *
588
+	 * @param        string $msg  the message to display to users or developers - adding a double pipe || (OR) creates
589
+	 *                            separate messages for user || dev
590
+	 * @param        string $file the file that the error occurred in - just use __FILE__
591
+	 * @param        string $func the function/method that the error occurred in - just use __FUNCTION__
592
+	 * @param        string $line the line number where the error occurred - just use __LINE__
593
+	 * @return        void
594
+	 */
595
+	public static function add_attention($msg = null, $file = null, $func = null, $line = null)
596
+	{
597
+		self::_add_notice('attention', $msg, $file, $func, $line);
598
+	}
599
+
600
+
601
+
602
+	/**
603
+	 * @param string $type whether the message is for a success or error notification
604
+	 * @param string $msg the message to display to users or developers
605
+	 *                    - adding a double pipe || (OR) creates separate messages for user || dev
606
+	 * @param string $file the file that the error occurred in - just use __FILE__
607
+	 * @param string $func the function/method that the error occurred in - just use __FUNCTION__
608
+	 * @param string $line the line number where the error occurred - just use __LINE__
609
+	 * @return void
610
+	 */
611
+	private static function _add_notice($type = 'success', $msg = '', $file = '', $func = '', $line = '')
612
+	{
613
+		if (empty($msg)) {
614
+			EE_Error::doing_it_wrong(
615
+				'EE_Error::add_' . $type . '()',
616
+				sprintf(
617
+					__('Notifications are not much use without a message! Please add a message to the EE_Error::add_%s() call made in %s on line %d',
618
+						'event_espresso'),
619
+					$type,
620
+					$file,
621
+					$line
622
+				),
623
+				EVENT_ESPRESSO_VERSION
624
+			);
625
+		}
626
+		if ($type === 'errors' && (empty($file) || empty($func) || empty($line))) {
627
+			EE_Error::doing_it_wrong(
628
+				'EE_Error::add_error()',
629
+				__('You need to provide the file name, function name, and line number that the error occurred on in order to better assist with debugging.',
630
+					'event_espresso'),
631
+				EVENT_ESPRESSO_VERSION
632
+			);
633
+		}
634
+		// get separate user and developer messages if they exist
635
+		$msg      = explode('||', $msg);
636
+		$user_msg = $msg[0];
637
+		$dev_msg  = isset($msg[1]) ? $msg[1] : $msg[0];
638
+		/**
639
+		 * Do an action so other code can be triggered when a notice is created
640
+		 *
641
+		 * @param string $type     can be 'errors', 'attention', or 'success'
642
+		 * @param string $user_msg message displayed to user when WP_DEBUG is off
643
+		 * @param string $user_msg message displayed to user when WP_DEBUG is on
644
+		 * @param string $file     file where error was generated
645
+		 * @param string $func     function where error was generated
646
+		 * @param string $line     line where error was generated
647
+		 */
648
+		do_action('AHEE__EE_Error___add_notice', $type, $user_msg, $dev_msg, $file, $func, $line);
649
+		$msg = WP_DEBUG ? $dev_msg : $user_msg;
650
+		// add notice if message exists
651
+		if (! empty($msg)) {
652
+			// get error code
653
+			$notice_code = EE_Error::generate_error_code($file, $func, $line);
654
+			if (WP_DEBUG && $type === 'errors') {
655
+				$msg .= '<br/><span class="tiny-text">' . $notice_code . '</span>';
656
+			}
657
+			// add notice. Index by code if it's not blank
658
+			if ($notice_code) {
659
+				self::$_espresso_notices[$type][$notice_code] = $msg;
660
+			} else {
661
+				self::$_espresso_notices[$type][] = $msg;
662
+			}
663
+			add_action('wp_footer', array('EE_Error', 'enqueue_error_scripts'), 1);
664
+		}
665
+	}
666
+
667
+
668
+	/**
669
+	 * in some case it may be necessary to overwrite the existing success messages
670
+	 *
671
+	 * @return        void
672
+	 */
673
+	public static function overwrite_success()
674
+	{
675
+		self::$_espresso_notices['success'] = false;
676
+	}
677
+
678
+
679
+
680
+	/**
681
+	 * in some case it may be necessary to overwrite the existing attention messages
682
+	 *
683
+	 * @return void
684
+	 */
685
+	public static function overwrite_attention()
686
+	{
687
+		self::$_espresso_notices['attention'] = false;
688
+	}
689
+
690
+
691
+
692
+	/**
693
+	 * in some case it may be necessary to overwrite the existing error messages
694
+	 *
695
+	 * @return void
696
+	 */
697
+	public static function overwrite_errors()
698
+	{
699
+		self::$_espresso_notices['errors'] = false;
700
+	}
701
+
702
+
703
+
704
+	/**
705
+	 * @return void
706
+	 */
707
+	public static function reset_notices()
708
+	{
709
+		self::$_espresso_notices['success']   = false;
710
+		self::$_espresso_notices['attention'] = false;
711
+		self::$_espresso_notices['errors']    = false;
712
+	}
713
+
714
+
715
+
716
+	/**
717
+	 * @return int
718
+	 */
719
+	public static function has_notices()
720
+	{
721
+		$has_notices = 0;
722
+		// check for success messages
723
+		$has_notices = self::$_espresso_notices['success'] && ! empty(self::$_espresso_notices['success'])
724
+			? 3
725
+			: $has_notices;
726
+		// check for attention messages
727
+		$has_notices = self::$_espresso_notices['attention'] && ! empty(self::$_espresso_notices['attention'])
728
+			? 2
729
+			: $has_notices;
730
+		// check for error messages
731
+		$has_notices = self::$_espresso_notices['errors'] && ! empty(self::$_espresso_notices['errors'])
732
+			? 1
733
+			: $has_notices;
734
+		return $has_notices;
735
+	}
736
+
737
+
738
+	/**
739
+	 * This simply returns non formatted error notices as they were sent into the EE_Error object.
740
+	 *
741
+	 * @since 4.9.0
742
+	 * @return array
743
+	 */
744
+	public static function get_vanilla_notices()
745
+	{
746
+		return array(
747
+			'success'   => isset(self::$_espresso_notices['success'])
748
+				? self::$_espresso_notices['success']
749
+				: array(),
750
+			'attention' => isset(self::$_espresso_notices['attention'])
751
+				? self::$_espresso_notices['attention']
752
+				: array(),
753
+			'errors'    => isset(self::$_espresso_notices['errors'])
754
+				? self::$_espresso_notices['errors']
755
+				: array(),
756
+		);
757
+	}
758
+
759
+
760
+
761
+	/**
762
+	 * compile all error or success messages into one string
763
+	 *
764
+	 * @see EE_Error::get_raw_notices if you want the raw notices without any preparations made to them
765
+	 * @param boolean $format_output     whether or not to format the messages for display in the WP admin
766
+	 * @param boolean $save_to_transient whether or not to save notices to the db for retrieval on next request
767
+	 *                                          - ONLY do this just before redirecting
768
+	 * @param boolean $remove_empty      whether or not to unset empty messages
769
+	 * @return array
770
+	 */
771
+	public static function get_notices($format_output = true, $save_to_transient = false, $remove_empty = true)
772
+	{
773
+		// do_action('AHEE_log', __FILE__, __FUNCTION__, '');
774
+		$success_messages   = '';
775
+		$attention_messages = '';
776
+		$error_messages     = '';
777
+		$print_scripts      = false;
778
+		// EEH_Debug_Tools::printr( self::$_espresso_notices, 'espresso_notices  <br /><span style="font-size:10px;font-weight:normal;">' . __FILE__ . '<br />line no: ' . __LINE__ . '</span>', 'auto' );
779
+		// either save notices to the db
780
+		if ($save_to_transient || isset($_REQUEST['activate-selected'])) {
781
+			$existing_notices  = get_option(EE_Error::OPTIONS_KEY_NOTICES, array());
782
+			$existing_notices = is_array($existing_notices) ? $existing_notices : array();
783
+			self::$_espresso_notices = array_merge(
784
+				$existing_notices,
785
+				self::$_espresso_notices
786
+			);
787
+			update_option(EE_Error::OPTIONS_KEY_NOTICES, self::$_espresso_notices);
788
+			return array();
789
+		}
790
+		// grab any notices that have been previously saved
791
+		if ($notices = get_option(EE_Error::OPTIONS_KEY_NOTICES, array())) {
792
+			foreach ($notices as $type => $notice) {
793
+				if (is_array($notice) && ! empty($notice)) {
794
+					// make sure that existing notice type is an array
795
+					self::$_espresso_notices[$type] = is_array(self::$_espresso_notices[$type])
796
+													  && ! empty(self::$_espresso_notices[$type])
797
+						? self::$_espresso_notices[$type]
798
+						: array();
799
+					// merge stored notices with any newly created ones
800
+					self::$_espresso_notices[$type] = array_merge(self::$_espresso_notices[$type], $notice);
801
+					$print_scripts                  = true;
802
+				}
803
+			}
804
+			// now clear any stored notices
805
+			update_option(EE_Error::OPTIONS_KEY_NOTICES, array());
806
+		}
807
+		// check for success messages
808
+		if (self::$_espresso_notices['success'] && ! empty(self::$_espresso_notices['success'])) {
809
+			// combine messages
810
+			$success_messages .= implode(self::$_espresso_notices['success'], '<br />');
811
+			$print_scripts    = true;
812
+		}
813
+		// check for attention messages
814
+		if (self::$_espresso_notices['attention'] && ! empty(self::$_espresso_notices['attention'])) {
815
+			// combine messages
816
+			$attention_messages .= implode(self::$_espresso_notices['attention'], '<br />');
817
+			$print_scripts      = true;
818
+		}
819
+		// check for error messages
820
+		if (self::$_espresso_notices['errors'] && ! empty(self::$_espresso_notices['errors'])) {
821
+			$error_messages .= count(self::$_espresso_notices['errors']) > 1
822
+				? __('The following errors have occurred:<br />', 'event_espresso')
823
+				: __('An error has occurred:<br />', 'event_espresso');
824
+			// combine messages
825
+			$error_messages .= implode(self::$_espresso_notices['errors'], '<br />');
826
+			$print_scripts  = true;
827
+		}
828
+		if ($format_output) {
829
+
830
+			$notices = '<div id="espresso-notices">';
831
+			$close = is_admin() ? ''
832
+				: '<a class="close-espresso-notice hide-if-no-js"><span class="dashicons dashicons-no"></span></a>';
833
+			if ($success_messages !== '') {
834
+				$css_id    = is_admin() ? 'ee-success-message' : 'espresso-notices-success';
835
+				$css_class = is_admin() ? 'updated fade' : 'success fade-away';
836
+				//showMessage( $success_messages );
837
+				$notices .= '<div id="'
838
+							. $css_id
839
+							. '" class="espresso-notices '
840
+							. $css_class
841
+							. '" style="display:none;"><p>'
842
+							. $success_messages
843
+							. '</p>'
844
+							. $close
845
+							. '</div>';
846
+			}
847
+			if ($attention_messages !== '') {
848
+				$css_id    = is_admin() ? 'ee-attention-message' : 'espresso-notices-attention';
849
+				$css_class = is_admin() ? 'updated ee-notices-attention' : 'attention fade-away';
850
+				//showMessage( $error_messages, TRUE );
851
+				$notices .= '<div id="'
852
+							. $css_id
853
+							. '" class="espresso-notices '
854
+							. $css_class
855
+							. '" style="display:none;"><p>'
856
+							. $attention_messages
857
+							. '</p>'
858
+							. $close
859
+							. '</div>';
860
+			}
861
+			if ($error_messages !== '') {
862
+				$css_id    = is_admin() ? 'ee-error-message' : 'espresso-notices-error';
863
+				$css_class = is_admin() ? 'error' : 'error fade-away';
864
+				//showMessage( $error_messages, TRUE );
865
+				$notices .= '<div id="'
866
+							. $css_id
867
+							. '" class="espresso-notices '
868
+							. $css_class
869
+							. '" style="display:none;"><p>'
870
+							. $error_messages
871
+							. '</p>'
872
+							. $close
873
+							. '</div>';
874
+			}
875
+			$notices .= '</div>';
876
+		} else {
877
+
878
+			$notices = array(
879
+				'success'   => $success_messages,
880
+				'attention' => $attention_messages,
881
+				'errors'    => $error_messages,
882
+			);
883
+			if ($remove_empty) {
884
+				// remove empty notices
885
+				foreach ($notices as $type => $notice) {
886
+					if (empty($notice)) {
887
+						unset($notices[$type]);
888
+					}
889
+				}
890
+			}
891
+		}
892
+		if ($print_scripts) {
893
+			self::_print_scripts();
894
+		}
895
+		return $notices;
896
+	}
897
+
898
+
899
+
900
+	/**
901
+	 * _print_scripts
902
+	 *
903
+	 * @param    bool $force_print
904
+	 * @return    string
905
+	 */
906
+	private static function _print_scripts($force_print = false)
907
+	{
908
+		if (! $force_print && (did_action('admin_enqueue_scripts') || did_action('wp_enqueue_scripts'))) {
909
+			if (wp_script_is('ee_error_js', 'enqueued')) {
910
+				return '';
911
+			}
912
+			if (wp_script_is('ee_error_js', 'registered')) {
913
+				wp_enqueue_style('espresso_default');
914
+				wp_enqueue_style('espresso_custom_css');
915
+				wp_enqueue_script('ee_error_js');
916
+				wp_localize_script('ee_error_js', 'ee_settings', array('wp_debug' => WP_DEBUG));
917
+			}
918
+		} else {
919
+			return '
920 920
 <script>
921 921
 /* <![CDATA[ */
922 922
 var ee_settings = {"wp_debug":"' . WP_DEBUG . '"};
@@ -926,223 +926,223 @@  discard block
 block discarded – undo
926 926
 <script src="' . EE_GLOBAL_ASSETS_URL . 'scripts/espresso_core.js' . '?ver=' . espresso_version() . '" type="text/javascript"></script>
927 927
 <script src="' . EE_GLOBAL_ASSETS_URL . 'scripts/EE_Error.js' . '?ver=' . espresso_version() . '" type="text/javascript"></script>
928 928
 ';
929
-        }
930
-        return '';
931
-    }
932
-
933
-
934
-
935
-    /**
936
-     * @return void
937
-     */
938
-    public static function enqueue_error_scripts()
939
-    {
940
-        self::_print_scripts();
941
-    }
942
-
943
-
944
-
945
-    /**
946
-     * create error code from filepath, function name,
947
-     * and line number where exception or error was thrown
948
-     *
949
-     * @param string $file
950
-     * @param string $func
951
-     * @param string $line
952
-     * @return string
953
-     */
954
-    public static function generate_error_code($file = '', $func = '', $line = '')
955
-    {
956
-        $file       = explode('.', basename($file));
957
-        $error_code = ! empty($file[0]) ? $file[0] : '';
958
-        $error_code .= ! empty($func) ? ' - ' . $func : '';
959
-        $error_code .= ! empty($line) ? ' - ' . $line : '';
960
-        return $error_code;
961
-    }
962
-
963
-
964
-
965
-    /**
966
-     * write exception details to log file
967
-     * Since 4.9.53.rc.006 this writes to the standard PHP log file, not EE's custom log file
968
-     *
969
-     * @param int   $time
970
-     * @param array $ex
971
-     * @param bool  $clear
972
-     * @return void
973
-     */
974
-    public function write_to_error_log($time = 0, $ex = array(), $clear = false)
975
-    {
976
-        if (empty($ex)) {
977
-            return;
978
-        }
979
-        if (! $time) {
980
-            $time = time();
981
-        }
982
-        $exception_log = '----------------------------------------------------------------------------------------'
983
-                         . PHP_EOL;
984
-        $exception_log .= '[' . date('Y-m-d H:i:s', $time) . ']  Exception Details' . PHP_EOL;
985
-        $exception_log .= 'Message: ' . $ex['msg'] . PHP_EOL;
986
-        $exception_log .= 'Code: ' . $ex['code'] . PHP_EOL;
987
-        $exception_log .= 'File: ' . $ex['file'] . PHP_EOL;
988
-        $exception_log .= 'Line No: ' . $ex['line'] . PHP_EOL;
989
-        $exception_log .= 'Stack trace: ' . PHP_EOL;
990
-        $exception_log .= $ex['string'] . PHP_EOL;
991
-        $exception_log .= '----------------------------------------------------------------------------------------'
992
-                          . PHP_EOL;
993
-        try {
994
-            error_log($exception_log);
995
-        } catch (EE_Error $e) {
996
-            EE_Error::add_error(sprintf(__('Event Espresso error logging could not be setup because: %s',
997
-                'event_espresso'), $e->getMessage()));
998
-        }
999
-    }
1000
-
1001
-
1002
-
1003
-    /**
1004
-     * This is just a wrapper for the EEH_Debug_Tools::instance()->doing_it_wrong() method.
1005
-     * doing_it_wrong() is used in those cases where a normal PHP error won't get thrown,
1006
-     * but the code execution is done in a manner that could lead to unexpected results
1007
-     * (i.e. running to early, or too late in WP or EE loading process).
1008
-     * A good test for knowing whether to use this method is:
1009
-     * 1. Is there going to be a PHP error if something isn't setup/used correctly?
1010
-     * Yes -> use EE_Error::add_error() or throw new EE_Error()
1011
-     * 2. If this is loaded before something else, it won't break anything,
1012
-     * but just wont' do what its supposed to do? Yes -> use EE_Error::doing_it_wrong()
1013
-     *
1014
-     * @uses   constant WP_DEBUG test if wp_debug is on or not
1015
-     * @param string $function      The function that was called
1016
-     * @param string $message       A message explaining what has been done incorrectly
1017
-     * @param string $version       The version of Event Espresso where the error was added
1018
-     * @param string $applies_when  a version string for when you want the doing_it_wrong notice to begin appearing
1019
-     *                              for a deprecated function. This allows deprecation to occur during one version,
1020
-     *                              but not have any notices appear until a later version. This allows developers
1021
-     *                              extra time to update their code before notices appear.
1022
-     * @param int    $error_type
1023
-     */
1024
-    public static function doing_it_wrong(
1025
-        $function,
1026
-        $message,
1027
-        $version,
1028
-        $applies_when = '',
1029
-        $error_type = null
1030
-    ) {
1031
-        if (defined('WP_DEBUG') && WP_DEBUG) {
1032
-            EEH_Debug_Tools::instance()->doing_it_wrong($function, $message, $version, $applies_when, $error_type);
1033
-        }
1034
-    }
1035
-
1036
-
1037
-
1038
-    /**
1039
-     * Like get_notices, but returns an array of all the notices of the given type.
1040
-     *
1041
-     * @return array {
1042
-     *  @type array $success   all the success messages
1043
-     *  @type array $errors    all the error messages
1044
-     *  @type array $attention all the attention messages
1045
-     * }
1046
-     */
1047
-    public static function get_raw_notices()
1048
-    {
1049
-        return self::$_espresso_notices;
1050
-    }
1051
-
1052
-
1053
-
1054
-    /**
1055
-     * @deprecated 4.9.27
1056
-     * @param string $pan_name     the name, or key of the Persistent Admin Notice to be stored
1057
-     * @param string $pan_message  the message to be stored persistently until dismissed
1058
-     * @param bool   $force_update allows one to enforce the reappearance of a persistent message.
1059
-     * @return void
1060
-     * @throws InvalidDataTypeException
1061
-     */
1062
-    public static function add_persistent_admin_notice($pan_name = '', $pan_message, $force_update = false)
1063
-    {
1064
-        new PersistentAdminNotice(
1065
-            $pan_name,
1066
-            $pan_message,
1067
-            $force_update
1068
-        );
1069
-        EE_Error::doing_it_wrong(
1070
-            __METHOD__,
1071
-            sprintf(
1072
-                __('Usage is deprecated. Use "%1$s" instead.', 'event_espresso'),
1073
-                '\EventEspresso\core\domain\entities\notifications\PersistentAdminNotice'
1074
-            ),
1075
-            '4.9.27'
1076
-        );
1077
-    }
1078
-
1079
-
1080
-
1081
-    /**
1082
-     * @deprecated 4.9.27
1083
-     * @param string $pan_name the name, or key of the Persistent Admin Notice to be dismissed
1084
-     * @param bool   $purge
1085
-     * @param bool   $return
1086
-     * @throws DomainException
1087
-     * @throws InvalidInterfaceException
1088
-     * @throws InvalidDataTypeException
1089
-     * @throws ServiceNotFoundException
1090
-     * @throws InvalidArgumentException
1091
-     */
1092
-    public static function dismiss_persistent_admin_notice($pan_name = '', $purge = false, $return = false)
1093
-    {
1094
-        /** @var PersistentAdminNoticeManager $persistent_admin_notice_manager */
1095
-        $persistent_admin_notice_manager = LoaderFactory::getLoader()->getShared(
1096
-            'EventEspresso\core\services\notifications\PersistentAdminNoticeManager'
1097
-        );
1098
-        $persistent_admin_notice_manager->dismissNotice($pan_name, $purge, $return);
1099
-        EE_Error::doing_it_wrong(
1100
-            __METHOD__,
1101
-            sprintf(
1102
-                __('Usage is deprecated. Use "%1$s" instead.', 'event_espresso'),
1103
-                '\EventEspresso\core\services\notifications\PersistentAdminNoticeManager'
1104
-            ),
1105
-            '4.9.27'
1106
-        );
1107
-    }
1108
-
1109
-
1110
-
1111
-    /**
1112
-     * @deprecated 4.9.27
1113
-     * @param  string $pan_name    the name, or key of the Persistent Admin Notice to be stored
1114
-     * @param  string $pan_message the message to be stored persistently until dismissed
1115
-     * @param  string $return_url  URL to go back to after nag notice is dismissed
1116
-     */
1117
-    public static function display_persistent_admin_notices($pan_name = '', $pan_message = '', $return_url = '')
1118
-    {
1119
-        EE_Error::doing_it_wrong(
1120
-            __METHOD__,
1121
-            sprintf(
1122
-                __('Usage is deprecated. Use "%1$s" instead.', 'event_espresso'),
1123
-                '\EventEspresso\core\services\notifications\PersistentAdminNoticeManager'
1124
-            ),
1125
-            '4.9.27'
1126
-        );
1127
-    }
1128
-
1129
-
1130
-
1131
-    /**
1132
-     * @deprecated 4.9.27
1133
-     * @param string $return_url
1134
-     */
1135
-    public static function get_persistent_admin_notices($return_url = '')
1136
-    {
1137
-        EE_Error::doing_it_wrong(
1138
-            __METHOD__,
1139
-            sprintf(
1140
-                __('Usage is deprecated. Use "%1$s" instead.', 'event_espresso'),
1141
-                '\EventEspresso\core\services\notifications\PersistentAdminNoticeManager'
1142
-            ),
1143
-            '4.9.27'
1144
-        );
1145
-    }
929
+		}
930
+		return '';
931
+	}
932
+
933
+
934
+
935
+	/**
936
+	 * @return void
937
+	 */
938
+	public static function enqueue_error_scripts()
939
+	{
940
+		self::_print_scripts();
941
+	}
942
+
943
+
944
+
945
+	/**
946
+	 * create error code from filepath, function name,
947
+	 * and line number where exception or error was thrown
948
+	 *
949
+	 * @param string $file
950
+	 * @param string $func
951
+	 * @param string $line
952
+	 * @return string
953
+	 */
954
+	public static function generate_error_code($file = '', $func = '', $line = '')
955
+	{
956
+		$file       = explode('.', basename($file));
957
+		$error_code = ! empty($file[0]) ? $file[0] : '';
958
+		$error_code .= ! empty($func) ? ' - ' . $func : '';
959
+		$error_code .= ! empty($line) ? ' - ' . $line : '';
960
+		return $error_code;
961
+	}
962
+
963
+
964
+
965
+	/**
966
+	 * write exception details to log file
967
+	 * Since 4.9.53.rc.006 this writes to the standard PHP log file, not EE's custom log file
968
+	 *
969
+	 * @param int   $time
970
+	 * @param array $ex
971
+	 * @param bool  $clear
972
+	 * @return void
973
+	 */
974
+	public function write_to_error_log($time = 0, $ex = array(), $clear = false)
975
+	{
976
+		if (empty($ex)) {
977
+			return;
978
+		}
979
+		if (! $time) {
980
+			$time = time();
981
+		}
982
+		$exception_log = '----------------------------------------------------------------------------------------'
983
+						 . PHP_EOL;
984
+		$exception_log .= '[' . date('Y-m-d H:i:s', $time) . ']  Exception Details' . PHP_EOL;
985
+		$exception_log .= 'Message: ' . $ex['msg'] . PHP_EOL;
986
+		$exception_log .= 'Code: ' . $ex['code'] . PHP_EOL;
987
+		$exception_log .= 'File: ' . $ex['file'] . PHP_EOL;
988
+		$exception_log .= 'Line No: ' . $ex['line'] . PHP_EOL;
989
+		$exception_log .= 'Stack trace: ' . PHP_EOL;
990
+		$exception_log .= $ex['string'] . PHP_EOL;
991
+		$exception_log .= '----------------------------------------------------------------------------------------'
992
+						  . PHP_EOL;
993
+		try {
994
+			error_log($exception_log);
995
+		} catch (EE_Error $e) {
996
+			EE_Error::add_error(sprintf(__('Event Espresso error logging could not be setup because: %s',
997
+				'event_espresso'), $e->getMessage()));
998
+		}
999
+	}
1000
+
1001
+
1002
+
1003
+	/**
1004
+	 * This is just a wrapper for the EEH_Debug_Tools::instance()->doing_it_wrong() method.
1005
+	 * doing_it_wrong() is used in those cases where a normal PHP error won't get thrown,
1006
+	 * but the code execution is done in a manner that could lead to unexpected results
1007
+	 * (i.e. running to early, or too late in WP or EE loading process).
1008
+	 * A good test for knowing whether to use this method is:
1009
+	 * 1. Is there going to be a PHP error if something isn't setup/used correctly?
1010
+	 * Yes -> use EE_Error::add_error() or throw new EE_Error()
1011
+	 * 2. If this is loaded before something else, it won't break anything,
1012
+	 * but just wont' do what its supposed to do? Yes -> use EE_Error::doing_it_wrong()
1013
+	 *
1014
+	 * @uses   constant WP_DEBUG test if wp_debug is on or not
1015
+	 * @param string $function      The function that was called
1016
+	 * @param string $message       A message explaining what has been done incorrectly
1017
+	 * @param string $version       The version of Event Espresso where the error was added
1018
+	 * @param string $applies_when  a version string for when you want the doing_it_wrong notice to begin appearing
1019
+	 *                              for a deprecated function. This allows deprecation to occur during one version,
1020
+	 *                              but not have any notices appear until a later version. This allows developers
1021
+	 *                              extra time to update their code before notices appear.
1022
+	 * @param int    $error_type
1023
+	 */
1024
+	public static function doing_it_wrong(
1025
+		$function,
1026
+		$message,
1027
+		$version,
1028
+		$applies_when = '',
1029
+		$error_type = null
1030
+	) {
1031
+		if (defined('WP_DEBUG') && WP_DEBUG) {
1032
+			EEH_Debug_Tools::instance()->doing_it_wrong($function, $message, $version, $applies_when, $error_type);
1033
+		}
1034
+	}
1035
+
1036
+
1037
+
1038
+	/**
1039
+	 * Like get_notices, but returns an array of all the notices of the given type.
1040
+	 *
1041
+	 * @return array {
1042
+	 *  @type array $success   all the success messages
1043
+	 *  @type array $errors    all the error messages
1044
+	 *  @type array $attention all the attention messages
1045
+	 * }
1046
+	 */
1047
+	public static function get_raw_notices()
1048
+	{
1049
+		return self::$_espresso_notices;
1050
+	}
1051
+
1052
+
1053
+
1054
+	/**
1055
+	 * @deprecated 4.9.27
1056
+	 * @param string $pan_name     the name, or key of the Persistent Admin Notice to be stored
1057
+	 * @param string $pan_message  the message to be stored persistently until dismissed
1058
+	 * @param bool   $force_update allows one to enforce the reappearance of a persistent message.
1059
+	 * @return void
1060
+	 * @throws InvalidDataTypeException
1061
+	 */
1062
+	public static function add_persistent_admin_notice($pan_name = '', $pan_message, $force_update = false)
1063
+	{
1064
+		new PersistentAdminNotice(
1065
+			$pan_name,
1066
+			$pan_message,
1067
+			$force_update
1068
+		);
1069
+		EE_Error::doing_it_wrong(
1070
+			__METHOD__,
1071
+			sprintf(
1072
+				__('Usage is deprecated. Use "%1$s" instead.', 'event_espresso'),
1073
+				'\EventEspresso\core\domain\entities\notifications\PersistentAdminNotice'
1074
+			),
1075
+			'4.9.27'
1076
+		);
1077
+	}
1078
+
1079
+
1080
+
1081
+	/**
1082
+	 * @deprecated 4.9.27
1083
+	 * @param string $pan_name the name, or key of the Persistent Admin Notice to be dismissed
1084
+	 * @param bool   $purge
1085
+	 * @param bool   $return
1086
+	 * @throws DomainException
1087
+	 * @throws InvalidInterfaceException
1088
+	 * @throws InvalidDataTypeException
1089
+	 * @throws ServiceNotFoundException
1090
+	 * @throws InvalidArgumentException
1091
+	 */
1092
+	public static function dismiss_persistent_admin_notice($pan_name = '', $purge = false, $return = false)
1093
+	{
1094
+		/** @var PersistentAdminNoticeManager $persistent_admin_notice_manager */
1095
+		$persistent_admin_notice_manager = LoaderFactory::getLoader()->getShared(
1096
+			'EventEspresso\core\services\notifications\PersistentAdminNoticeManager'
1097
+		);
1098
+		$persistent_admin_notice_manager->dismissNotice($pan_name, $purge, $return);
1099
+		EE_Error::doing_it_wrong(
1100
+			__METHOD__,
1101
+			sprintf(
1102
+				__('Usage is deprecated. Use "%1$s" instead.', 'event_espresso'),
1103
+				'\EventEspresso\core\services\notifications\PersistentAdminNoticeManager'
1104
+			),
1105
+			'4.9.27'
1106
+		);
1107
+	}
1108
+
1109
+
1110
+
1111
+	/**
1112
+	 * @deprecated 4.9.27
1113
+	 * @param  string $pan_name    the name, or key of the Persistent Admin Notice to be stored
1114
+	 * @param  string $pan_message the message to be stored persistently until dismissed
1115
+	 * @param  string $return_url  URL to go back to after nag notice is dismissed
1116
+	 */
1117
+	public static function display_persistent_admin_notices($pan_name = '', $pan_message = '', $return_url = '')
1118
+	{
1119
+		EE_Error::doing_it_wrong(
1120
+			__METHOD__,
1121
+			sprintf(
1122
+				__('Usage is deprecated. Use "%1$s" instead.', 'event_espresso'),
1123
+				'\EventEspresso\core\services\notifications\PersistentAdminNoticeManager'
1124
+			),
1125
+			'4.9.27'
1126
+		);
1127
+	}
1128
+
1129
+
1130
+
1131
+	/**
1132
+	 * @deprecated 4.9.27
1133
+	 * @param string $return_url
1134
+	 */
1135
+	public static function get_persistent_admin_notices($return_url = '')
1136
+	{
1137
+		EE_Error::doing_it_wrong(
1138
+			__METHOD__,
1139
+			sprintf(
1140
+				__('Usage is deprecated. Use "%1$s" instead.', 'event_espresso'),
1141
+				'\EventEspresso\core\services\notifications\PersistentAdminNoticeManager'
1142
+			),
1143
+			'4.9.27'
1144
+		);
1145
+	}
1146 1146
 
1147 1147
 
1148 1148
 
@@ -1157,27 +1157,27 @@  discard block
 block discarded – undo
1157 1157
  */
1158 1158
 function espresso_error_enqueue_scripts()
1159 1159
 {
1160
-    // js for error handling
1161
-    wp_register_script(
1162
-        'espresso_core',
1163
-        EE_GLOBAL_ASSETS_URL . 'scripts/espresso_core.js',
1164
-        array('jquery'),
1165
-        EVENT_ESPRESSO_VERSION,
1166
-        false
1167
-    );
1168
-    wp_register_script(
1169
-        'ee_error_js',
1170
-        EE_GLOBAL_ASSETS_URL . 'scripts/EE_Error.js',
1171
-        array('espresso_core'),
1172
-        EVENT_ESPRESSO_VERSION,
1173
-        false
1174
-    );
1160
+	// js for error handling
1161
+	wp_register_script(
1162
+		'espresso_core',
1163
+		EE_GLOBAL_ASSETS_URL . 'scripts/espresso_core.js',
1164
+		array('jquery'),
1165
+		EVENT_ESPRESSO_VERSION,
1166
+		false
1167
+	);
1168
+	wp_register_script(
1169
+		'ee_error_js',
1170
+		EE_GLOBAL_ASSETS_URL . 'scripts/EE_Error.js',
1171
+		array('espresso_core'),
1172
+		EVENT_ESPRESSO_VERSION,
1173
+		false
1174
+	);
1175 1175
 }
1176 1176
 
1177 1177
 if (is_admin()) {
1178
-    add_action('admin_enqueue_scripts', 'espresso_error_enqueue_scripts', 2);
1178
+	add_action('admin_enqueue_scripts', 'espresso_error_enqueue_scripts', 2);
1179 1179
 } else {
1180
-    add_action('wp_enqueue_scripts', 'espresso_error_enqueue_scripts', 2);
1180
+	add_action('wp_enqueue_scripts', 'espresso_error_enqueue_scripts', 2);
1181 1181
 }
1182 1182
 
1183 1183
 
Please login to merge, or discard this patch.
core/bootstrap_espresso.php 2 patches
Indentation   +64 added lines, -64 removed lines patch added patch discarded remove patch
@@ -9,22 +9,22 @@  discard block
 block discarded – undo
9 9
  */
10 10
 function espresso_load_error_handling()
11 11
 {
12
-    static $error_handling_loaded = false;
13
-    if ($error_handling_loaded) {
14
-        return;
15
-    }
16
-    // load debugging tools
17
-    if (WP_DEBUG === true && is_readable(EE_HELPERS . 'EEH_Debug_Tools.helper.php')) {
18
-        require_once EE_HELPERS . 'EEH_Debug_Tools.helper.php';
19
-        \EEH_Debug_Tools::instance();
20
-    }
21
-    // load error handling
22
-    if (is_readable(EE_CORE . 'EE_Error.core.php')) {
23
-        require_once EE_CORE . 'EE_Error.core.php';
24
-    } else {
25
-        wp_die(esc_html__('The EE_Error core class could not be loaded.', 'event_espresso'));
26
-    }
27
-    $error_handling_loaded = true;
12
+	static $error_handling_loaded = false;
13
+	if ($error_handling_loaded) {
14
+		return;
15
+	}
16
+	// load debugging tools
17
+	if (WP_DEBUG === true && is_readable(EE_HELPERS . 'EEH_Debug_Tools.helper.php')) {
18
+		require_once EE_HELPERS . 'EEH_Debug_Tools.helper.php';
19
+		\EEH_Debug_Tools::instance();
20
+	}
21
+	// load error handling
22
+	if (is_readable(EE_CORE . 'EE_Error.core.php')) {
23
+		require_once EE_CORE . 'EE_Error.core.php';
24
+	} else {
25
+		wp_die(esc_html__('The EE_Error core class could not be loaded.', 'event_espresso'));
26
+	}
27
+	$error_handling_loaded = true;
28 28
 }
29 29
 
30 30
 
@@ -38,19 +38,19 @@  discard block
 block discarded – undo
38 38
  */
39 39
 function espresso_load_required($classname, $full_path_to_file)
40 40
 {
41
-    if (is_readable($full_path_to_file)) {
42
-        require_once $full_path_to_file;
43
-    } else {
44
-        throw new \EE_Error (
45
-            sprintf(
46
-                esc_html__(
47
-                    'The %s class file could not be located or is not readable due to file permissions.',
48
-                    'event_espresso'
49
-                ),
50
-                $classname
51
-            )
52
-        );
53
-    }
41
+	if (is_readable($full_path_to_file)) {
42
+		require_once $full_path_to_file;
43
+	} else {
44
+		throw new \EE_Error (
45
+			sprintf(
46
+				esc_html__(
47
+					'The %s class file could not be located or is not readable due to file permissions.',
48
+					'event_espresso'
49
+				),
50
+				$classname
51
+			)
52
+		);
53
+	}
54 54
 }
55 55
 
56 56
 
@@ -69,41 +69,41 @@  discard block
 block discarded – undo
69 69
  */
70 70
 function bootstrap_espresso()
71 71
 {
72
-    require_once __DIR__ . '/espresso_definitions.php';
73
-    try {
74
-        espresso_load_error_handling();
75
-        espresso_load_required(
76
-            'EEH_Base',
77
-            EE_CORE . 'helpers' . DS . 'EEH_Base.helper.php'
78
-        );
79
-        espresso_load_required(
80
-            'EEH_File',
81
-            EE_CORE . 'interfaces' . DS . 'EEHI_File.interface.php'
82
-        );
83
-        espresso_load_required(
84
-            'EEH_File',
85
-            EE_CORE . 'helpers' . DS . 'EEH_File.helper.php'
86
-        );
87
-        espresso_load_required(
88
-            'EEH_Array',
89
-            EE_CORE . 'helpers' . DS . 'EEH_Array.helper.php'
90
-        );
91
-        // instantiate and configure PSR4 autoloader
92
-        espresso_load_required(
93
-            'Psr4Autoloader',
94
-            EE_CORE . 'Psr4Autoloader.php'
95
-        );
96
-        espresso_load_required(
97
-            'EE_Psr4AutoloaderInit',
98
-            EE_CORE . 'EE_Psr4AutoloaderInit.core.php'
99
-        );
100
-        $AutoloaderInit = new EE_Psr4AutoloaderInit();
101
-        $AutoloaderInit->initializeAutoloader();
102
-        new EventEspresso\core\services\bootstrap\BootstrapCore();
103
-    } catch (Exception $e) {
104
-        require_once EE_CORE . 'exceptions' . DS . 'ExceptionStackTraceDisplay.php';
105
-        new EventEspresso\core\exceptions\ExceptionStackTraceDisplay($e);
106
-    }
72
+	require_once __DIR__ . '/espresso_definitions.php';
73
+	try {
74
+		espresso_load_error_handling();
75
+		espresso_load_required(
76
+			'EEH_Base',
77
+			EE_CORE . 'helpers' . DS . 'EEH_Base.helper.php'
78
+		);
79
+		espresso_load_required(
80
+			'EEH_File',
81
+			EE_CORE . 'interfaces' . DS . 'EEHI_File.interface.php'
82
+		);
83
+		espresso_load_required(
84
+			'EEH_File',
85
+			EE_CORE . 'helpers' . DS . 'EEH_File.helper.php'
86
+		);
87
+		espresso_load_required(
88
+			'EEH_Array',
89
+			EE_CORE . 'helpers' . DS . 'EEH_Array.helper.php'
90
+		);
91
+		// instantiate and configure PSR4 autoloader
92
+		espresso_load_required(
93
+			'Psr4Autoloader',
94
+			EE_CORE . 'Psr4Autoloader.php'
95
+		);
96
+		espresso_load_required(
97
+			'EE_Psr4AutoloaderInit',
98
+			EE_CORE . 'EE_Psr4AutoloaderInit.core.php'
99
+		);
100
+		$AutoloaderInit = new EE_Psr4AutoloaderInit();
101
+		$AutoloaderInit->initializeAutoloader();
102
+		new EventEspresso\core\services\bootstrap\BootstrapCore();
103
+	} catch (Exception $e) {
104
+		require_once EE_CORE . 'exceptions' . DS . 'ExceptionStackTraceDisplay.php';
105
+		new EventEspresso\core\exceptions\ExceptionStackTraceDisplay($e);
106
+	}
107 107
 }
108 108
 
109 109
 
Please login to merge, or discard this patch.
Spacing   +13 added lines, -13 removed lines patch added patch discarded remove patch
@@ -14,13 +14,13 @@  discard block
 block discarded – undo
14 14
         return;
15 15
     }
16 16
     // load debugging tools
17
-    if (WP_DEBUG === true && is_readable(EE_HELPERS . 'EEH_Debug_Tools.helper.php')) {
18
-        require_once EE_HELPERS . 'EEH_Debug_Tools.helper.php';
17
+    if (WP_DEBUG === true && is_readable(EE_HELPERS.'EEH_Debug_Tools.helper.php')) {
18
+        require_once EE_HELPERS.'EEH_Debug_Tools.helper.php';
19 19
         \EEH_Debug_Tools::instance();
20 20
     }
21 21
     // load error handling
22
-    if (is_readable(EE_CORE . 'EE_Error.core.php')) {
23
-        require_once EE_CORE . 'EE_Error.core.php';
22
+    if (is_readable(EE_CORE.'EE_Error.core.php')) {
23
+        require_once EE_CORE.'EE_Error.core.php';
24 24
     } else {
25 25
         wp_die(esc_html__('The EE_Error core class could not be loaded.', 'event_espresso'));
26 26
     }
@@ -41,7 +41,7 @@  discard block
 block discarded – undo
41 41
     if (is_readable($full_path_to_file)) {
42 42
         require_once $full_path_to_file;
43 43
     } else {
44
-        throw new \EE_Error (
44
+        throw new \EE_Error(
45 45
             sprintf(
46 46
                 esc_html__(
47 47
                     'The %s class file could not be located or is not readable due to file permissions.',
@@ -69,39 +69,39 @@  discard block
 block discarded – undo
69 69
  */
70 70
 function bootstrap_espresso()
71 71
 {
72
-    require_once __DIR__ . '/espresso_definitions.php';
72
+    require_once __DIR__.'/espresso_definitions.php';
73 73
     try {
74 74
         espresso_load_error_handling();
75 75
         espresso_load_required(
76 76
             'EEH_Base',
77
-            EE_CORE . 'helpers' . DS . 'EEH_Base.helper.php'
77
+            EE_CORE.'helpers'.DS.'EEH_Base.helper.php'
78 78
         );
79 79
         espresso_load_required(
80 80
             'EEH_File',
81
-            EE_CORE . 'interfaces' . DS . 'EEHI_File.interface.php'
81
+            EE_CORE.'interfaces'.DS.'EEHI_File.interface.php'
82 82
         );
83 83
         espresso_load_required(
84 84
             'EEH_File',
85
-            EE_CORE . 'helpers' . DS . 'EEH_File.helper.php'
85
+            EE_CORE.'helpers'.DS.'EEH_File.helper.php'
86 86
         );
87 87
         espresso_load_required(
88 88
             'EEH_Array',
89
-            EE_CORE . 'helpers' . DS . 'EEH_Array.helper.php'
89
+            EE_CORE.'helpers'.DS.'EEH_Array.helper.php'
90 90
         );
91 91
         // instantiate and configure PSR4 autoloader
92 92
         espresso_load_required(
93 93
             'Psr4Autoloader',
94
-            EE_CORE . 'Psr4Autoloader.php'
94
+            EE_CORE.'Psr4Autoloader.php'
95 95
         );
96 96
         espresso_load_required(
97 97
             'EE_Psr4AutoloaderInit',
98
-            EE_CORE . 'EE_Psr4AutoloaderInit.core.php'
98
+            EE_CORE.'EE_Psr4AutoloaderInit.core.php'
99 99
         );
100 100
         $AutoloaderInit = new EE_Psr4AutoloaderInit();
101 101
         $AutoloaderInit->initializeAutoloader();
102 102
         new EventEspresso\core\services\bootstrap\BootstrapCore();
103 103
     } catch (Exception $e) {
104
-        require_once EE_CORE . 'exceptions' . DS . 'ExceptionStackTraceDisplay.php';
104
+        require_once EE_CORE.'exceptions'.DS.'ExceptionStackTraceDisplay.php';
105 105
         new EventEspresso\core\exceptions\ExceptionStackTraceDisplay($e);
106 106
     }
107 107
 }
Please login to merge, or discard this patch.
espresso.php 2 patches
Spacing   +6 added lines, -6 removed lines patch added patch discarded remove patch
@@ -38,7 +38,7 @@  discard block
 block discarded – undo
38 38
  * @since       4.0
39 39
  */
40 40
 if (function_exists('espresso_version')) {
41
-    if (! function_exists('espresso_duplicate_plugin_error')) {
41
+    if ( ! function_exists('espresso_duplicate_plugin_error')) {
42 42
         /**
43 43
          *    espresso_duplicate_plugin_error
44 44
          *    displays if more than one version of EE is activated at the same time
@@ -63,7 +63,7 @@  discard block
 block discarded – undo
63 63
 
64 64
 } else {
65 65
     define('EE_MIN_PHP_VER_REQUIRED', '5.3.9');
66
-    if (! version_compare(PHP_VERSION, EE_MIN_PHP_VER_REQUIRED, '>=')) {
66
+    if ( ! version_compare(PHP_VERSION, EE_MIN_PHP_VER_REQUIRED, '>=')) {
67 67
         /**
68 68
          * espresso_minimum_php_version_error
69 69
          * @return void
@@ -116,11 +116,11 @@  discard block
 block discarded – undo
116 116
 
117 117
         register_activation_hook(EVENT_ESPRESSO_MAIN_FILE, 'espresso_plugin_activation');
118 118
 
119
-        require_once __DIR__ . '/core/bootstrap_espresso.php';
119
+        require_once __DIR__.'/core/bootstrap_espresso.php';
120 120
         bootstrap_espresso();
121 121
     }
122 122
 }
123
-if (! function_exists('espresso_deactivate_plugin')) {
123
+if ( ! function_exists('espresso_deactivate_plugin')) {
124 124
     /**
125 125
      *    deactivate_plugin
126 126
      * usage:  espresso_deactivate_plugin( plugin_basename( __FILE__ ));
@@ -131,8 +131,8 @@  discard block
 block discarded – undo
131 131
      */
132 132
     function espresso_deactivate_plugin($plugin_basename = '')
133 133
     {
134
-        if (! function_exists('deactivate_plugins')) {
135
-            require_once ABSPATH . 'wp-admin/includes/plugin.php';
134
+        if ( ! function_exists('deactivate_plugins')) {
135
+            require_once ABSPATH.'wp-admin/includes/plugin.php';
136 136
         }
137 137
         unset($_GET['activate'], $_REQUEST['activate']);
138 138
         deactivate_plugins($plugin_basename);
Please login to merge, or discard this patch.
Indentation   +79 added lines, -79 removed lines patch added patch discarded remove patch
@@ -38,103 +38,103 @@
 block discarded – undo
38 38
  * @since       4.0
39 39
  */
40 40
 if (function_exists('espresso_version')) {
41
-    if (! function_exists('espresso_duplicate_plugin_error')) {
42
-        /**
43
-         *    espresso_duplicate_plugin_error
44
-         *    displays if more than one version of EE is activated at the same time
45
-         */
46
-        function espresso_duplicate_plugin_error()
47
-        {
48
-            ?>
41
+	if (! function_exists('espresso_duplicate_plugin_error')) {
42
+		/**
43
+		 *    espresso_duplicate_plugin_error
44
+		 *    displays if more than one version of EE is activated at the same time
45
+		 */
46
+		function espresso_duplicate_plugin_error()
47
+		{
48
+			?>
49 49
             <div class="error">
50 50
                 <p>
51 51
                     <?php
52
-                    echo esc_html__(
53
-                        'Can not run multiple versions of Event Espresso! One version has been automatically deactivated. Please verify that you have the correct version you want still active.',
54
-                        'event_espresso'
55
-                    ); ?>
52
+					echo esc_html__(
53
+						'Can not run multiple versions of Event Espresso! One version has been automatically deactivated. Please verify that you have the correct version you want still active.',
54
+						'event_espresso'
55
+					); ?>
56 56
                 </p>
57 57
             </div>
58 58
             <?php
59
-            espresso_deactivate_plugin(plugin_basename(__FILE__));
60
-        }
61
-    }
62
-    add_action('admin_notices', 'espresso_duplicate_plugin_error', 1);
59
+			espresso_deactivate_plugin(plugin_basename(__FILE__));
60
+		}
61
+	}
62
+	add_action('admin_notices', 'espresso_duplicate_plugin_error', 1);
63 63
 
64 64
 } else {
65
-    define('EE_MIN_PHP_VER_REQUIRED', '5.3.9');
66
-    if (! version_compare(PHP_VERSION, EE_MIN_PHP_VER_REQUIRED, '>=')) {
67
-        /**
68
-         * espresso_minimum_php_version_error
69
-         * @return void
70
-         */
71
-        function espresso_minimum_php_version_error()
72
-        {
73
-            ?>
65
+	define('EE_MIN_PHP_VER_REQUIRED', '5.3.9');
66
+	if (! version_compare(PHP_VERSION, EE_MIN_PHP_VER_REQUIRED, '>=')) {
67
+		/**
68
+		 * espresso_minimum_php_version_error
69
+		 * @return void
70
+		 */
71
+		function espresso_minimum_php_version_error()
72
+		{
73
+			?>
74 74
             <div class="error">
75 75
                 <p>
76 76
                     <?php
77
-                    printf(
78
-                        esc_html__(
79
-                            'We\'re sorry, but Event Espresso requires PHP version %1$s or greater in order to operate. You are currently running version %2$s.%3$sIn order to update your version of PHP, you will need to contact your current hosting provider.%3$sFor information on stable PHP versions, please go to %4$s.',
80
-                            'event_espresso'
81
-                        ),
82
-                        EE_MIN_PHP_VER_REQUIRED,
83
-                        PHP_VERSION,
84
-                        '<br/>',
85
-                        '<a href="http://php.net/downloads.php">http://php.net/downloads.php</a>'
86
-                    );
87
-                    ?>
77
+					printf(
78
+						esc_html__(
79
+							'We\'re sorry, but Event Espresso requires PHP version %1$s or greater in order to operate. You are currently running version %2$s.%3$sIn order to update your version of PHP, you will need to contact your current hosting provider.%3$sFor information on stable PHP versions, please go to %4$s.',
80
+							'event_espresso'
81
+						),
82
+						EE_MIN_PHP_VER_REQUIRED,
83
+						PHP_VERSION,
84
+						'<br/>',
85
+						'<a href="http://php.net/downloads.php">http://php.net/downloads.php</a>'
86
+					);
87
+					?>
88 88
                 </p>
89 89
             </div>
90 90
             <?php
91
-            espresso_deactivate_plugin(plugin_basename(__FILE__));
92
-        }
91
+			espresso_deactivate_plugin(plugin_basename(__FILE__));
92
+		}
93 93
 
94
-        add_action('admin_notices', 'espresso_minimum_php_version_error', 1);
95
-    } else {
96
-        define('EVENT_ESPRESSO_MAIN_FILE', __FILE__);
97
-        /**
98
-         * espresso_version
99
-         * Returns the plugin version
100
-         *
101
-         * @return string
102
-         */
103
-        function espresso_version()
104
-        {
105
-            return apply_filters('FHEE__espresso__espresso_version', '4.9.59.rc.014');
106
-        }
94
+		add_action('admin_notices', 'espresso_minimum_php_version_error', 1);
95
+	} else {
96
+		define('EVENT_ESPRESSO_MAIN_FILE', __FILE__);
97
+		/**
98
+		 * espresso_version
99
+		 * Returns the plugin version
100
+		 *
101
+		 * @return string
102
+		 */
103
+		function espresso_version()
104
+		{
105
+			return apply_filters('FHEE__espresso__espresso_version', '4.9.59.rc.014');
106
+		}
107 107
 
108
-        /**
109
-         * espresso_plugin_activation
110
-         * adds a wp-option to indicate that EE has been activated via the WP admin plugins page
111
-         */
112
-        function espresso_plugin_activation()
113
-        {
114
-            update_option('ee_espresso_activation', true);
115
-        }
108
+		/**
109
+		 * espresso_plugin_activation
110
+		 * adds a wp-option to indicate that EE has been activated via the WP admin plugins page
111
+		 */
112
+		function espresso_plugin_activation()
113
+		{
114
+			update_option('ee_espresso_activation', true);
115
+		}
116 116
 
117
-        register_activation_hook(EVENT_ESPRESSO_MAIN_FILE, 'espresso_plugin_activation');
117
+		register_activation_hook(EVENT_ESPRESSO_MAIN_FILE, 'espresso_plugin_activation');
118 118
 
119
-        require_once __DIR__ . '/core/bootstrap_espresso.php';
120
-        bootstrap_espresso();
121
-    }
119
+		require_once __DIR__ . '/core/bootstrap_espresso.php';
120
+		bootstrap_espresso();
121
+	}
122 122
 }
123 123
 if (! function_exists('espresso_deactivate_plugin')) {
124
-    /**
125
-     *    deactivate_plugin
126
-     * usage:  espresso_deactivate_plugin( plugin_basename( __FILE__ ));
127
-     *
128
-     * @access public
129
-     * @param string $plugin_basename - the results of plugin_basename( __FILE__ ) for the plugin's main file
130
-     * @return    void
131
-     */
132
-    function espresso_deactivate_plugin($plugin_basename = '')
133
-    {
134
-        if (! function_exists('deactivate_plugins')) {
135
-            require_once ABSPATH . 'wp-admin/includes/plugin.php';
136
-        }
137
-        unset($_GET['activate'], $_REQUEST['activate']);
138
-        deactivate_plugins($plugin_basename);
139
-    }
124
+	/**
125
+	 *    deactivate_plugin
126
+	 * usage:  espresso_deactivate_plugin( plugin_basename( __FILE__ ));
127
+	 *
128
+	 * @access public
129
+	 * @param string $plugin_basename - the results of plugin_basename( __FILE__ ) for the plugin's main file
130
+	 * @return    void
131
+	 */
132
+	function espresso_deactivate_plugin($plugin_basename = '')
133
+	{
134
+		if (! function_exists('deactivate_plugins')) {
135
+			require_once ABSPATH . 'wp-admin/includes/plugin.php';
136
+		}
137
+		unset($_GET['activate'], $_REQUEST['activate']);
138
+		deactivate_plugins($plugin_basename);
139
+	}
140 140
 }
Please login to merge, or discard this patch.
core/admin/EE_Admin_Page_CPT.core.php 2 patches
Indentation   +1432 added lines, -1432 removed lines patch added patch discarded remove patch
@@ -3,7 +3,7 @@  discard block
 block discarded – undo
3 3
 use EventEspresso\core\services\request\middleware\RecommendedVersions;
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
 /**
@@ -28,470 +28,470 @@  discard block
 block discarded – undo
28 28
 {
29 29
 
30 30
 
31
-    /**
32
-     * This gets set in _setup_cpt
33
-     * It will contain the object for the custom post type.
34
-     *
35
-     * @var EE_CPT_Base
36
-     */
37
-    protected $_cpt_object;
38
-
39
-
40
-
41
-    /**
42
-     * a boolean flag to set whether the current route is a cpt route or not.
43
-     *
44
-     * @var bool
45
-     */
46
-    protected $_cpt_route = false;
47
-
48
-
49
-
50
-    /**
51
-     * This property allows cpt classes to define multiple routes as cpt routes.
52
-     * //in this array we define what the custom post type for this route is.
53
-     * array(
54
-     * 'route_name' => 'custom_post_type_slug'
55
-     * )
56
-     *
57
-     * @var array
58
-     */
59
-    protected $_cpt_routes = array();
60
-
31
+	/**
32
+	 * This gets set in _setup_cpt
33
+	 * It will contain the object for the custom post type.
34
+	 *
35
+	 * @var EE_CPT_Base
36
+	 */
37
+	protected $_cpt_object;
38
+
39
+
40
+
41
+	/**
42
+	 * a boolean flag to set whether the current route is a cpt route or not.
43
+	 *
44
+	 * @var bool
45
+	 */
46
+	protected $_cpt_route = false;
47
+
48
+
49
+
50
+	/**
51
+	 * This property allows cpt classes to define multiple routes as cpt routes.
52
+	 * //in this array we define what the custom post type for this route is.
53
+	 * array(
54
+	 * 'route_name' => 'custom_post_type_slug'
55
+	 * )
56
+	 *
57
+	 * @var array
58
+	 */
59
+	protected $_cpt_routes = array();
60
+
61 61
 
62 62
 
63
-    /**
64
-     * This simply defines what the corresponding routes WP will be redirected to after completing a post save/update.
65
-     * in this format:
66
-     * array(
67
-     * 'post_type_slug' => 'edit_route'
68
-     * )
69
-     *
70
-     * @var array
71
-     */
72
-    protected $_cpt_edit_routes = array();
73
-
74
-
75
-
76
-    /**
77
-     * If child classes set the name of their main model via the $_cpt_obj_models property, EE_Admin_Page_CPT will
78
-     * attempt to retrieve the related object model for the edit pages and assign it to _cpt_page_object. the
79
-     * _cpt_model_names property should be in the following format: array(
80
-     * 'route_defined_by_action_param' => 'Model_Name')
81
-     *
82
-     * @var array $_cpt_model_names
83
-     */
84
-    protected $_cpt_model_names = array();
85
-
86
-
87
-    /**
88
-     * @var EE_CPT_Base
89
-     */
90
-    protected $_cpt_model_obj = false;
91
-
92
-
93
-
94
-    /**
95
-     * This will hold an array of autosave containers that will be used to obtain input values and hook into the WP
96
-     * autosave so we can save our inputs on the save_post hook!  Children classes should add to this array by using
97
-     * the _register_autosave_containers() method so that we don't override any other containers already registered.
98
-     * Registration of containers should be done before load_page_dependencies() is run.
99
-     *
100
-     * @var array()
101
-     */
102
-    protected $_autosave_containers = array();
103
-    protected $_autosave_fields = array();
104
-
105
-    /**
106
-     * Array mapping from admin actions to their equivalent wp core pages for custom post types. So when a user visits
107
-     * a page for an action, it will appear as if they were visiting the wp core page for that custom post type
108
-     *
109
-     * @var array
110
-     */
111
-    protected $_pagenow_map;
112
-
113
-
114
-
115
-    /**
116
-     * This is hooked into the WordPress do_action('save_post') hook and runs after the custom post type has been
117
-     * saved.  Child classes are required to declare this method.  Typically you would use this to save any additional
118
-     * data. Keep in mind also that "save_post" runs on EVERY post update to the database. ALSO very important.  When a
119
-     * post transitions from scheduled to published, the save_post action is fired but you will NOT have any _POST data
120
-     * containing any extra info you may have from other meta saves.  So MAKE sure that you handle this accordingly.
121
-     *
122
-     * @access protected
123
-     * @abstract
124
-     * @param  string $post_id The ID of the cpt that was saved (so you can link relationally)
125
-     * @param  EE_CPT_Base $post    The post object of the cpt that was saved.
126
-     * @return void
127
-     */
128
-    abstract protected function _insert_update_cpt_item($post_id, $post);
129
-
130
-
131
-
132
-    /**
133
-     * This is hooked into the WordPress do_action('trashed_post') hook and runs after a cpt has been trashed.
134
-     *
135
-     * @abstract
136
-     * @access public
137
-     * @param  string $post_id The ID of the cpt that was trashed
138
-     * @return void
139
-     */
140
-    abstract public function trash_cpt_item($post_id);
141
-
142
-
143
-
144
-    /**
145
-     * This is hooked into the WordPress do_action('untrashed_post') hook and runs after a cpt has been untrashed
146
-     *
147
-     * @param  string $post_id theID of the cpt that was untrashed
148
-     * @return void
149
-     */
150
-    abstract public function restore_cpt_item($post_id);
151
-
152
-
153
-
154
-    /**
155
-     * This is hooked into the WordPress do_action('delete_cpt_item') hook and runs after a cpt has been fully deleted
156
-     * from the db
157
-     *
158
-     * @param  string $post_id the ID of the cpt that was deleted
159
-     * @return void
160
-     */
161
-    abstract public function delete_cpt_item($post_id);
162
-
163
-
164
-
165
-    /**
166
-     * Just utilizing the method EE_Admin exposes for doing things before page setup.
167
-     *
168
-     * @access protected
169
-     * @return void
170
-     */
171
-    protected function _before_page_setup()
172
-    {
173
-        $page = isset($this->_req_data['page']) ? $this->_req_data['page'] : $this->page_slug;
174
-        $this->_cpt_routes = array_merge(array(
175
-            'create_new' => $this->page_slug,
176
-            'edit'       => $this->page_slug,
177
-            'trash'      => $this->page_slug,
178
-        ), $this->_cpt_routes);
179
-        //let's see if the current route has a value for cpt_object_slug if it does we use that instead of the page
180
-        $this->_cpt_object = isset($this->_req_data['action']) && isset($this->_cpt_routes[$this->_req_data['action']])
181
-            ? get_post_type_object($this->_cpt_routes[$this->_req_data['action']])
182
-            : get_post_type_object($page);
183
-        //tweak pagenow for page loading.
184
-        if ( ! $this->_pagenow_map) {
185
-            $this->_pagenow_map = array(
186
-                'create_new' => 'post-new.php',
187
-                'edit'       => 'post.php',
188
-                'trash'      => 'post.php',
189
-            );
190
-        }
191
-        add_action('current_screen', array($this, 'modify_pagenow'));
192
-        //TODO the below will need to be reworked to account for the cpt routes that are NOT based off of page but action param.
193
-        //get current page from autosave
194
-        $current_page = isset($this->_req_data['ee_autosave_data']['ee-cpt-hidden-inputs']['current_page'])
195
-            ? $this->_req_data['ee_autosave_data']['ee-cpt-hidden-inputs']['current_page']
196
-            : null;
197
-        $this->_current_page = isset($this->_req_data['current_page'])
198
-            ? $this->_req_data['current_page']
199
-            : $current_page;
200
-        //autosave... make sure its only for the correct page
201
-        //if ( ! empty($this->_current_page) && $this->_current_page == $this->page_slug) {
202
-            //setup autosave ajax hook
203
-            //add_action('wp_ajax_ee-autosave', array( $this, 'do_extra_autosave_stuff' ), 10 ); //TODO reactivate when 4.2 autosave is implemented
204
-        //}
205
-    }
206
-
207
-
208
-
209
-    /**
210
-     * Simply ensure that we simulate the correct post route for cpt screens
211
-     *
212
-     * @param WP_Screen $current_screen
213
-     * @return void
214
-     */
215
-    public function modify_pagenow($current_screen)
216
-    {
217
-        global $pagenow, $hook_suffix;
218
-        //possibly reset pagenow.
219
-        if ( ! empty($this->_req_data['page'])
220
-             && $this->_req_data['page'] == $this->page_slug
221
-             && ! empty($this->_req_data['action'])
222
-             && isset($this->_pagenow_map[$this->_req_data['action']])
223
-        ) {
224
-            $pagenow = $this->_pagenow_map[$this->_req_data['action']];
225
-            $hook_suffix = $pagenow;
226
-        }
227
-    }
228
-
229
-
230
-
231
-    /**
232
-     * This method is used to register additional autosave containers to the _autosave_containers property.
233
-     *
234
-     * @todo We should automate this at some point by creating a wrapper for add_post_metabox and in our wrapper we
235
-     *       automatically register the id for the post metabox as a container.
236
-     * @param  array $ids an array of ids for containers that hold form inputs we want autosave to pickup.  Typically
237
-     *                    you would send along the id of a metabox container.
238
-     * @return void
239
-     */
240
-    protected function _register_autosave_containers($ids)
241
-    {
242
-        $this->_autosave_containers = array_merge($this->_autosave_fields, (array)$ids);
243
-    }
244
-
245
-
246
-
247
-    /**
248
-     * Something nifty.  We're going to loop through all the registered metaboxes and if the CALLBACK is an instance of
249
-     * EE_Admin_Page OR EE_Admin_Hooks, then we'll add the id to our _autosave_containers array.
250
-     */
251
-    protected function _set_autosave_containers()
252
-    {
253
-        global $wp_meta_boxes;
254
-        $containers = array();
255
-        if (empty($wp_meta_boxes)) {
256
-            return;
257
-        }
258
-        $current_metaboxes = isset($wp_meta_boxes[$this->page_slug]) ? $wp_meta_boxes[$this->page_slug] : array();
259
-        foreach ($current_metaboxes as $box_context) {
260
-            foreach ($box_context as $box_details) {
261
-                foreach ($box_details as $box) {
262
-                    if (
263
-                        is_array($box['callback'])
264
-                        && (
265
-                            $box['callback'][0] instanceof EE_Admin_Page
266
-                            || $box['callback'][0] instanceof EE_Admin_Hooks
267
-                        )
268
-                    ) {
269
-                        $containers[] = $box['id'];
270
-                    }
271
-                }
272
-            }
273
-        }
274
-        $this->_autosave_containers = array_merge($this->_autosave_containers, $containers);
275
-        //add hidden inputs container
276
-        $this->_autosave_containers[] = 'ee-cpt-hidden-inputs';
277
-    }
278
-
279
-
280
-
281
-    protected function _load_autosave_scripts_styles()
282
-    {
283
-        /*wp_register_script('cpt-autosave', EE_ADMIN_URL . 'assets/ee-cpt-autosave.js', array('ee-serialize-full-array', 'event_editor_js'), EVENT_ESPRESSO_VERSION, TRUE );
63
+	/**
64
+	 * This simply defines what the corresponding routes WP will be redirected to after completing a post save/update.
65
+	 * in this format:
66
+	 * array(
67
+	 * 'post_type_slug' => 'edit_route'
68
+	 * )
69
+	 *
70
+	 * @var array
71
+	 */
72
+	protected $_cpt_edit_routes = array();
73
+
74
+
75
+
76
+	/**
77
+	 * If child classes set the name of their main model via the $_cpt_obj_models property, EE_Admin_Page_CPT will
78
+	 * attempt to retrieve the related object model for the edit pages and assign it to _cpt_page_object. the
79
+	 * _cpt_model_names property should be in the following format: array(
80
+	 * 'route_defined_by_action_param' => 'Model_Name')
81
+	 *
82
+	 * @var array $_cpt_model_names
83
+	 */
84
+	protected $_cpt_model_names = array();
85
+
86
+
87
+	/**
88
+	 * @var EE_CPT_Base
89
+	 */
90
+	protected $_cpt_model_obj = false;
91
+
92
+
93
+
94
+	/**
95
+	 * This will hold an array of autosave containers that will be used to obtain input values and hook into the WP
96
+	 * autosave so we can save our inputs on the save_post hook!  Children classes should add to this array by using
97
+	 * the _register_autosave_containers() method so that we don't override any other containers already registered.
98
+	 * Registration of containers should be done before load_page_dependencies() is run.
99
+	 *
100
+	 * @var array()
101
+	 */
102
+	protected $_autosave_containers = array();
103
+	protected $_autosave_fields = array();
104
+
105
+	/**
106
+	 * Array mapping from admin actions to their equivalent wp core pages for custom post types. So when a user visits
107
+	 * a page for an action, it will appear as if they were visiting the wp core page for that custom post type
108
+	 *
109
+	 * @var array
110
+	 */
111
+	protected $_pagenow_map;
112
+
113
+
114
+
115
+	/**
116
+	 * This is hooked into the WordPress do_action('save_post') hook and runs after the custom post type has been
117
+	 * saved.  Child classes are required to declare this method.  Typically you would use this to save any additional
118
+	 * data. Keep in mind also that "save_post" runs on EVERY post update to the database. ALSO very important.  When a
119
+	 * post transitions from scheduled to published, the save_post action is fired but you will NOT have any _POST data
120
+	 * containing any extra info you may have from other meta saves.  So MAKE sure that you handle this accordingly.
121
+	 *
122
+	 * @access protected
123
+	 * @abstract
124
+	 * @param  string $post_id The ID of the cpt that was saved (so you can link relationally)
125
+	 * @param  EE_CPT_Base $post    The post object of the cpt that was saved.
126
+	 * @return void
127
+	 */
128
+	abstract protected function _insert_update_cpt_item($post_id, $post);
129
+
130
+
131
+
132
+	/**
133
+	 * This is hooked into the WordPress do_action('trashed_post') hook and runs after a cpt has been trashed.
134
+	 *
135
+	 * @abstract
136
+	 * @access public
137
+	 * @param  string $post_id The ID of the cpt that was trashed
138
+	 * @return void
139
+	 */
140
+	abstract public function trash_cpt_item($post_id);
141
+
142
+
143
+
144
+	/**
145
+	 * This is hooked into the WordPress do_action('untrashed_post') hook and runs after a cpt has been untrashed
146
+	 *
147
+	 * @param  string $post_id theID of the cpt that was untrashed
148
+	 * @return void
149
+	 */
150
+	abstract public function restore_cpt_item($post_id);
151
+
152
+
153
+
154
+	/**
155
+	 * This is hooked into the WordPress do_action('delete_cpt_item') hook and runs after a cpt has been fully deleted
156
+	 * from the db
157
+	 *
158
+	 * @param  string $post_id the ID of the cpt that was deleted
159
+	 * @return void
160
+	 */
161
+	abstract public function delete_cpt_item($post_id);
162
+
163
+
164
+
165
+	/**
166
+	 * Just utilizing the method EE_Admin exposes for doing things before page setup.
167
+	 *
168
+	 * @access protected
169
+	 * @return void
170
+	 */
171
+	protected function _before_page_setup()
172
+	{
173
+		$page = isset($this->_req_data['page']) ? $this->_req_data['page'] : $this->page_slug;
174
+		$this->_cpt_routes = array_merge(array(
175
+			'create_new' => $this->page_slug,
176
+			'edit'       => $this->page_slug,
177
+			'trash'      => $this->page_slug,
178
+		), $this->_cpt_routes);
179
+		//let's see if the current route has a value for cpt_object_slug if it does we use that instead of the page
180
+		$this->_cpt_object = isset($this->_req_data['action']) && isset($this->_cpt_routes[$this->_req_data['action']])
181
+			? get_post_type_object($this->_cpt_routes[$this->_req_data['action']])
182
+			: get_post_type_object($page);
183
+		//tweak pagenow for page loading.
184
+		if ( ! $this->_pagenow_map) {
185
+			$this->_pagenow_map = array(
186
+				'create_new' => 'post-new.php',
187
+				'edit'       => 'post.php',
188
+				'trash'      => 'post.php',
189
+			);
190
+		}
191
+		add_action('current_screen', array($this, 'modify_pagenow'));
192
+		//TODO the below will need to be reworked to account for the cpt routes that are NOT based off of page but action param.
193
+		//get current page from autosave
194
+		$current_page = isset($this->_req_data['ee_autosave_data']['ee-cpt-hidden-inputs']['current_page'])
195
+			? $this->_req_data['ee_autosave_data']['ee-cpt-hidden-inputs']['current_page']
196
+			: null;
197
+		$this->_current_page = isset($this->_req_data['current_page'])
198
+			? $this->_req_data['current_page']
199
+			: $current_page;
200
+		//autosave... make sure its only for the correct page
201
+		//if ( ! empty($this->_current_page) && $this->_current_page == $this->page_slug) {
202
+			//setup autosave ajax hook
203
+			//add_action('wp_ajax_ee-autosave', array( $this, 'do_extra_autosave_stuff' ), 10 ); //TODO reactivate when 4.2 autosave is implemented
204
+		//}
205
+	}
206
+
207
+
208
+
209
+	/**
210
+	 * Simply ensure that we simulate the correct post route for cpt screens
211
+	 *
212
+	 * @param WP_Screen $current_screen
213
+	 * @return void
214
+	 */
215
+	public function modify_pagenow($current_screen)
216
+	{
217
+		global $pagenow, $hook_suffix;
218
+		//possibly reset pagenow.
219
+		if ( ! empty($this->_req_data['page'])
220
+			 && $this->_req_data['page'] == $this->page_slug
221
+			 && ! empty($this->_req_data['action'])
222
+			 && isset($this->_pagenow_map[$this->_req_data['action']])
223
+		) {
224
+			$pagenow = $this->_pagenow_map[$this->_req_data['action']];
225
+			$hook_suffix = $pagenow;
226
+		}
227
+	}
228
+
229
+
230
+
231
+	/**
232
+	 * This method is used to register additional autosave containers to the _autosave_containers property.
233
+	 *
234
+	 * @todo We should automate this at some point by creating a wrapper for add_post_metabox and in our wrapper we
235
+	 *       automatically register the id for the post metabox as a container.
236
+	 * @param  array $ids an array of ids for containers that hold form inputs we want autosave to pickup.  Typically
237
+	 *                    you would send along the id of a metabox container.
238
+	 * @return void
239
+	 */
240
+	protected function _register_autosave_containers($ids)
241
+	{
242
+		$this->_autosave_containers = array_merge($this->_autosave_fields, (array)$ids);
243
+	}
244
+
245
+
246
+
247
+	/**
248
+	 * Something nifty.  We're going to loop through all the registered metaboxes and if the CALLBACK is an instance of
249
+	 * EE_Admin_Page OR EE_Admin_Hooks, then we'll add the id to our _autosave_containers array.
250
+	 */
251
+	protected function _set_autosave_containers()
252
+	{
253
+		global $wp_meta_boxes;
254
+		$containers = array();
255
+		if (empty($wp_meta_boxes)) {
256
+			return;
257
+		}
258
+		$current_metaboxes = isset($wp_meta_boxes[$this->page_slug]) ? $wp_meta_boxes[$this->page_slug] : array();
259
+		foreach ($current_metaboxes as $box_context) {
260
+			foreach ($box_context as $box_details) {
261
+				foreach ($box_details as $box) {
262
+					if (
263
+						is_array($box['callback'])
264
+						&& (
265
+							$box['callback'][0] instanceof EE_Admin_Page
266
+							|| $box['callback'][0] instanceof EE_Admin_Hooks
267
+						)
268
+					) {
269
+						$containers[] = $box['id'];
270
+					}
271
+				}
272
+			}
273
+		}
274
+		$this->_autosave_containers = array_merge($this->_autosave_containers, $containers);
275
+		//add hidden inputs container
276
+		$this->_autosave_containers[] = 'ee-cpt-hidden-inputs';
277
+	}
278
+
279
+
280
+
281
+	protected function _load_autosave_scripts_styles()
282
+	{
283
+		/*wp_register_script('cpt-autosave', EE_ADMIN_URL . 'assets/ee-cpt-autosave.js', array('ee-serialize-full-array', 'event_editor_js'), EVENT_ESPRESSO_VERSION, TRUE );
284 284
         wp_enqueue_script('cpt-autosave');/**/ //todo re-enable when we start doing autosave again in 4.2
285 285
 
286
-        //filter _autosave_containers
287
-        $containers = apply_filters('FHEE__EE_Admin_Page_CPT___load_autosave_scripts_styles__containers',
288
-            $this->_autosave_containers, $this);
289
-        $containers = apply_filters('FHEE__EE_Admin_Page_CPT__' . get_class($this) . '___load_autosave_scripts_styles__containers',
290
-            $containers, $this);
291
-
292
-        wp_localize_script('event_editor_js', 'EE_AUTOSAVE_IDS',
293
-            $containers); //todo once we enable autosaves, this needs to be switched to localize with "cpt-autosave"
294
-
295
-        $unsaved_data_msg = array(
296
-            'eventmsg'     => sprintf(__("The changes you made to this %s will be lost if you navigate away from this page.",
297
-                'event_espresso'), $this->_cpt_object->labels->singular_name),
298
-            'inputChanged' => 0,
299
-        );
300
-        wp_localize_script('event_editor_js', 'UNSAVED_DATA_MSG', $unsaved_data_msg);
301
-    }
302
-
303
-
304
-
305
-    public function load_page_dependencies()
306
-    {
307
-        try {
308
-            $this->_load_page_dependencies();
309
-        } catch (EE_Error $e) {
310
-            $e->get_error();
311
-        }
312
-    }
313
-
314
-
315
-
316
-    /**
317
-     * overloading the EE_Admin_Page parent load_page_dependencies so we can get the cpt stuff added in appropriately
318
-     *
319
-     * @access protected
320
-     * @return void
321
-     */
322
-    protected function _load_page_dependencies()
323
-    {
324
-        //we only add stuff if this is a cpt_route!
325
-        if ( ! $this->_cpt_route) {
326
-            parent::_load_page_dependencies();
327
-            return;
328
-        }
329
-        // now let's do some automatic filters into the wp_system
330
-        // and we'll check to make sure the CHILD class
331
-        // automatically has the required methods in place.
332
-        // the following filters are for setting all the redirects
333
-        // on DEFAULT WP custom post type actions
334
-        // let's add a hidden input to the post-edit form
335
-        // so we know when we have to trigger our custom redirects!
336
-        // Otherwise the redirects will happen on ALL post saves which wouldn't be good of course!
337
-        add_action('edit_form_after_title', array($this, 'cpt_post_form_hidden_input'));
338
-        // inject our Admin page nav tabs...
339
-        // let's make sure the nav tabs are set if they aren't already
340
-        // if ( empty( $this->_nav_tabs ) ) $this->_set_nav_tabs();
341
-        add_action('post_edit_form_tag', array($this, 'inject_nav_tabs'));
342
-        // modify the post_updated messages array
343
-        add_action('post_updated_messages', array($this, 'post_update_messages'), 10);
344
-        // add shortlink button to cpt edit screens.  We can do this as a universal thing BECAUSE,
345
-        // cpts use the same format for shortlinks as posts!
346
-        add_filter('pre_get_shortlink', array($this, 'add_shortlink_button_to_editor'), 10, 4);
347
-        // This basically allows us to change the title of the "publish" metabox area
348
-        // on CPT pages by setting a 'publishbox' value in the $_labels property array in the child class.
349
-        if ( ! empty($this->_labels['publishbox'])) {
350
-            $box_label = is_array($this->_labels['publishbox'])
351
-                         && isset($this->_labels['publishbox'][$this->_req_action])
352
-                    ? $this->_labels['publishbox'][$this->_req_action]
353
-                    : $this->_labels['publishbox'];
354
-            add_meta_box(
355
-                'submitdiv',
356
-                $box_label,
357
-                'post_submit_meta_box',
358
-                $this->_cpt_routes[$this->_req_action],
359
-                'side',
360
-                'core'
361
-            );
362
-        }
363
-        //let's add page_templates metabox if this cpt added support for it.
364
-        if ($this->_supports_page_templates($this->_cpt_object->name)) {
365
-            add_meta_box(
366
-                'page_templates',
367
-                __('Page Template', 'event_espresso'),
368
-                array($this, 'page_template_meta_box'),
369
-                $this->_cpt_routes[$this->_req_action],
370
-                'side',
371
-                'default'
372
-            );
373
-        }
374
-        //this is a filter that allows the addition of extra html after the permalink field on the wp post edit-form
375
-        if (method_exists($this, 'extra_permalink_field_buttons')) {
376
-            add_filter('get_sample_permalink_html', array($this, 'extra_permalink_field_buttons'), 10, 4);
377
-        }
378
-        //add preview button
379
-        add_filter('get_sample_permalink_html', array($this, 'preview_button_html'), 5, 4);
380
-        //insert our own post_stati dropdown
381
-        add_action('post_submitbox_misc_actions', array($this, 'custom_post_stati_dropdown'), 10);
382
-        //This allows adding additional information to the publish post submitbox on the wp post edit form
383
-        if (method_exists($this, 'extra_misc_actions_publish_box')) {
384
-            add_action('post_submitbox_misc_actions', array($this, 'extra_misc_actions_publish_box'), 10);
385
-        }
386
-        // This allows for adding additional stuff after the title field on the wp post edit form.
387
-        // This is also before the wp_editor for post description field.
388
-        if (method_exists($this, 'edit_form_after_title')) {
389
-            add_action('edit_form_after_title', array($this, 'edit_form_after_title'), 10);
390
-        }
391
-        /**
392
-         * Filtering WP's esc_url to capture urls pointing to core wp routes so they point to our route.
393
-         */
394
-        add_filter('clean_url', array($this, 'switch_core_wp_urls_with_ours'), 10, 3);
395
-        parent::_load_page_dependencies();
396
-        // notice we are ALSO going to load the pagenow hook set for this route
397
-        // (see _before_page_setup for the reset of the pagenow global ).
398
-        // This is for any plugins that are doing things properly
399
-        // and hooking into the load page hook for core wp cpt routes.
400
-        global $pagenow;
401
-        do_action('load-' . $pagenow);
402
-        $this->modify_current_screen();
403
-        add_action('admin_enqueue_scripts', array($this, 'setup_autosave_hooks'), 30);
404
-        //we route REALLY early.
405
-        try {
406
-            $this->_route_admin_request();
407
-        } catch (EE_Error $e) {
408
-            $e->get_error();
409
-        }
410
-    }
411
-
412
-
413
-
414
-    /**
415
-     * Since we don't want users going to default core wp routes, this will check any wp urls run through the
416
-     * esc_url() method and if we see a url matching a pattern for our routes, we'll modify it to point to OUR
417
-     * route instead.
418
-     *
419
-     * @param string $good_protocol_url The escaped url.
420
-     * @param string $original_url      The original url.
421
-     * @param string $_context          The context sent to the esc_url method.
422
-     * @return string possibly a new url for our route.
423
-     */
424
-    public function switch_core_wp_urls_with_ours($good_protocol_url, $original_url, $_context)
425
-    {
426
-        $routes_to_match = array(
427
-            0 => array(
428
-                'edit.php?post_type=espresso_attendees',
429
-                'admin.php?page=espresso_registrations&action=contact_list',
430
-            ),
431
-            1 => array(
432
-                'edit.php?post_type=' . $this->_cpt_object->name,
433
-                'admin.php?page=' . $this->_cpt_object->name,
434
-            ),
435
-        );
436
-        foreach ($routes_to_match as $route_matches) {
437
-            if (strpos($good_protocol_url, $route_matches[0]) !== false) {
438
-                return str_replace($route_matches[0], $route_matches[1], $good_protocol_url);
439
-            }
440
-        }
441
-        return $good_protocol_url;
442
-    }
443
-
444
-
445
-
446
-    /**
447
-     * Determine whether the current cpt supports page templates or not.
448
-     *
449
-     * @since %VER%
450
-     * @param string $cpt_name The cpt slug we're checking on.
451
-     * @return bool True supported, false not.
452
-     */
453
-    private function _supports_page_templates($cpt_name)
454
-    {
455
-
456
-        $cpt_args = EE_Register_CPTs::get_CPTs();
457
-        $cpt_args = isset($cpt_args[$cpt_name]) ? $cpt_args[$cpt_name]['args'] : array();
458
-        $cpt_has_support = ! empty($cpt_args['page_templates']);
459
-
460
-        //if the installed version of WP is > 4.7 we do some additional checks.
461
-        if (RecommendedVersions::compareWordPressVersion('4.7','>=')) {
462
-            $post_templates = wp_get_theme()->get_post_templates();
463
-            //if there are $post_templates for this cpt, then we return false for this method because
464
-            //that means we aren't going to load our page template manager and leave that up to the native
465
-            //cpt template manager.
466
-            $cpt_has_support = ! isset($post_templates[$cpt_name]) ? $cpt_has_support : false;
467
-        }
468
-
469
-        return $cpt_has_support;
470
-    }
471
-
472
-
473
-    /**
474
-     * Callback for the page_templates metabox selector.
475
-     *
476
-     * @since %VER%
477
-     * @return void
478
-     */
479
-    public function page_template_meta_box()
480
-    {
481
-        global $post;
482
-        $template = '';
483
-
484
-        if (RecommendedVersions::compareWordPressVersion('4.7','>=')) {
485
-            $page_template_count = count(get_page_templates());
486
-        } else {
487
-            $page_template_count = count(get_page_templates($post));
488
-        };
489
-
490
-        if ($page_template_count) {
491
-            $page_template = get_post_meta($post->ID, '_wp_page_template', true);
492
-            $template      = ! empty($page_template) ? $page_template : '';
493
-        }
494
-        ?>
286
+		//filter _autosave_containers
287
+		$containers = apply_filters('FHEE__EE_Admin_Page_CPT___load_autosave_scripts_styles__containers',
288
+			$this->_autosave_containers, $this);
289
+		$containers = apply_filters('FHEE__EE_Admin_Page_CPT__' . get_class($this) . '___load_autosave_scripts_styles__containers',
290
+			$containers, $this);
291
+
292
+		wp_localize_script('event_editor_js', 'EE_AUTOSAVE_IDS',
293
+			$containers); //todo once we enable autosaves, this needs to be switched to localize with "cpt-autosave"
294
+
295
+		$unsaved_data_msg = array(
296
+			'eventmsg'     => sprintf(__("The changes you made to this %s will be lost if you navigate away from this page.",
297
+				'event_espresso'), $this->_cpt_object->labels->singular_name),
298
+			'inputChanged' => 0,
299
+		);
300
+		wp_localize_script('event_editor_js', 'UNSAVED_DATA_MSG', $unsaved_data_msg);
301
+	}
302
+
303
+
304
+
305
+	public function load_page_dependencies()
306
+	{
307
+		try {
308
+			$this->_load_page_dependencies();
309
+		} catch (EE_Error $e) {
310
+			$e->get_error();
311
+		}
312
+	}
313
+
314
+
315
+
316
+	/**
317
+	 * overloading the EE_Admin_Page parent load_page_dependencies so we can get the cpt stuff added in appropriately
318
+	 *
319
+	 * @access protected
320
+	 * @return void
321
+	 */
322
+	protected function _load_page_dependencies()
323
+	{
324
+		//we only add stuff if this is a cpt_route!
325
+		if ( ! $this->_cpt_route) {
326
+			parent::_load_page_dependencies();
327
+			return;
328
+		}
329
+		// now let's do some automatic filters into the wp_system
330
+		// and we'll check to make sure the CHILD class
331
+		// automatically has the required methods in place.
332
+		// the following filters are for setting all the redirects
333
+		// on DEFAULT WP custom post type actions
334
+		// let's add a hidden input to the post-edit form
335
+		// so we know when we have to trigger our custom redirects!
336
+		// Otherwise the redirects will happen on ALL post saves which wouldn't be good of course!
337
+		add_action('edit_form_after_title', array($this, 'cpt_post_form_hidden_input'));
338
+		// inject our Admin page nav tabs...
339
+		// let's make sure the nav tabs are set if they aren't already
340
+		// if ( empty( $this->_nav_tabs ) ) $this->_set_nav_tabs();
341
+		add_action('post_edit_form_tag', array($this, 'inject_nav_tabs'));
342
+		// modify the post_updated messages array
343
+		add_action('post_updated_messages', array($this, 'post_update_messages'), 10);
344
+		// add shortlink button to cpt edit screens.  We can do this as a universal thing BECAUSE,
345
+		// cpts use the same format for shortlinks as posts!
346
+		add_filter('pre_get_shortlink', array($this, 'add_shortlink_button_to_editor'), 10, 4);
347
+		// This basically allows us to change the title of the "publish" metabox area
348
+		// on CPT pages by setting a 'publishbox' value in the $_labels property array in the child class.
349
+		if ( ! empty($this->_labels['publishbox'])) {
350
+			$box_label = is_array($this->_labels['publishbox'])
351
+						 && isset($this->_labels['publishbox'][$this->_req_action])
352
+					? $this->_labels['publishbox'][$this->_req_action]
353
+					: $this->_labels['publishbox'];
354
+			add_meta_box(
355
+				'submitdiv',
356
+				$box_label,
357
+				'post_submit_meta_box',
358
+				$this->_cpt_routes[$this->_req_action],
359
+				'side',
360
+				'core'
361
+			);
362
+		}
363
+		//let's add page_templates metabox if this cpt added support for it.
364
+		if ($this->_supports_page_templates($this->_cpt_object->name)) {
365
+			add_meta_box(
366
+				'page_templates',
367
+				__('Page Template', 'event_espresso'),
368
+				array($this, 'page_template_meta_box'),
369
+				$this->_cpt_routes[$this->_req_action],
370
+				'side',
371
+				'default'
372
+			);
373
+		}
374
+		//this is a filter that allows the addition of extra html after the permalink field on the wp post edit-form
375
+		if (method_exists($this, 'extra_permalink_field_buttons')) {
376
+			add_filter('get_sample_permalink_html', array($this, 'extra_permalink_field_buttons'), 10, 4);
377
+		}
378
+		//add preview button
379
+		add_filter('get_sample_permalink_html', array($this, 'preview_button_html'), 5, 4);
380
+		//insert our own post_stati dropdown
381
+		add_action('post_submitbox_misc_actions', array($this, 'custom_post_stati_dropdown'), 10);
382
+		//This allows adding additional information to the publish post submitbox on the wp post edit form
383
+		if (method_exists($this, 'extra_misc_actions_publish_box')) {
384
+			add_action('post_submitbox_misc_actions', array($this, 'extra_misc_actions_publish_box'), 10);
385
+		}
386
+		// This allows for adding additional stuff after the title field on the wp post edit form.
387
+		// This is also before the wp_editor for post description field.
388
+		if (method_exists($this, 'edit_form_after_title')) {
389
+			add_action('edit_form_after_title', array($this, 'edit_form_after_title'), 10);
390
+		}
391
+		/**
392
+		 * Filtering WP's esc_url to capture urls pointing to core wp routes so they point to our route.
393
+		 */
394
+		add_filter('clean_url', array($this, 'switch_core_wp_urls_with_ours'), 10, 3);
395
+		parent::_load_page_dependencies();
396
+		// notice we are ALSO going to load the pagenow hook set for this route
397
+		// (see _before_page_setup for the reset of the pagenow global ).
398
+		// This is for any plugins that are doing things properly
399
+		// and hooking into the load page hook for core wp cpt routes.
400
+		global $pagenow;
401
+		do_action('load-' . $pagenow);
402
+		$this->modify_current_screen();
403
+		add_action('admin_enqueue_scripts', array($this, 'setup_autosave_hooks'), 30);
404
+		//we route REALLY early.
405
+		try {
406
+			$this->_route_admin_request();
407
+		} catch (EE_Error $e) {
408
+			$e->get_error();
409
+		}
410
+	}
411
+
412
+
413
+
414
+	/**
415
+	 * Since we don't want users going to default core wp routes, this will check any wp urls run through the
416
+	 * esc_url() method and if we see a url matching a pattern for our routes, we'll modify it to point to OUR
417
+	 * route instead.
418
+	 *
419
+	 * @param string $good_protocol_url The escaped url.
420
+	 * @param string $original_url      The original url.
421
+	 * @param string $_context          The context sent to the esc_url method.
422
+	 * @return string possibly a new url for our route.
423
+	 */
424
+	public function switch_core_wp_urls_with_ours($good_protocol_url, $original_url, $_context)
425
+	{
426
+		$routes_to_match = array(
427
+			0 => array(
428
+				'edit.php?post_type=espresso_attendees',
429
+				'admin.php?page=espresso_registrations&action=contact_list',
430
+			),
431
+			1 => array(
432
+				'edit.php?post_type=' . $this->_cpt_object->name,
433
+				'admin.php?page=' . $this->_cpt_object->name,
434
+			),
435
+		);
436
+		foreach ($routes_to_match as $route_matches) {
437
+			if (strpos($good_protocol_url, $route_matches[0]) !== false) {
438
+				return str_replace($route_matches[0], $route_matches[1], $good_protocol_url);
439
+			}
440
+		}
441
+		return $good_protocol_url;
442
+	}
443
+
444
+
445
+
446
+	/**
447
+	 * Determine whether the current cpt supports page templates or not.
448
+	 *
449
+	 * @since %VER%
450
+	 * @param string $cpt_name The cpt slug we're checking on.
451
+	 * @return bool True supported, false not.
452
+	 */
453
+	private function _supports_page_templates($cpt_name)
454
+	{
455
+
456
+		$cpt_args = EE_Register_CPTs::get_CPTs();
457
+		$cpt_args = isset($cpt_args[$cpt_name]) ? $cpt_args[$cpt_name]['args'] : array();
458
+		$cpt_has_support = ! empty($cpt_args['page_templates']);
459
+
460
+		//if the installed version of WP is > 4.7 we do some additional checks.
461
+		if (RecommendedVersions::compareWordPressVersion('4.7','>=')) {
462
+			$post_templates = wp_get_theme()->get_post_templates();
463
+			//if there are $post_templates for this cpt, then we return false for this method because
464
+			//that means we aren't going to load our page template manager and leave that up to the native
465
+			//cpt template manager.
466
+			$cpt_has_support = ! isset($post_templates[$cpt_name]) ? $cpt_has_support : false;
467
+		}
468
+
469
+		return $cpt_has_support;
470
+	}
471
+
472
+
473
+	/**
474
+	 * Callback for the page_templates metabox selector.
475
+	 *
476
+	 * @since %VER%
477
+	 * @return void
478
+	 */
479
+	public function page_template_meta_box()
480
+	{
481
+		global $post;
482
+		$template = '';
483
+
484
+		if (RecommendedVersions::compareWordPressVersion('4.7','>=')) {
485
+			$page_template_count = count(get_page_templates());
486
+		} else {
487
+			$page_template_count = count(get_page_templates($post));
488
+		};
489
+
490
+		if ($page_template_count) {
491
+			$page_template = get_post_meta($post->ID, '_wp_page_template', true);
492
+			$template      = ! empty($page_template) ? $page_template : '';
493
+		}
494
+		?>
495 495
         <p><strong><?php _e('Template') ?></strong></p>
496 496
         <label class="screen-reader-text" for="page_template"><?php _e('Page Template') ?></label><select
497 497
             name="page_template" id="page_template">
@@ -499,450 +499,450 @@  discard block
 block discarded – undo
499 499
         <?php page_template_dropdown($template); ?>
500 500
     </select>
501 501
         <?php
502
-    }
503
-
504
-
505
-
506
-    /**
507
-     * if this post is a draft or scheduled post then we provide a preview button for user to click
508
-     * Method is called from parent and is hooked into the wp 'get_sample_permalink_html' filter.
509
-     *
510
-     * @param  string $return    the current html
511
-     * @param  int    $id        the post id for the page
512
-     * @param  string $new_title What the title is
513
-     * @param  string $new_slug  what the slug is
514
-     * @return string            The new html string for the permalink area
515
-     */
516
-    public function preview_button_html($return, $id, $new_title, $new_slug)
517
-    {
518
-        $post = get_post($id);
519
-        if ('publish' !== get_post_status($post)) {
520
-            //include shims for the `get_preview_post_link` function
521
-            require_once( EE_CORE . 'wordpress-shims.php' );
522
-            $return .= '<span_id="view-post-btn"><a target="_blank" href="'
523
-                       . get_preview_post_link($id)
524
-                       . '" class="button button-small">'
525
-                       . __('Preview', 'event_espresso')
526
-                       . '</a></span>'
527
-                       . "\n";
528
-        }
529
-        return $return;
530
-    }
531
-
532
-
533
-
534
-    /**
535
-     * add our custom post stati dropdown on the wp post page for this cpt
536
-     *
537
-     * @return void
538
-     */
539
-    public function custom_post_stati_dropdown()
540
-    {
541
-
542
-        $statuses         = $this->_cpt_model_obj->get_custom_post_statuses();
543
-        $cur_status_label = array_key_exists($this->_cpt_model_obj->status(), $statuses)
544
-            ? $statuses[$this->_cpt_model_obj->status()]
545
-            : '';
546
-        $template_args    = array(
547
-            'cur_status'            => $this->_cpt_model_obj->status(),
548
-            'statuses'              => $statuses,
549
-            'cur_status_label'      => $cur_status_label,
550
-            'localized_status_save' => sprintf(__('Save %s', 'event_espresso'), $cur_status_label),
551
-        );
552
-        //we'll add a trash post status (WP doesn't add one for some reason)
553
-        if ($this->_cpt_model_obj->status() === 'trash') {
554
-            $template_args['cur_status_label'] = __('Trashed', 'event_espresso');
555
-            $statuses['trash']                 = __('Trashed', 'event_espresso');
556
-            $template_args['statuses']         = $statuses;
557
-        }
558
-
559
-        $template = EE_ADMIN_TEMPLATE . 'status_dropdown.template.php';
560
-        EEH_Template::display_template($template, $template_args);
561
-    }
562
-
563
-
564
-
565
-    public function setup_autosave_hooks()
566
-    {
567
-        $this->_set_autosave_containers();
568
-        $this->_load_autosave_scripts_styles();
569
-    }
570
-
571
-
572
-
573
-    /**
574
-     * This is run on all WordPress autosaves AFTER the autosave is complete and sends along a $_POST object (available
575
-     * in $this->_req_data) containing: post_ID of the saved post autosavenonce for the saved post We'll do the check
576
-     * for the nonce in here, but then this method looks for two things:
577
-     * 1. Execute a method (if exists) matching 'ee_autosave_' and appended with the given route. OR
578
-     * 2. do_actions() for global or class specific actions that have been registered (for plugins/addons not in an
579
-     * EE_Admin_Page class. PLEASE NOTE: Data will be returned using the _return_json() object and so the
580
-     * $_template_args property should be used to hold the $data array.  We're expecting the following things set in
581
-     * template args.
582
-     *    1. $template_args['error'] = IF there is an error you can add the message in here.
583
-     *    2. $template_args['data']['items'] = an array of items that are setup in key index pairs of 'where_values_go'
584
-     *    => 'values_to_add'.  In other words, for the datetime metabox we'll have something like
585
-     *    $this->_template_args['data']['items'] = array(
586
-     *        'event-datetime-ids' => '1,2,3';
587
-     *    );
588
-     *    Keep in mind the following things:
589
-     *    - "where" index is for the input with the id as that string.
590
-     *    - "what" index is what will be used for the value of that input.
591
-     *
592
-     * @return void
593
-     */
594
-    public function do_extra_autosave_stuff()
595
-    {
596
-        //next let's check for the autosave nonce (we'll use _verify_nonce )
597
-        $nonce = isset($this->_req_data['autosavenonce'])
598
-                ? $this->_req_data['autosavenonce']
599
-                : null;
600
-        $this->_verify_nonce($nonce, 'autosave');
601
-        //make sure we define doing autosave (cause WP isn't triggering this we want to make sure we define it)
602
-        if ( ! defined('DOING_AUTOSAVE')) {
603
-            define('DOING_AUTOSAVE', true);
604
-        }
605
-        //if we made it here then the nonce checked out.  Let's run our methods and actions
606
-        $autosave = "_ee_autosave_{$this->_current_view}";
607
-        if (method_exists($this, $autosave)) {
608
-            $this->$autosave();
609
-        } else {
610
-            $this->_template_args['success'] = true;
611
-        }
612
-        do_action('AHEE__EE_Admin_Page_CPT__do_extra_autosave_stuff__global_after', $this);
613
-        do_action('AHEE__EE_Admin_Page_CPT__do_extra_autosave_stuff__after_' . get_class($this), $this);
614
-        //now let's return json
615
-        $this->_return_json();
616
-    }
617
-
618
-
619
-
620
-    /**
621
-     * This takes care of setting up default routes and pages that utilize the core WP admin pages.
622
-     * Child classes can override the defaults (in cases for adding metaboxes etc.)
623
-     * but take care that you include the defaults here otherwise your core WP admin pages for the cpt won't work!
624
-     *
625
-     * @access protected
626
-     * @throws EE_Error
627
-     * @return void
628
-     */
629
-    protected function _extend_page_config_for_cpt()
630
-    {
631
-        //before doing anything we need to make sure this runs ONLY when the loaded page matches the set page_slug
632
-        if (isset($this->_req_data['page']) && $this->_req_data['page'] !== $this->page_slug) {
633
-            return;
634
-        }
635
-        //set page routes and page config but ONLY if we're not viewing a custom setup cpt route as defined in _cpt_routes
636
-        if ( ! empty($this->_cpt_object)) {
637
-            $this->_page_routes = array_merge(array(
638
-                'create_new' => '_create_new_cpt_item',
639
-                'edit'       => '_edit_cpt_item',
640
-            ), $this->_page_routes);
641
-            $this->_page_config = array_merge(array(
642
-                'create_new' => array(
643
-                    'nav'           => array(
644
-                        'label' => $this->_cpt_object->labels->add_new_item,
645
-                        'order' => 5,
646
-                    ),
647
-                    'require_nonce' => false,
648
-                ),
649
-                'edit'       => array(
650
-                    'nav'           => array(
651
-                        'label'      => $this->_cpt_object->labels->edit_item,
652
-                        'order'      => 5,
653
-                        'persistent' => false,
654
-                        'url'        => '',
655
-                    ),
656
-                    'require_nonce' => false,
657
-                ),
658
-            ),
659
-                $this->_page_config
660
-            );
661
-        }
662
-        //load the next section only if this is a matching cpt route as set in the cpt routes array.
663
-        if ( ! isset($this->_cpt_routes[$this->_req_action])) {
664
-            return;
665
-        }
666
-        $this->_cpt_route = isset($this->_cpt_routes[$this->_req_action]) ? true : false;
667
-        //add_action('FHEE__EE_Admin_Page___load_page_dependencies__after_load', array( $this, 'modify_current_screen') );
668
-        if (empty($this->_cpt_object)) {
669
-            $msg = sprintf(__('This page has been set as being related to a registered custom post type, however, the custom post type object could not be retrieved. There are two possible reasons for this:  1. The "%s" does not match a registered post type. or 2. The custom post type is not registered for the "%s" action as indexed in the "$_cpt_routes" property on this class (%s).'),
670
-                $this->page_slug, $this->_req_action, get_class($this));
671
-            throw new EE_Error($msg);
672
-        }
673
-        if ($this->_cpt_route) {
674
-            $id = isset($this->_req_data['post']) ? $this->_req_data['post'] : null;
675
-            $this->_set_model_object($id);
676
-        }
677
-    }
678
-
679
-
680
-
681
-    /**
682
-     * Sets the _cpt_model_object property using what has been set for the _cpt_model_name and a given id.
683
-     *
684
-     * @access protected
685
-     * @param int  $id The id to retrieve the model object for. If empty we set a default object.
686
-     * @param bool $ignore_route_check
687
-     * @param string $req_type whether the current route is for inserting, updating, or deleting the CPT
688
-     * @throws EE_Error
689
-     */
690
-    protected function _set_model_object($id = null, $ignore_route_check = false, $req_type = '')
691
-    {
692
-        $model = null;
693
-        if (
694
-            empty($this->_cpt_model_names)
695
-            || (
696
-                ! $ignore_route_check
697
-                && ! isset($this->_cpt_routes[$this->_req_action])
698
-            ) || (
699
-                $this->_cpt_model_obj instanceof EE_CPT_Base
700
-                && $this->_cpt_model_obj->ID() === $id
701
-            )
702
-        ) {
703
-            //get out cuz we either don't have a model name OR the object has already been set and it has the same id as what has been sent.
704
-            return;
705
-        }
706
-        //if ignore_route_check is true, then get the model name via EE_Register_CPTs
707
-        if ($ignore_route_check) {
708
-            $model_names = EE_Register_CPTs::get_cpt_model_names();
709
-            $post_type   = get_post_type($id);
710
-            if (isset($model_names[$post_type])) {
711
-                $model = EE_Registry::instance()->load_model($model_names[$post_type]);
712
-            }
713
-        } else {
714
-            $model = EE_Registry::instance()->load_model($this->_cpt_model_names[$this->_req_action]);
715
-        }
716
-        if ($model instanceof EEM_Base) {
717
-            $this->_cpt_model_obj = ! empty($id) ? $model->get_one_by_ID($id) : $model->create_default_object();
718
-        }
719
-        do_action(
720
-            'AHEE__EE_Admin_Page_CPT__set_model_object__after_set_object',
721
-            $this->_cpt_model_obj,
722
-            $req_type
723
-        );
724
-    }
725
-
726
-
727
-
728
-    /**
729
-     * admin_init_global
730
-     * This runs all the code that we want executed within the WP admin_init hook.
731
-     * This method executes for ALL EE Admin pages.
732
-     *
733
-     * @access public
734
-     * @return void
735
-     */
736
-    public function admin_init_global()
737
-    {
738
-        $post = isset($this->_req_data['post']) ? get_post($this->_req_data['post']) : null;
739
-        //its possible this is a new save so let's catch that instead
740
-        $post = isset($this->_req_data['post_ID']) ? get_post($this->_req_data['post_ID']) : $post;
741
-        $post_type = $post ? $post->post_type : false;
742
-        $current_route = isset($this->_req_data['current_route'])
743
-            ? $this->_req_data['current_route']
744
-            : 'shouldneverwork';
745
-        $route_to_check = $post_type && isset($this->_cpt_routes[$current_route])
746
-            ? $this->_cpt_routes[$current_route]
747
-            : '';
748
-        add_filter('get_delete_post_link', array($this, 'modify_delete_post_link'), 10, 3);
749
-        add_filter('get_edit_post_link', array($this, 'modify_edit_post_link'), 10, 3);
750
-        if ($post_type === $route_to_check) {
751
-            add_filter('redirect_post_location', array($this, 'cpt_post_location_redirect'), 10, 2);
752
-        }
753
-        //now let's filter redirect if we're on a revision page and the revision is for an event CPT.
754
-        $revision = isset($this->_req_data['revision']) ? $this->_req_data['revision'] : null;
755
-        if ( ! empty($revision)) {
756
-            $action = isset($this->_req_data['action']) ? $this->_req_data['action'] : null;
757
-            //doing a restore?
758
-            if ( ! empty($action) && $action === 'restore') {
759
-                //get post for revision
760
-                $rev_post = get_post($revision);
761
-                $rev_parent = get_post($rev_post->post_parent);
762
-                //only do our redirect filter AND our restore revision action if the post_type for the parent is one of our cpts.
763
-                if ($rev_parent && $rev_parent->post_type === $this->page_slug) {
764
-                    add_filter('wp_redirect', array($this, 'revision_redirect'), 10, 2);
765
-                    //restores of revisions
766
-                    add_action('wp_restore_post_revision', array($this, 'restore_revision'), 10, 2);
767
-                }
768
-            }
769
-        }
770
-        //NOTE we ONLY want to run these hooks if we're on the right class for the given post type.  Otherwise we could see some really freaky things happen!
771
-        if ($post_type && $post_type === $route_to_check) {
772
-            //$post_id, $post
773
-            add_action('save_post', array($this, 'insert_update'), 10, 3);
774
-            //$post_id
775
-            add_action('trashed_post', array($this, 'before_trash_cpt_item'), 10);
776
-            add_action('trashed_post', array($this, 'dont_permanently_delete_ee_cpts'), 10);
777
-            add_action('untrashed_post', array($this, 'before_restore_cpt_item'), 10);
778
-            add_action('after_delete_post', array($this, 'before_delete_cpt_item'), 10);
779
-        }
780
-    }
781
-
782
-
783
-
784
-    /**
785
-     * Callback for the WordPress trashed_post hook.
786
-     * Execute some basic checks before calling the trash_cpt_item declared in the child class.
787
-     *
788
-     * @param int $post_id
789
-     * @throws \EE_Error
790
-     */
791
-    public function before_trash_cpt_item($post_id)
792
-    {
793
-        $this->_set_model_object($post_id, true, 'trash');
794
-        //if our cpt object isn't existent then get out immediately.
795
-        if ( ! $this->_cpt_model_obj instanceof EE_CPT_Base || $this->_cpt_model_obj->ID() !== $post_id) {
796
-            return;
797
-        }
798
-        $this->trash_cpt_item($post_id);
799
-    }
800
-
801
-
802
-
803
-    /**
804
-     * Callback for the WordPress untrashed_post hook.
805
-     * Execute some basic checks before calling the restore_cpt_method in the child class.
806
-     *
807
-     * @param $post_id
808
-     * @throws \EE_Error
809
-     */
810
-    public function before_restore_cpt_item($post_id)
811
-    {
812
-        $this->_set_model_object($post_id, true, 'restore');
813
-        //if our cpt object isn't existent then get out immediately.
814
-        if ( ! $this->_cpt_model_obj instanceof EE_CPT_Base || $this->_cpt_model_obj->ID() !== $post_id) {
815
-            return;
816
-        }
817
-        $this->restore_cpt_item($post_id);
818
-    }
819
-
820
-
821
-
822
-    /**
823
-     * Callback for the WordPress after_delete_post hook.
824
-     * Execute some basic checks before calling the delete_cpt_item method in the child class.
825
-     *
826
-     * @param $post_id
827
-     * @throws \EE_Error
828
-     */
829
-    public function before_delete_cpt_item($post_id)
830
-    {
831
-        $this->_set_model_object($post_id, true, 'delete');
832
-        //if our cpt object isn't existent then get out immediately.
833
-        if ( ! $this->_cpt_model_obj instanceof EE_CPT_Base || $this->_cpt_model_obj->ID() !== $post_id) {
834
-            return;
835
-        }
836
-        $this->delete_cpt_item($post_id);
837
-    }
838
-
839
-
840
-
841
-    /**
842
-     * This simply verifies if the cpt_model_object is instantiated for the given page and throws an error message
843
-     * accordingly.
844
-     *
845
-     * @access public
846
-     * @throws EE_Error
847
-     * @return void
848
-     */
849
-    public function verify_cpt_object()
850
-    {
851
-        $label = ! empty($this->_cpt_object) ? $this->_cpt_object->labels->singular_name : $this->page_label;
852
-        // verify event object
853
-        if ( ! $this->_cpt_model_obj instanceof EE_CPT_Base) {
854
-            throw new EE_Error(sprintf(__('Something has gone wrong with the page load because we are unable to set up the object for the %1$s.  This usually happens when the given id for the page route is NOT for the correct custom post type for this page',
855
-                    'event_espresso'), $label));
856
-        }
857
-        //if auto-draft then throw an error
858
-        if ($this->_cpt_model_obj->get('status') === 'auto-draft') {
859
-            EE_Error::overwrite_errors();
860
-            EE_Error::add_error(sprintf(__('This %1$s was saved without a title, description, or excerpt which means that none of the extra details you added were saved properly.  All autodrafts will show up in the "draft" view of your event list table.  You can delete them from there. Please click the "Add %1$s" button to refresh and restart.'),
861
-                    $label), __FILE__, __FUNCTION__, __LINE__);
862
-        }
863
-    }
864
-
865
-
866
-
867
-    /**
868
-     * admin_footer_scripts_global
869
-     * Anything triggered by the 'admin_print_footer_scripts' WP hook should be put in here. This particular method
870
-     * will apply on ALL EE_Admin pages.
871
-     *
872
-     * @access public
873
-     * @return void
874
-     */
875
-    public function admin_footer_scripts_global()
876
-    {
877
-        $this->_add_admin_page_ajax_loading_img();
878
-        $this->_add_admin_page_overlay();
879
-    }
880
-
881
-
882
-
883
-    /**
884
-     * add in any global scripts for cpt routes
885
-     *
886
-     * @return void
887
-     */
888
-    public function load_global_scripts_styles()
889
-    {
890
-        parent::load_global_scripts_styles();
891
-        if ($this->_cpt_model_obj instanceof EE_CPT_Base) {
892
-            //setup custom post status object for localize script but only if we've got a cpt object
893
-            $statuses = $this->_cpt_model_obj->get_custom_post_statuses();
894
-            if ( ! empty($statuses)) {
895
-                //get ALL statuses!
896
-                $statuses = $this->_cpt_model_obj->get_all_post_statuses();
897
-                //setup object
898
-                $ee_cpt_statuses = array();
899
-                foreach ($statuses as $status => $label) {
900
-                    $ee_cpt_statuses[$status] = array(
901
-                        'label'      => $label,
902
-                        'save_label' => sprintf(__('Save as %s', 'event_espresso'), $label),
903
-                    );
904
-                }
905
-                wp_localize_script('ee_admin_js', 'eeCPTstatuses', $ee_cpt_statuses);
906
-            }
907
-        }
908
-    }
909
-
910
-
911
-
912
-    /**
913
-     * This is a wrapper for the insert/update routes for cpt items so we can add things that are common to ALL
914
-     * insert/updates
915
-     *
916
-     * @param  int     $post_id ID of post being updated
917
-     * @param  WP_Post $post    Post object from WP
918
-     * @param  bool    $update  Whether this is an update or a new save.
919
-     * @return void
920
-     * @throws \EE_Error
921
-     */
922
-    public function insert_update($post_id, $post, $update)
923
-    {
924
-        //make sure that if this is a revision OR trash action that we don't do any updates!
925
-        if (
926
-            isset($this->_req_data['action'])
927
-            && (
928
-                $this->_req_data['action'] === 'restore'
929
-                || $this->_req_data['action'] === 'trash'
930
-            )
931
-        ) {
932
-            return;
933
-        }
934
-        $this->_set_model_object($post_id, true, 'insert_update');
935
-        //if our cpt object is not instantiated and its NOT the same post_id as what is triggering this callback, then exit.
936
-        if ($update
937
-            && (
938
-                ! $this->_cpt_model_obj instanceof EE_CPT_Base
939
-                || $this->_cpt_model_obj->ID() !== $post_id
940
-            )
941
-        ) {
942
-            return;
943
-        }
944
-        //check for autosave and update our req_data property accordingly.
945
-        /*if ( defined('DOING_AUTOSAVE') && DOING_AUTOSAVE && isset( $this->_req_data['ee_autosave_data'] ) ) {
502
+	}
503
+
504
+
505
+
506
+	/**
507
+	 * if this post is a draft or scheduled post then we provide a preview button for user to click
508
+	 * Method is called from parent and is hooked into the wp 'get_sample_permalink_html' filter.
509
+	 *
510
+	 * @param  string $return    the current html
511
+	 * @param  int    $id        the post id for the page
512
+	 * @param  string $new_title What the title is
513
+	 * @param  string $new_slug  what the slug is
514
+	 * @return string            The new html string for the permalink area
515
+	 */
516
+	public function preview_button_html($return, $id, $new_title, $new_slug)
517
+	{
518
+		$post = get_post($id);
519
+		if ('publish' !== get_post_status($post)) {
520
+			//include shims for the `get_preview_post_link` function
521
+			require_once( EE_CORE . 'wordpress-shims.php' );
522
+			$return .= '<span_id="view-post-btn"><a target="_blank" href="'
523
+					   . get_preview_post_link($id)
524
+					   . '" class="button button-small">'
525
+					   . __('Preview', 'event_espresso')
526
+					   . '</a></span>'
527
+					   . "\n";
528
+		}
529
+		return $return;
530
+	}
531
+
532
+
533
+
534
+	/**
535
+	 * add our custom post stati dropdown on the wp post page for this cpt
536
+	 *
537
+	 * @return void
538
+	 */
539
+	public function custom_post_stati_dropdown()
540
+	{
541
+
542
+		$statuses         = $this->_cpt_model_obj->get_custom_post_statuses();
543
+		$cur_status_label = array_key_exists($this->_cpt_model_obj->status(), $statuses)
544
+			? $statuses[$this->_cpt_model_obj->status()]
545
+			: '';
546
+		$template_args    = array(
547
+			'cur_status'            => $this->_cpt_model_obj->status(),
548
+			'statuses'              => $statuses,
549
+			'cur_status_label'      => $cur_status_label,
550
+			'localized_status_save' => sprintf(__('Save %s', 'event_espresso'), $cur_status_label),
551
+		);
552
+		//we'll add a trash post status (WP doesn't add one for some reason)
553
+		if ($this->_cpt_model_obj->status() === 'trash') {
554
+			$template_args['cur_status_label'] = __('Trashed', 'event_espresso');
555
+			$statuses['trash']                 = __('Trashed', 'event_espresso');
556
+			$template_args['statuses']         = $statuses;
557
+		}
558
+
559
+		$template = EE_ADMIN_TEMPLATE . 'status_dropdown.template.php';
560
+		EEH_Template::display_template($template, $template_args);
561
+	}
562
+
563
+
564
+
565
+	public function setup_autosave_hooks()
566
+	{
567
+		$this->_set_autosave_containers();
568
+		$this->_load_autosave_scripts_styles();
569
+	}
570
+
571
+
572
+
573
+	/**
574
+	 * This is run on all WordPress autosaves AFTER the autosave is complete and sends along a $_POST object (available
575
+	 * in $this->_req_data) containing: post_ID of the saved post autosavenonce for the saved post We'll do the check
576
+	 * for the nonce in here, but then this method looks for two things:
577
+	 * 1. Execute a method (if exists) matching 'ee_autosave_' and appended with the given route. OR
578
+	 * 2. do_actions() for global or class specific actions that have been registered (for plugins/addons not in an
579
+	 * EE_Admin_Page class. PLEASE NOTE: Data will be returned using the _return_json() object and so the
580
+	 * $_template_args property should be used to hold the $data array.  We're expecting the following things set in
581
+	 * template args.
582
+	 *    1. $template_args['error'] = IF there is an error you can add the message in here.
583
+	 *    2. $template_args['data']['items'] = an array of items that are setup in key index pairs of 'where_values_go'
584
+	 *    => 'values_to_add'.  In other words, for the datetime metabox we'll have something like
585
+	 *    $this->_template_args['data']['items'] = array(
586
+	 *        'event-datetime-ids' => '1,2,3';
587
+	 *    );
588
+	 *    Keep in mind the following things:
589
+	 *    - "where" index is for the input with the id as that string.
590
+	 *    - "what" index is what will be used for the value of that input.
591
+	 *
592
+	 * @return void
593
+	 */
594
+	public function do_extra_autosave_stuff()
595
+	{
596
+		//next let's check for the autosave nonce (we'll use _verify_nonce )
597
+		$nonce = isset($this->_req_data['autosavenonce'])
598
+				? $this->_req_data['autosavenonce']
599
+				: null;
600
+		$this->_verify_nonce($nonce, 'autosave');
601
+		//make sure we define doing autosave (cause WP isn't triggering this we want to make sure we define it)
602
+		if ( ! defined('DOING_AUTOSAVE')) {
603
+			define('DOING_AUTOSAVE', true);
604
+		}
605
+		//if we made it here then the nonce checked out.  Let's run our methods and actions
606
+		$autosave = "_ee_autosave_{$this->_current_view}";
607
+		if (method_exists($this, $autosave)) {
608
+			$this->$autosave();
609
+		} else {
610
+			$this->_template_args['success'] = true;
611
+		}
612
+		do_action('AHEE__EE_Admin_Page_CPT__do_extra_autosave_stuff__global_after', $this);
613
+		do_action('AHEE__EE_Admin_Page_CPT__do_extra_autosave_stuff__after_' . get_class($this), $this);
614
+		//now let's return json
615
+		$this->_return_json();
616
+	}
617
+
618
+
619
+
620
+	/**
621
+	 * This takes care of setting up default routes and pages that utilize the core WP admin pages.
622
+	 * Child classes can override the defaults (in cases for adding metaboxes etc.)
623
+	 * but take care that you include the defaults here otherwise your core WP admin pages for the cpt won't work!
624
+	 *
625
+	 * @access protected
626
+	 * @throws EE_Error
627
+	 * @return void
628
+	 */
629
+	protected function _extend_page_config_for_cpt()
630
+	{
631
+		//before doing anything we need to make sure this runs ONLY when the loaded page matches the set page_slug
632
+		if (isset($this->_req_data['page']) && $this->_req_data['page'] !== $this->page_slug) {
633
+			return;
634
+		}
635
+		//set page routes and page config but ONLY if we're not viewing a custom setup cpt route as defined in _cpt_routes
636
+		if ( ! empty($this->_cpt_object)) {
637
+			$this->_page_routes = array_merge(array(
638
+				'create_new' => '_create_new_cpt_item',
639
+				'edit'       => '_edit_cpt_item',
640
+			), $this->_page_routes);
641
+			$this->_page_config = array_merge(array(
642
+				'create_new' => array(
643
+					'nav'           => array(
644
+						'label' => $this->_cpt_object->labels->add_new_item,
645
+						'order' => 5,
646
+					),
647
+					'require_nonce' => false,
648
+				),
649
+				'edit'       => array(
650
+					'nav'           => array(
651
+						'label'      => $this->_cpt_object->labels->edit_item,
652
+						'order'      => 5,
653
+						'persistent' => false,
654
+						'url'        => '',
655
+					),
656
+					'require_nonce' => false,
657
+				),
658
+			),
659
+				$this->_page_config
660
+			);
661
+		}
662
+		//load the next section only if this is a matching cpt route as set in the cpt routes array.
663
+		if ( ! isset($this->_cpt_routes[$this->_req_action])) {
664
+			return;
665
+		}
666
+		$this->_cpt_route = isset($this->_cpt_routes[$this->_req_action]) ? true : false;
667
+		//add_action('FHEE__EE_Admin_Page___load_page_dependencies__after_load', array( $this, 'modify_current_screen') );
668
+		if (empty($this->_cpt_object)) {
669
+			$msg = sprintf(__('This page has been set as being related to a registered custom post type, however, the custom post type object could not be retrieved. There are two possible reasons for this:  1. The "%s" does not match a registered post type. or 2. The custom post type is not registered for the "%s" action as indexed in the "$_cpt_routes" property on this class (%s).'),
670
+				$this->page_slug, $this->_req_action, get_class($this));
671
+			throw new EE_Error($msg);
672
+		}
673
+		if ($this->_cpt_route) {
674
+			$id = isset($this->_req_data['post']) ? $this->_req_data['post'] : null;
675
+			$this->_set_model_object($id);
676
+		}
677
+	}
678
+
679
+
680
+
681
+	/**
682
+	 * Sets the _cpt_model_object property using what has been set for the _cpt_model_name and a given id.
683
+	 *
684
+	 * @access protected
685
+	 * @param int  $id The id to retrieve the model object for. If empty we set a default object.
686
+	 * @param bool $ignore_route_check
687
+	 * @param string $req_type whether the current route is for inserting, updating, or deleting the CPT
688
+	 * @throws EE_Error
689
+	 */
690
+	protected function _set_model_object($id = null, $ignore_route_check = false, $req_type = '')
691
+	{
692
+		$model = null;
693
+		if (
694
+			empty($this->_cpt_model_names)
695
+			|| (
696
+				! $ignore_route_check
697
+				&& ! isset($this->_cpt_routes[$this->_req_action])
698
+			) || (
699
+				$this->_cpt_model_obj instanceof EE_CPT_Base
700
+				&& $this->_cpt_model_obj->ID() === $id
701
+			)
702
+		) {
703
+			//get out cuz we either don't have a model name OR the object has already been set and it has the same id as what has been sent.
704
+			return;
705
+		}
706
+		//if ignore_route_check is true, then get the model name via EE_Register_CPTs
707
+		if ($ignore_route_check) {
708
+			$model_names = EE_Register_CPTs::get_cpt_model_names();
709
+			$post_type   = get_post_type($id);
710
+			if (isset($model_names[$post_type])) {
711
+				$model = EE_Registry::instance()->load_model($model_names[$post_type]);
712
+			}
713
+		} else {
714
+			$model = EE_Registry::instance()->load_model($this->_cpt_model_names[$this->_req_action]);
715
+		}
716
+		if ($model instanceof EEM_Base) {
717
+			$this->_cpt_model_obj = ! empty($id) ? $model->get_one_by_ID($id) : $model->create_default_object();
718
+		}
719
+		do_action(
720
+			'AHEE__EE_Admin_Page_CPT__set_model_object__after_set_object',
721
+			$this->_cpt_model_obj,
722
+			$req_type
723
+		);
724
+	}
725
+
726
+
727
+
728
+	/**
729
+	 * admin_init_global
730
+	 * This runs all the code that we want executed within the WP admin_init hook.
731
+	 * This method executes for ALL EE Admin pages.
732
+	 *
733
+	 * @access public
734
+	 * @return void
735
+	 */
736
+	public function admin_init_global()
737
+	{
738
+		$post = isset($this->_req_data['post']) ? get_post($this->_req_data['post']) : null;
739
+		//its possible this is a new save so let's catch that instead
740
+		$post = isset($this->_req_data['post_ID']) ? get_post($this->_req_data['post_ID']) : $post;
741
+		$post_type = $post ? $post->post_type : false;
742
+		$current_route = isset($this->_req_data['current_route'])
743
+			? $this->_req_data['current_route']
744
+			: 'shouldneverwork';
745
+		$route_to_check = $post_type && isset($this->_cpt_routes[$current_route])
746
+			? $this->_cpt_routes[$current_route]
747
+			: '';
748
+		add_filter('get_delete_post_link', array($this, 'modify_delete_post_link'), 10, 3);
749
+		add_filter('get_edit_post_link', array($this, 'modify_edit_post_link'), 10, 3);
750
+		if ($post_type === $route_to_check) {
751
+			add_filter('redirect_post_location', array($this, 'cpt_post_location_redirect'), 10, 2);
752
+		}
753
+		//now let's filter redirect if we're on a revision page and the revision is for an event CPT.
754
+		$revision = isset($this->_req_data['revision']) ? $this->_req_data['revision'] : null;
755
+		if ( ! empty($revision)) {
756
+			$action = isset($this->_req_data['action']) ? $this->_req_data['action'] : null;
757
+			//doing a restore?
758
+			if ( ! empty($action) && $action === 'restore') {
759
+				//get post for revision
760
+				$rev_post = get_post($revision);
761
+				$rev_parent = get_post($rev_post->post_parent);
762
+				//only do our redirect filter AND our restore revision action if the post_type for the parent is one of our cpts.
763
+				if ($rev_parent && $rev_parent->post_type === $this->page_slug) {
764
+					add_filter('wp_redirect', array($this, 'revision_redirect'), 10, 2);
765
+					//restores of revisions
766
+					add_action('wp_restore_post_revision', array($this, 'restore_revision'), 10, 2);
767
+				}
768
+			}
769
+		}
770
+		//NOTE we ONLY want to run these hooks if we're on the right class for the given post type.  Otherwise we could see some really freaky things happen!
771
+		if ($post_type && $post_type === $route_to_check) {
772
+			//$post_id, $post
773
+			add_action('save_post', array($this, 'insert_update'), 10, 3);
774
+			//$post_id
775
+			add_action('trashed_post', array($this, 'before_trash_cpt_item'), 10);
776
+			add_action('trashed_post', array($this, 'dont_permanently_delete_ee_cpts'), 10);
777
+			add_action('untrashed_post', array($this, 'before_restore_cpt_item'), 10);
778
+			add_action('after_delete_post', array($this, 'before_delete_cpt_item'), 10);
779
+		}
780
+	}
781
+
782
+
783
+
784
+	/**
785
+	 * Callback for the WordPress trashed_post hook.
786
+	 * Execute some basic checks before calling the trash_cpt_item declared in the child class.
787
+	 *
788
+	 * @param int $post_id
789
+	 * @throws \EE_Error
790
+	 */
791
+	public function before_trash_cpt_item($post_id)
792
+	{
793
+		$this->_set_model_object($post_id, true, 'trash');
794
+		//if our cpt object isn't existent then get out immediately.
795
+		if ( ! $this->_cpt_model_obj instanceof EE_CPT_Base || $this->_cpt_model_obj->ID() !== $post_id) {
796
+			return;
797
+		}
798
+		$this->trash_cpt_item($post_id);
799
+	}
800
+
801
+
802
+
803
+	/**
804
+	 * Callback for the WordPress untrashed_post hook.
805
+	 * Execute some basic checks before calling the restore_cpt_method in the child class.
806
+	 *
807
+	 * @param $post_id
808
+	 * @throws \EE_Error
809
+	 */
810
+	public function before_restore_cpt_item($post_id)
811
+	{
812
+		$this->_set_model_object($post_id, true, 'restore');
813
+		//if our cpt object isn't existent then get out immediately.
814
+		if ( ! $this->_cpt_model_obj instanceof EE_CPT_Base || $this->_cpt_model_obj->ID() !== $post_id) {
815
+			return;
816
+		}
817
+		$this->restore_cpt_item($post_id);
818
+	}
819
+
820
+
821
+
822
+	/**
823
+	 * Callback for the WordPress after_delete_post hook.
824
+	 * Execute some basic checks before calling the delete_cpt_item method in the child class.
825
+	 *
826
+	 * @param $post_id
827
+	 * @throws \EE_Error
828
+	 */
829
+	public function before_delete_cpt_item($post_id)
830
+	{
831
+		$this->_set_model_object($post_id, true, 'delete');
832
+		//if our cpt object isn't existent then get out immediately.
833
+		if ( ! $this->_cpt_model_obj instanceof EE_CPT_Base || $this->_cpt_model_obj->ID() !== $post_id) {
834
+			return;
835
+		}
836
+		$this->delete_cpt_item($post_id);
837
+	}
838
+
839
+
840
+
841
+	/**
842
+	 * This simply verifies if the cpt_model_object is instantiated for the given page and throws an error message
843
+	 * accordingly.
844
+	 *
845
+	 * @access public
846
+	 * @throws EE_Error
847
+	 * @return void
848
+	 */
849
+	public function verify_cpt_object()
850
+	{
851
+		$label = ! empty($this->_cpt_object) ? $this->_cpt_object->labels->singular_name : $this->page_label;
852
+		// verify event object
853
+		if ( ! $this->_cpt_model_obj instanceof EE_CPT_Base) {
854
+			throw new EE_Error(sprintf(__('Something has gone wrong with the page load because we are unable to set up the object for the %1$s.  This usually happens when the given id for the page route is NOT for the correct custom post type for this page',
855
+					'event_espresso'), $label));
856
+		}
857
+		//if auto-draft then throw an error
858
+		if ($this->_cpt_model_obj->get('status') === 'auto-draft') {
859
+			EE_Error::overwrite_errors();
860
+			EE_Error::add_error(sprintf(__('This %1$s was saved without a title, description, or excerpt which means that none of the extra details you added were saved properly.  All autodrafts will show up in the "draft" view of your event list table.  You can delete them from there. Please click the "Add %1$s" button to refresh and restart.'),
861
+					$label), __FILE__, __FUNCTION__, __LINE__);
862
+		}
863
+	}
864
+
865
+
866
+
867
+	/**
868
+	 * admin_footer_scripts_global
869
+	 * Anything triggered by the 'admin_print_footer_scripts' WP hook should be put in here. This particular method
870
+	 * will apply on ALL EE_Admin pages.
871
+	 *
872
+	 * @access public
873
+	 * @return void
874
+	 */
875
+	public function admin_footer_scripts_global()
876
+	{
877
+		$this->_add_admin_page_ajax_loading_img();
878
+		$this->_add_admin_page_overlay();
879
+	}
880
+
881
+
882
+
883
+	/**
884
+	 * add in any global scripts for cpt routes
885
+	 *
886
+	 * @return void
887
+	 */
888
+	public function load_global_scripts_styles()
889
+	{
890
+		parent::load_global_scripts_styles();
891
+		if ($this->_cpt_model_obj instanceof EE_CPT_Base) {
892
+			//setup custom post status object for localize script but only if we've got a cpt object
893
+			$statuses = $this->_cpt_model_obj->get_custom_post_statuses();
894
+			if ( ! empty($statuses)) {
895
+				//get ALL statuses!
896
+				$statuses = $this->_cpt_model_obj->get_all_post_statuses();
897
+				//setup object
898
+				$ee_cpt_statuses = array();
899
+				foreach ($statuses as $status => $label) {
900
+					$ee_cpt_statuses[$status] = array(
901
+						'label'      => $label,
902
+						'save_label' => sprintf(__('Save as %s', 'event_espresso'), $label),
903
+					);
904
+				}
905
+				wp_localize_script('ee_admin_js', 'eeCPTstatuses', $ee_cpt_statuses);
906
+			}
907
+		}
908
+	}
909
+
910
+
911
+
912
+	/**
913
+	 * This is a wrapper for the insert/update routes for cpt items so we can add things that are common to ALL
914
+	 * insert/updates
915
+	 *
916
+	 * @param  int     $post_id ID of post being updated
917
+	 * @param  WP_Post $post    Post object from WP
918
+	 * @param  bool    $update  Whether this is an update or a new save.
919
+	 * @return void
920
+	 * @throws \EE_Error
921
+	 */
922
+	public function insert_update($post_id, $post, $update)
923
+	{
924
+		//make sure that if this is a revision OR trash action that we don't do any updates!
925
+		if (
926
+			isset($this->_req_data['action'])
927
+			&& (
928
+				$this->_req_data['action'] === 'restore'
929
+				|| $this->_req_data['action'] === 'trash'
930
+			)
931
+		) {
932
+			return;
933
+		}
934
+		$this->_set_model_object($post_id, true, 'insert_update');
935
+		//if our cpt object is not instantiated and its NOT the same post_id as what is triggering this callback, then exit.
936
+		if ($update
937
+			&& (
938
+				! $this->_cpt_model_obj instanceof EE_CPT_Base
939
+				|| $this->_cpt_model_obj->ID() !== $post_id
940
+			)
941
+		) {
942
+			return;
943
+		}
944
+		//check for autosave and update our req_data property accordingly.
945
+		/*if ( defined('DOING_AUTOSAVE') && DOING_AUTOSAVE && isset( $this->_req_data['ee_autosave_data'] ) ) {
946 946
             foreach( (array) $this->_req_data['ee_autosave_data'] as $id => $values ) {
947 947
 
948 948
                 foreach ( (array) $values as $key => $value ) {
@@ -952,542 +952,542 @@  discard block
 block discarded – undo
952 952
 
953 953
         }/**/ //TODO reactivate after autosave is implemented in 4.2
954 954
 
955
-        //take care of updating any selected page_template IF this cpt supports it.
956
-        if ($this->_supports_page_templates($post->post_type) && ! empty($this->_req_data['page_template'])) {
957
-            //wp version aware.
958
-            if (RecommendedVersions::compareWordPressVersion('4.7', '>=')) {
959
-                $page_templates = wp_get_theme()->get_page_templates();
960
-            } else {
961
-                $post->page_template = $this->_req_data['page_template'];
962
-                $page_templates      = wp_get_theme()->get_page_templates($post);
963
-            }
964
-            if ('default' != $this->_req_data['page_template'] && ! isset($page_templates[$this->_req_data['page_template']])) {
965
-                EE_Error::add_error(__('Invalid Page Template.', 'event_espresso'), __FILE__, __FUNCTION__, __LINE__);
966
-            } else {
967
-                update_post_meta($post_id, '_wp_page_template', $this->_req_data['page_template']);
968
-            }
969
-        }
970
-        if (defined('DOING_AUTOSAVE') && DOING_AUTOSAVE) {
971
-            return;
972
-        } //TODO we'll remove this after reimplementing autosave in 4.2
973
-        $this->_insert_update_cpt_item($post_id, $post);
974
-    }
975
-
976
-
977
-
978
-    /**
979
-     * This hooks into the wp_trash_post() function and removes the `_wp_trash_meta_status` and `_wp_trash_meta_time`
980
-     * post meta IF the trashed post is one of our CPT's - note this method should only be called with our cpt routes
981
-     * so we don't have to check for our CPT.
982
-     *
983
-     * @param  int $post_id ID of the post
984
-     * @return void
985
-     */
986
-    public function dont_permanently_delete_ee_cpts($post_id)
987
-    {
988
-        //only do this if we're actually processing one of our CPTs
989
-        //if our cpt object isn't existent then get out immediately.
990
-        if ( ! $this->_cpt_model_obj instanceof EE_CPT_Base) {
991
-            return;
992
-        }
993
-        delete_post_meta($post_id, '_wp_trash_meta_status');
994
-        delete_post_meta($post_id, '_wp_trash_meta_time');
995
-        //our cpts may have comments so let's take care of that too
996
-        delete_post_meta($post_id, '_wp_trash_meta_comments_status');
997
-    }
998
-
999
-
1000
-
1001
-    /**
1002
-     * This is a wrapper for the restore_cpt_revision route for cpt items so we can make sure that when a revision is
1003
-     * triggered that we restore related items.  In order to work cpt classes MUST have a restore_cpt_revision method
1004
-     * in them. We also have our OWN action in here so addons can hook into the restore process easily.
1005
-     *
1006
-     * @param  int $post_id     ID of cpt item
1007
-     * @param  int $revision_id ID of revision being restored
1008
-     * @return void
1009
-     */
1010
-    public function restore_revision($post_id, $revision_id)
1011
-    {
1012
-        $this->_restore_cpt_item($post_id, $revision_id);
1013
-        //global action
1014
-        do_action('AHEE_EE_Admin_Page_CPT__restore_revision', $post_id, $revision_id);
1015
-        //class specific action so you can limit hooking into a specific page.
1016
-        do_action('AHEE_EE_Admin_Page_CPT_' . get_class($this) . '__restore_revision', $post_id, $revision_id);
1017
-    }
1018
-
1019
-
1020
-
1021
-    /**
1022
-     * @see restore_revision() for details
1023
-     * @param  int $post_id     ID of cpt item
1024
-     * @param  int $revision_id ID of revision for item
1025
-     * @return void
1026
-     */
1027
-    abstract protected function _restore_cpt_item($post_id, $revision_id);
1028
-
1029
-
1030
-
1031
-    /**
1032
-     * Execution of this method is added to the end of the load_page_dependencies method in the parent
1033
-     * so that we can fix a bug where default core metaboxes were not being called in the sidebar.
1034
-     * To fix we have to reset the current_screen using the page_slug
1035
-     * (which is identical - or should be - to our registered_post_type id.)
1036
-     * Also, since the core WP file loads the admin_header.php for WP
1037
-     * (and there are a bunch of other things edit-form-advanced.php loads that need to happen really early)
1038
-     * we need to load it NOW, hence our _route_admin_request in here. (Otherwise screen options won't be set).
1039
-     *
1040
-     * @return void
1041
-     */
1042
-    public function modify_current_screen()
1043
-    {
1044
-        //ONLY do this if the current page_route IS a cpt route
1045
-        if ( ! $this->_cpt_route) {
1046
-            return;
1047
-        }
1048
-        //routing things REALLY early b/c this is a cpt admin page
1049
-        set_current_screen($this->_cpt_routes[$this->_req_action]);
1050
-        $this->_current_screen       = get_current_screen();
1051
-        $this->_current_screen->base = 'event-espresso';
1052
-        $this->_add_help_tabs(); //we make sure we add any help tabs back in!
1053
-        /*try {
955
+		//take care of updating any selected page_template IF this cpt supports it.
956
+		if ($this->_supports_page_templates($post->post_type) && ! empty($this->_req_data['page_template'])) {
957
+			//wp version aware.
958
+			if (RecommendedVersions::compareWordPressVersion('4.7', '>=')) {
959
+				$page_templates = wp_get_theme()->get_page_templates();
960
+			} else {
961
+				$post->page_template = $this->_req_data['page_template'];
962
+				$page_templates      = wp_get_theme()->get_page_templates($post);
963
+			}
964
+			if ('default' != $this->_req_data['page_template'] && ! isset($page_templates[$this->_req_data['page_template']])) {
965
+				EE_Error::add_error(__('Invalid Page Template.', 'event_espresso'), __FILE__, __FUNCTION__, __LINE__);
966
+			} else {
967
+				update_post_meta($post_id, '_wp_page_template', $this->_req_data['page_template']);
968
+			}
969
+		}
970
+		if (defined('DOING_AUTOSAVE') && DOING_AUTOSAVE) {
971
+			return;
972
+		} //TODO we'll remove this after reimplementing autosave in 4.2
973
+		$this->_insert_update_cpt_item($post_id, $post);
974
+	}
975
+
976
+
977
+
978
+	/**
979
+	 * This hooks into the wp_trash_post() function and removes the `_wp_trash_meta_status` and `_wp_trash_meta_time`
980
+	 * post meta IF the trashed post is one of our CPT's - note this method should only be called with our cpt routes
981
+	 * so we don't have to check for our CPT.
982
+	 *
983
+	 * @param  int $post_id ID of the post
984
+	 * @return void
985
+	 */
986
+	public function dont_permanently_delete_ee_cpts($post_id)
987
+	{
988
+		//only do this if we're actually processing one of our CPTs
989
+		//if our cpt object isn't existent then get out immediately.
990
+		if ( ! $this->_cpt_model_obj instanceof EE_CPT_Base) {
991
+			return;
992
+		}
993
+		delete_post_meta($post_id, '_wp_trash_meta_status');
994
+		delete_post_meta($post_id, '_wp_trash_meta_time');
995
+		//our cpts may have comments so let's take care of that too
996
+		delete_post_meta($post_id, '_wp_trash_meta_comments_status');
997
+	}
998
+
999
+
1000
+
1001
+	/**
1002
+	 * This is a wrapper for the restore_cpt_revision route for cpt items so we can make sure that when a revision is
1003
+	 * triggered that we restore related items.  In order to work cpt classes MUST have a restore_cpt_revision method
1004
+	 * in them. We also have our OWN action in here so addons can hook into the restore process easily.
1005
+	 *
1006
+	 * @param  int $post_id     ID of cpt item
1007
+	 * @param  int $revision_id ID of revision being restored
1008
+	 * @return void
1009
+	 */
1010
+	public function restore_revision($post_id, $revision_id)
1011
+	{
1012
+		$this->_restore_cpt_item($post_id, $revision_id);
1013
+		//global action
1014
+		do_action('AHEE_EE_Admin_Page_CPT__restore_revision', $post_id, $revision_id);
1015
+		//class specific action so you can limit hooking into a specific page.
1016
+		do_action('AHEE_EE_Admin_Page_CPT_' . get_class($this) . '__restore_revision', $post_id, $revision_id);
1017
+	}
1018
+
1019
+
1020
+
1021
+	/**
1022
+	 * @see restore_revision() for details
1023
+	 * @param  int $post_id     ID of cpt item
1024
+	 * @param  int $revision_id ID of revision for item
1025
+	 * @return void
1026
+	 */
1027
+	abstract protected function _restore_cpt_item($post_id, $revision_id);
1028
+
1029
+
1030
+
1031
+	/**
1032
+	 * Execution of this method is added to the end of the load_page_dependencies method in the parent
1033
+	 * so that we can fix a bug where default core metaboxes were not being called in the sidebar.
1034
+	 * To fix we have to reset the current_screen using the page_slug
1035
+	 * (which is identical - or should be - to our registered_post_type id.)
1036
+	 * Also, since the core WP file loads the admin_header.php for WP
1037
+	 * (and there are a bunch of other things edit-form-advanced.php loads that need to happen really early)
1038
+	 * we need to load it NOW, hence our _route_admin_request in here. (Otherwise screen options won't be set).
1039
+	 *
1040
+	 * @return void
1041
+	 */
1042
+	public function modify_current_screen()
1043
+	{
1044
+		//ONLY do this if the current page_route IS a cpt route
1045
+		if ( ! $this->_cpt_route) {
1046
+			return;
1047
+		}
1048
+		//routing things REALLY early b/c this is a cpt admin page
1049
+		set_current_screen($this->_cpt_routes[$this->_req_action]);
1050
+		$this->_current_screen       = get_current_screen();
1051
+		$this->_current_screen->base = 'event-espresso';
1052
+		$this->_add_help_tabs(); //we make sure we add any help tabs back in!
1053
+		/*try {
1054 1054
             $this->_route_admin_request();
1055 1055
         } catch ( EE_Error $e ) {
1056 1056
             $e->get_error();
1057 1057
         }/**/
1058
-    }
1059
-
1060
-
1061
-
1062
-    /**
1063
-     * This allows child classes to modify the default editor title that appears when people add a new or edit an
1064
-     * existing CPT item.     * This uses the _labels property set by the child class via _define_page_props. Just make
1065
-     * sure you have a key in _labels property that equals 'editor_title' and the value can be whatever you want the
1066
-     * default to be.
1067
-     *
1068
-     * @param string $title The new title (or existing if there is no editor_title defined)
1069
-     * @return string
1070
-     */
1071
-    public function add_custom_editor_default_title($title)
1072
-    {
1073
-        return isset($this->_labels['editor_title'][$this->_cpt_routes[$this->_req_action]])
1074
-            ? $this->_labels['editor_title'][$this->_cpt_routes[$this->_req_action]]
1075
-            : $title;
1076
-    }
1077
-
1078
-
1079
-
1080
-    /**
1081
-     * hooks into the wp_get_shortlink button and makes sure that the shortlink gets generated
1082
-     *
1083
-     * @param string $shortlink   The already generated shortlink
1084
-     * @param int    $id          Post ID for this item
1085
-     * @param string $context     The context for the link
1086
-     * @param bool   $allow_slugs Whether to allow post slugs in the shortlink.
1087
-     * @return string
1088
-     */
1089
-    public function add_shortlink_button_to_editor($shortlink, $id, $context, $allow_slugs)
1090
-    {
1091
-        if ( ! empty($id) && get_option('permalink_structure') !== '') {
1092
-            $post = get_post($id);
1093
-            if (isset($post->post_type) && $this->page_slug === $post->post_type) {
1094
-                $shortlink = home_url('?p=' . $post->ID);
1095
-            }
1096
-        }
1097
-        return $shortlink;
1098
-    }
1099
-
1100
-
1101
-
1102
-    /**
1103
-     * overriding the parent route_admin_request method so we DON'T run the route twice on cpt core page loads (it's
1104
-     * already run in modify_current_screen())
1105
-     *
1106
-     * @return void
1107
-     */
1108
-    public function route_admin_request()
1109
-    {
1110
-        if ($this->_cpt_route) {
1111
-            return;
1112
-        }
1113
-        try {
1114
-            $this->_route_admin_request();
1115
-        } catch (EE_Error $e) {
1116
-            $e->get_error();
1117
-        }
1118
-    }
1119
-
1120
-
1121
-
1122
-    /**
1123
-     * Add a hidden form input to cpt core pages so that we know to do redirects to our routes on saves
1124
-     *
1125
-     * @return void
1126
-     */
1127
-    public function cpt_post_form_hidden_input()
1128
-    {
1129
-        echo '<input type="hidden" name="ee_cpt_item_redirect_url" value="' . $this->_admin_base_url . '" />';
1130
-        //we're also going to add the route value and the current page so we can direct autosave parsing correctly
1131
-        echo '<div id="ee-cpt-hidden-inputs">';
1132
-        echo '<input type="hidden" id="current_route" name="current_route" value="' . $this->_current_view . '" />';
1133
-        echo '<input type="hidden" id="current_page" name="current_page" value="' . $this->page_slug . '" />';
1134
-        echo '</div>';
1135
-    }
1136
-
1137
-
1138
-
1139
-    /**
1140
-     * This allows us to redirect the location of revision restores when they happen so it goes to our CPT routes.
1141
-     *
1142
-     * @param  string $location Original location url
1143
-     * @param  int    $status   Status for http header
1144
-     * @return string           new (or original) url to redirect to.
1145
-     */
1146
-    public function revision_redirect($location, $status)
1147
-    {
1148
-        //get revision
1149
-        $rev_id = isset($this->_req_data['revision']) ? $this->_req_data['revision'] : null;
1150
-        //can't do anything without revision so let's get out if not present
1151
-        if (empty($rev_id)) {
1152
-            return $location;
1153
-        }
1154
-        //get rev_post_data
1155
-        $rev = get_post($rev_id);
1156
-        $admin_url = $this->_admin_base_url;
1157
-        $query_args = array(
1158
-            'action'   => 'edit',
1159
-            'post'     => $rev->post_parent,
1160
-            'revision' => $rev_id,
1161
-            'message'  => 5,
1162
-        );
1163
-        $this->_process_notices($query_args, true);
1164
-        return self::add_query_args_and_nonce($query_args, $admin_url);
1165
-    }
1166
-
1167
-
1168
-
1169
-    /**
1170
-     * Modify the edit post link generated by wp core function so that EE CPTs get setup differently.
1171
-     *
1172
-     * @param  string $link    the original generated link
1173
-     * @param  int    $id      post id
1174
-     * @param  string $context optional, defaults to display.  How to write the '&'
1175
-     * @return string          the link
1176
-     */
1177
-    public function modify_edit_post_link($link, $id, $context)
1178
-    {
1179
-        $post = get_post($id);
1180
-        if ( ! isset($this->_req_data['action'])
1181
-             || ! isset($this->_cpt_routes[$this->_req_data['action']])
1182
-             || $post->post_type !== $this->_cpt_routes[$this->_req_data['action']]
1183
-        ) {
1184
-            return $link;
1185
-        }
1186
-        $query_args = array(
1187
-            'action' => isset($this->_cpt_edit_routes[$post->post_type])
1188
-                ? $this->_cpt_edit_routes[$post->post_type]
1189
-                : 'edit',
1190
-            'post'   => $id,
1191
-        );
1192
-        return self::add_query_args_and_nonce($query_args, $this->_admin_base_url);
1193
-    }
1194
-
1195
-
1196
-    /**
1197
-     * Modify the trash link on our cpt edit pages so it has the required query var for triggering redirect properly on
1198
-     * our routes.
1199
-     *
1200
-     * @param  string $delete_link  original delete link
1201
-     * @param  int    $post_id      id of cpt object
1202
-     * @param  bool   $force_delete whether this is forcing a hard delete instead of trash
1203
-     * @return string new delete link
1204
-     * @throws EE_Error
1205
-     */
1206
-    public function modify_delete_post_link($delete_link, $post_id, $force_delete)
1207
-    {
1208
-        $post = get_post($post_id);
1209
-
1210
-        if (empty($this->_req_data['action'])
1211
-            || ! isset($this->_cpt_routes[$this->_req_data['action']])
1212
-            || ! $post instanceof WP_Post
1213
-            || $post->post_type !== $this->_cpt_routes[$this->_req_data['action']]
1214
-        ) {
1215
-            return $delete_link;
1216
-        }
1217
-        $this->_set_model_object($post->ID, true);
1218
-
1219
-        //returns something like `trash_event` or `trash_attendee` or `trash_venue`
1220
-        $action = 'trash_' . str_replace('ee_', '', strtolower(get_class($this->_cpt_model_obj)));
1221
-
1222
-        return EE_Admin_Page::add_query_args_and_nonce(
1223
-            array(
1224
-                'page' => $this->_req_data['page'],
1225
-                'action' => $action,
1226
-                $this->_cpt_model_obj->get_model()->get_primary_key_field()->get_name()
1227
-                    => $post->ID
1228
-            ),
1229
-            admin_url()
1230
-        );
1231
-    }
1232
-
1233
-
1234
-
1235
-    /**
1236
-     * This is the callback for the 'redirect_post_location' filter in wp-admin/post.php
1237
-     * so that we can hijack the default redirect locations for wp custom post types
1238
-     * that WE'RE using and send back to OUR routes.  This should only be hooked in on the right route.
1239
-     *
1240
-     * @param  string $location This is the incoming currently set redirect location
1241
-     * @param  string $post_id  This is the 'ID' value of the wp_posts table
1242
-     * @return string           the new location to redirect to
1243
-     */
1244
-    public function cpt_post_location_redirect($location, $post_id)
1245
-    {
1246
-        //we DO have a match so let's setup the url
1247
-        //we have to get the post to determine our route
1248
-        $post       = get_post($post_id);
1249
-        $edit_route = $this->_cpt_edit_routes[$post->post_type];
1250
-        //shared query_args
1251
-        $query_args = array('action' => $edit_route, 'post' => $post_id);
1252
-        $admin_url  = $this->_admin_base_url;
1253
-        if (isset($this->_req_data['save']) || isset($this->_req_data['publish'])) {
1254
-            $status = get_post_status($post_id);
1255
-            if (isset($this->_req_data['publish'])) {
1256
-                switch ($status) {
1257
-                    case 'pending':
1258
-                        $message = 8;
1259
-                        break;
1260
-                    case 'future':
1261
-                        $message = 9;
1262
-                        break;
1263
-                    default:
1264
-                        $message = 6;
1265
-                }
1266
-            } else {
1267
-                $message = 'draft' === $status ? 10 : 1;
1268
-            }
1269
-        } else if (isset($this->_req_data['addmeta']) && $this->_req_data['addmeta']) {
1270
-            $message = 2;
1271
-            //			$append = '#postcustom';
1272
-        } else if (isset($this->_req_data['deletemeta']) && $this->_req_data['deletemeta']) {
1273
-            $message = 3;
1274
-            //			$append = '#postcustom';
1275
-        } elseif ($this->_req_data['action'] === 'post-quickpress-save-cont') {
1276
-            $message = 7;
1277
-        } else {
1278
-            $message = 4;
1279
-        }
1280
-        //change the message if the post type is not viewable on the frontend
1281
-        $this->_cpt_object = get_post_type_object($post->post_type);
1282
-        $message           = $message === 1 && ! $this->_cpt_object->publicly_queryable ? 4 : $message;
1283
-        $query_args = array_merge(array('message' => $message), $query_args);
1284
-        $this->_process_notices($query_args, true);
1285
-        return self::add_query_args_and_nonce($query_args, $admin_url);
1286
-    }
1287
-
1288
-
1289
-
1290
-    /**
1291
-     * This method is called to inject nav tabs on core WP cpt pages
1292
-     *
1293
-     * @access public
1294
-     * @return void
1295
-     */
1296
-    public function inject_nav_tabs()
1297
-    {
1298
-        //can we hijack and insert the nav_tabs?
1299
-        $nav_tabs = $this->_get_main_nav_tabs();
1300
-        //first close off existing form tag
1301
-        $html = '>';
1302
-        $html .= $nav_tabs;
1303
-        //now let's handle the remaining tag ( missing ">" is CORRECT )
1304
-        $html .= '<span></span';
1305
-        echo $html;
1306
-    }
1307
-
1308
-
1309
-
1310
-    /**
1311
-     * This just sets up the post update messages when an update form is loaded
1312
-     *
1313
-     * @access public
1314
-     * @param  array $messages the original messages array
1315
-     * @return array           the new messages array
1316
-     */
1317
-    public function post_update_messages($messages)
1318
-    {
1319
-        global $post;
1320
-        $id = isset($this->_req_data['post']) ? $this->_req_data['post'] : null;
1321
-        $id = empty($id) && is_object($post) ? $post->ID : null;
1322
-        //		$post_type = $post ? $post->post_type : false;
1323
-        /*$current_route = isset($this->_req_data['current_route']) ? $this->_req_data['current_route'] : 'shouldneverwork';
1058
+	}
1059
+
1060
+
1061
+
1062
+	/**
1063
+	 * This allows child classes to modify the default editor title that appears when people add a new or edit an
1064
+	 * existing CPT item.     * This uses the _labels property set by the child class via _define_page_props. Just make
1065
+	 * sure you have a key in _labels property that equals 'editor_title' and the value can be whatever you want the
1066
+	 * default to be.
1067
+	 *
1068
+	 * @param string $title The new title (or existing if there is no editor_title defined)
1069
+	 * @return string
1070
+	 */
1071
+	public function add_custom_editor_default_title($title)
1072
+	{
1073
+		return isset($this->_labels['editor_title'][$this->_cpt_routes[$this->_req_action]])
1074
+			? $this->_labels['editor_title'][$this->_cpt_routes[$this->_req_action]]
1075
+			: $title;
1076
+	}
1077
+
1078
+
1079
+
1080
+	/**
1081
+	 * hooks into the wp_get_shortlink button and makes sure that the shortlink gets generated
1082
+	 *
1083
+	 * @param string $shortlink   The already generated shortlink
1084
+	 * @param int    $id          Post ID for this item
1085
+	 * @param string $context     The context for the link
1086
+	 * @param bool   $allow_slugs Whether to allow post slugs in the shortlink.
1087
+	 * @return string
1088
+	 */
1089
+	public function add_shortlink_button_to_editor($shortlink, $id, $context, $allow_slugs)
1090
+	{
1091
+		if ( ! empty($id) && get_option('permalink_structure') !== '') {
1092
+			$post = get_post($id);
1093
+			if (isset($post->post_type) && $this->page_slug === $post->post_type) {
1094
+				$shortlink = home_url('?p=' . $post->ID);
1095
+			}
1096
+		}
1097
+		return $shortlink;
1098
+	}
1099
+
1100
+
1101
+
1102
+	/**
1103
+	 * overriding the parent route_admin_request method so we DON'T run the route twice on cpt core page loads (it's
1104
+	 * already run in modify_current_screen())
1105
+	 *
1106
+	 * @return void
1107
+	 */
1108
+	public function route_admin_request()
1109
+	{
1110
+		if ($this->_cpt_route) {
1111
+			return;
1112
+		}
1113
+		try {
1114
+			$this->_route_admin_request();
1115
+		} catch (EE_Error $e) {
1116
+			$e->get_error();
1117
+		}
1118
+	}
1119
+
1120
+
1121
+
1122
+	/**
1123
+	 * Add a hidden form input to cpt core pages so that we know to do redirects to our routes on saves
1124
+	 *
1125
+	 * @return void
1126
+	 */
1127
+	public function cpt_post_form_hidden_input()
1128
+	{
1129
+		echo '<input type="hidden" name="ee_cpt_item_redirect_url" value="' . $this->_admin_base_url . '" />';
1130
+		//we're also going to add the route value and the current page so we can direct autosave parsing correctly
1131
+		echo '<div id="ee-cpt-hidden-inputs">';
1132
+		echo '<input type="hidden" id="current_route" name="current_route" value="' . $this->_current_view . '" />';
1133
+		echo '<input type="hidden" id="current_page" name="current_page" value="' . $this->page_slug . '" />';
1134
+		echo '</div>';
1135
+	}
1136
+
1137
+
1138
+
1139
+	/**
1140
+	 * This allows us to redirect the location of revision restores when they happen so it goes to our CPT routes.
1141
+	 *
1142
+	 * @param  string $location Original location url
1143
+	 * @param  int    $status   Status for http header
1144
+	 * @return string           new (or original) url to redirect to.
1145
+	 */
1146
+	public function revision_redirect($location, $status)
1147
+	{
1148
+		//get revision
1149
+		$rev_id = isset($this->_req_data['revision']) ? $this->_req_data['revision'] : null;
1150
+		//can't do anything without revision so let's get out if not present
1151
+		if (empty($rev_id)) {
1152
+			return $location;
1153
+		}
1154
+		//get rev_post_data
1155
+		$rev = get_post($rev_id);
1156
+		$admin_url = $this->_admin_base_url;
1157
+		$query_args = array(
1158
+			'action'   => 'edit',
1159
+			'post'     => $rev->post_parent,
1160
+			'revision' => $rev_id,
1161
+			'message'  => 5,
1162
+		);
1163
+		$this->_process_notices($query_args, true);
1164
+		return self::add_query_args_and_nonce($query_args, $admin_url);
1165
+	}
1166
+
1167
+
1168
+
1169
+	/**
1170
+	 * Modify the edit post link generated by wp core function so that EE CPTs get setup differently.
1171
+	 *
1172
+	 * @param  string $link    the original generated link
1173
+	 * @param  int    $id      post id
1174
+	 * @param  string $context optional, defaults to display.  How to write the '&'
1175
+	 * @return string          the link
1176
+	 */
1177
+	public function modify_edit_post_link($link, $id, $context)
1178
+	{
1179
+		$post = get_post($id);
1180
+		if ( ! isset($this->_req_data['action'])
1181
+			 || ! isset($this->_cpt_routes[$this->_req_data['action']])
1182
+			 || $post->post_type !== $this->_cpt_routes[$this->_req_data['action']]
1183
+		) {
1184
+			return $link;
1185
+		}
1186
+		$query_args = array(
1187
+			'action' => isset($this->_cpt_edit_routes[$post->post_type])
1188
+				? $this->_cpt_edit_routes[$post->post_type]
1189
+				: 'edit',
1190
+			'post'   => $id,
1191
+		);
1192
+		return self::add_query_args_and_nonce($query_args, $this->_admin_base_url);
1193
+	}
1194
+
1195
+
1196
+	/**
1197
+	 * Modify the trash link on our cpt edit pages so it has the required query var for triggering redirect properly on
1198
+	 * our routes.
1199
+	 *
1200
+	 * @param  string $delete_link  original delete link
1201
+	 * @param  int    $post_id      id of cpt object
1202
+	 * @param  bool   $force_delete whether this is forcing a hard delete instead of trash
1203
+	 * @return string new delete link
1204
+	 * @throws EE_Error
1205
+	 */
1206
+	public function modify_delete_post_link($delete_link, $post_id, $force_delete)
1207
+	{
1208
+		$post = get_post($post_id);
1209
+
1210
+		if (empty($this->_req_data['action'])
1211
+			|| ! isset($this->_cpt_routes[$this->_req_data['action']])
1212
+			|| ! $post instanceof WP_Post
1213
+			|| $post->post_type !== $this->_cpt_routes[$this->_req_data['action']]
1214
+		) {
1215
+			return $delete_link;
1216
+		}
1217
+		$this->_set_model_object($post->ID, true);
1218
+
1219
+		//returns something like `trash_event` or `trash_attendee` or `trash_venue`
1220
+		$action = 'trash_' . str_replace('ee_', '', strtolower(get_class($this->_cpt_model_obj)));
1221
+
1222
+		return EE_Admin_Page::add_query_args_and_nonce(
1223
+			array(
1224
+				'page' => $this->_req_data['page'],
1225
+				'action' => $action,
1226
+				$this->_cpt_model_obj->get_model()->get_primary_key_field()->get_name()
1227
+					=> $post->ID
1228
+			),
1229
+			admin_url()
1230
+		);
1231
+	}
1232
+
1233
+
1234
+
1235
+	/**
1236
+	 * This is the callback for the 'redirect_post_location' filter in wp-admin/post.php
1237
+	 * so that we can hijack the default redirect locations for wp custom post types
1238
+	 * that WE'RE using and send back to OUR routes.  This should only be hooked in on the right route.
1239
+	 *
1240
+	 * @param  string $location This is the incoming currently set redirect location
1241
+	 * @param  string $post_id  This is the 'ID' value of the wp_posts table
1242
+	 * @return string           the new location to redirect to
1243
+	 */
1244
+	public function cpt_post_location_redirect($location, $post_id)
1245
+	{
1246
+		//we DO have a match so let's setup the url
1247
+		//we have to get the post to determine our route
1248
+		$post       = get_post($post_id);
1249
+		$edit_route = $this->_cpt_edit_routes[$post->post_type];
1250
+		//shared query_args
1251
+		$query_args = array('action' => $edit_route, 'post' => $post_id);
1252
+		$admin_url  = $this->_admin_base_url;
1253
+		if (isset($this->_req_data['save']) || isset($this->_req_data['publish'])) {
1254
+			$status = get_post_status($post_id);
1255
+			if (isset($this->_req_data['publish'])) {
1256
+				switch ($status) {
1257
+					case 'pending':
1258
+						$message = 8;
1259
+						break;
1260
+					case 'future':
1261
+						$message = 9;
1262
+						break;
1263
+					default:
1264
+						$message = 6;
1265
+				}
1266
+			} else {
1267
+				$message = 'draft' === $status ? 10 : 1;
1268
+			}
1269
+		} else if (isset($this->_req_data['addmeta']) && $this->_req_data['addmeta']) {
1270
+			$message = 2;
1271
+			//			$append = '#postcustom';
1272
+		} else if (isset($this->_req_data['deletemeta']) && $this->_req_data['deletemeta']) {
1273
+			$message = 3;
1274
+			//			$append = '#postcustom';
1275
+		} elseif ($this->_req_data['action'] === 'post-quickpress-save-cont') {
1276
+			$message = 7;
1277
+		} else {
1278
+			$message = 4;
1279
+		}
1280
+		//change the message if the post type is not viewable on the frontend
1281
+		$this->_cpt_object = get_post_type_object($post->post_type);
1282
+		$message           = $message === 1 && ! $this->_cpt_object->publicly_queryable ? 4 : $message;
1283
+		$query_args = array_merge(array('message' => $message), $query_args);
1284
+		$this->_process_notices($query_args, true);
1285
+		return self::add_query_args_and_nonce($query_args, $admin_url);
1286
+	}
1287
+
1288
+
1289
+
1290
+	/**
1291
+	 * This method is called to inject nav tabs on core WP cpt pages
1292
+	 *
1293
+	 * @access public
1294
+	 * @return void
1295
+	 */
1296
+	public function inject_nav_tabs()
1297
+	{
1298
+		//can we hijack and insert the nav_tabs?
1299
+		$nav_tabs = $this->_get_main_nav_tabs();
1300
+		//first close off existing form tag
1301
+		$html = '>';
1302
+		$html .= $nav_tabs;
1303
+		//now let's handle the remaining tag ( missing ">" is CORRECT )
1304
+		$html .= '<span></span';
1305
+		echo $html;
1306
+	}
1307
+
1308
+
1309
+
1310
+	/**
1311
+	 * This just sets up the post update messages when an update form is loaded
1312
+	 *
1313
+	 * @access public
1314
+	 * @param  array $messages the original messages array
1315
+	 * @return array           the new messages array
1316
+	 */
1317
+	public function post_update_messages($messages)
1318
+	{
1319
+		global $post;
1320
+		$id = isset($this->_req_data['post']) ? $this->_req_data['post'] : null;
1321
+		$id = empty($id) && is_object($post) ? $post->ID : null;
1322
+		//		$post_type = $post ? $post->post_type : false;
1323
+		/*$current_route = isset($this->_req_data['current_route']) ? $this->_req_data['current_route'] : 'shouldneverwork';
1324 1324
 
1325 1325
         $route_to_check = $post_type && isset( $this->_cpt_routes[$current_route]) ? $this->_cpt_routes[$current_route] : '';/**/
1326
-        $messages[$post->post_type] = array(
1327
-            0 => '', //Unused. Messages start at index 1.
1328
-            1 => sprintf(
1329
-                __('%1$s updated. %2$sView %1$s%3$s', 'event_espresso'),
1330
-                $this->_cpt_object->labels->singular_name,
1331
-                '<a href="' . esc_url(get_permalink($id)) . '">',
1332
-                '</a>'
1333
-            ),
1334
-            2 => __('Custom field updated'),
1335
-            3 => __('Custom field deleted.'),
1336
-            4 => sprintf(__('%1$s updated.', 'event_espresso'), $this->_cpt_object->labels->singular_name),
1337
-            5 => isset($_GET['revision']) ? sprintf(__('%s restored to revision from %s', 'event_espresso'),
1338
-                $this->_cpt_object->labels->singular_name, wp_post_revision_title((int)$_GET['revision'], false))
1339
-                : false,
1340
-            6 => sprintf(
1341
-                __('%1$s published. %2$sView %1$s%3$s', 'event_espresso'),
1342
-                $this->_cpt_object->labels->singular_name,
1343
-                '<a href="' . esc_url(get_permalink($id)) . '">',
1344
-                '</a>'
1345
-            ),
1346
-            7 => sprintf(__('%1$s saved.', 'event_espresso'), $this->_cpt_object->labels->singular_name),
1347
-            8 => sprintf(
1348
-                __('%1$s submitted. %2$sPreview %1$s%3$s', 'event_espresso'),
1349
-                $this->_cpt_object->labels->singular_name,
1350
-                '<a target="_blank" href="' . esc_url(add_query_arg('preview', 'true', get_permalink($id))) . '">',
1351
-                '</a>'
1352
-            ),
1353
-            9 => sprintf(
1354
-                __('%1$s scheduled for: %2$s. %3$s">Preview %1$s%3$s', 'event_espresso'),
1355
-                $this->_cpt_object->labels->singular_name,
1356
-                '<strong>' . date_i18n(__('M j, Y @ G:i'), strtotime($post->post_date)) . '</strong>',
1357
-                '<a target="_blank" href="' . esc_url(get_permalink($id)),
1358
-                '</a>'
1359
-            ),
1360
-            10 => sprintf(
1361
-                __('%1$s draft updated. %2$s">Preview page%3$s', 'event_espresso'),
1362
-                $this->_cpt_object->labels->singular_name,
1363
-                '<a target="_blank" href="' . esc_url(add_query_arg('preview', 'true', get_permalink($id))),
1364
-                '</a>'
1365
-            ),
1366
-        );
1367
-        return $messages;
1368
-    }
1369
-
1370
-
1371
-
1372
-    /**
1373
-     * default method for the 'create_new' route for cpt admin pages.
1374
-     * For reference what to include in here, see wp-admin/post-new.php
1375
-     *
1376
-     * @access  protected
1377
-     * @return void
1378
-     */
1379
-    protected function _create_new_cpt_item()
1380
-    {
1381
-        // gather template vars for WP_ADMIN_PATH . 'edit-form-advanced.php'
1382
-        global $post, $title, $is_IE, $post_type, $post_type_object;
1383
-        $post_type        = $this->_cpt_routes[$this->_req_action];
1384
-        $post_type_object = $this->_cpt_object;
1385
-        $title            = $post_type_object->labels->add_new_item;
1386
-        $post    = $post = get_default_post_to_edit($this->_cpt_routes[$this->_req_action], true);
1387
-        add_action('admin_print_styles', array($this, 'add_new_admin_page_global'));
1388
-        //modify the default editor title field with default title.
1389
-        add_filter('enter_title_here', array($this, 'add_custom_editor_default_title'), 10);
1390
-        $this->loadEditorTemplate(true);
1391
-    }
1392
-
1393
-
1394
-    /**
1395
-     * Enqueues auto-save and loads the editor template
1396
-     *
1397
-     * @param bool $creating
1398
-     */
1399
-    private function loadEditorTemplate($creating = true) {
1400
-        global $post, $title, $is_IE, $post_type, $post_type_object;
1401
-        //these vars are used by the template
1402
-        $editing = true;
1403
-        $post_ID = $post->ID;
1404
-        if (apply_filters('FHEE__EE_Admin_Page_CPT___create_new_cpt_item__replace_editor', false, $post) === false) {
1405
-            //only enqueue autosave when creating event (necessary to get permalink/url generated)
1406
-            //otherwise EE doesn't support autosave fully, so to prevent user confusion we disable it in edit context.
1407
-            if ($creating) {
1408
-                wp_enqueue_script('autosave');
1409
-            } else {
1410
-                if (isset($this->_cpt_routes[$this->_req_data['action']])
1411
-                    && ! isset($this->_labels['hide_add_button_on_cpt_route'][$this->_req_data['action']])
1412
-                ) {
1413
-                    $create_new_action = apply_filters('FHEE__EE_Admin_Page_CPT___edit_cpt_item__create_new_action',
1414
-                        'create_new', $this);
1415
-                    $post_new_file = EE_Admin_Page::add_query_args_and_nonce(array(
1416
-                        'action' => $create_new_action,
1417
-                        'page'   => $this->page_slug,
1418
-                    ), 'admin.php');
1419
-                }
1420
-            }
1421
-            include_once WP_ADMIN_PATH . 'edit-form-advanced.php';
1422
-        }
1423
-    }
1424
-
1425
-
1426
-
1427
-    public function add_new_admin_page_global()
1428
-    {
1429
-        $admin_page = ! empty($this->_req_data['post']) ? 'post-php' : 'post-new-php';
1430
-        ?>
1326
+		$messages[$post->post_type] = array(
1327
+			0 => '', //Unused. Messages start at index 1.
1328
+			1 => sprintf(
1329
+				__('%1$s updated. %2$sView %1$s%3$s', 'event_espresso'),
1330
+				$this->_cpt_object->labels->singular_name,
1331
+				'<a href="' . esc_url(get_permalink($id)) . '">',
1332
+				'</a>'
1333
+			),
1334
+			2 => __('Custom field updated'),
1335
+			3 => __('Custom field deleted.'),
1336
+			4 => sprintf(__('%1$s updated.', 'event_espresso'), $this->_cpt_object->labels->singular_name),
1337
+			5 => isset($_GET['revision']) ? sprintf(__('%s restored to revision from %s', 'event_espresso'),
1338
+				$this->_cpt_object->labels->singular_name, wp_post_revision_title((int)$_GET['revision'], false))
1339
+				: false,
1340
+			6 => sprintf(
1341
+				__('%1$s published. %2$sView %1$s%3$s', 'event_espresso'),
1342
+				$this->_cpt_object->labels->singular_name,
1343
+				'<a href="' . esc_url(get_permalink($id)) . '">',
1344
+				'</a>'
1345
+			),
1346
+			7 => sprintf(__('%1$s saved.', 'event_espresso'), $this->_cpt_object->labels->singular_name),
1347
+			8 => sprintf(
1348
+				__('%1$s submitted. %2$sPreview %1$s%3$s', 'event_espresso'),
1349
+				$this->_cpt_object->labels->singular_name,
1350
+				'<a target="_blank" href="' . esc_url(add_query_arg('preview', 'true', get_permalink($id))) . '">',
1351
+				'</a>'
1352
+			),
1353
+			9 => sprintf(
1354
+				__('%1$s scheduled for: %2$s. %3$s">Preview %1$s%3$s', 'event_espresso'),
1355
+				$this->_cpt_object->labels->singular_name,
1356
+				'<strong>' . date_i18n(__('M j, Y @ G:i'), strtotime($post->post_date)) . '</strong>',
1357
+				'<a target="_blank" href="' . esc_url(get_permalink($id)),
1358
+				'</a>'
1359
+			),
1360
+			10 => sprintf(
1361
+				__('%1$s draft updated. %2$s">Preview page%3$s', 'event_espresso'),
1362
+				$this->_cpt_object->labels->singular_name,
1363
+				'<a target="_blank" href="' . esc_url(add_query_arg('preview', 'true', get_permalink($id))),
1364
+				'</a>'
1365
+			),
1366
+		);
1367
+		return $messages;
1368
+	}
1369
+
1370
+
1371
+
1372
+	/**
1373
+	 * default method for the 'create_new' route for cpt admin pages.
1374
+	 * For reference what to include in here, see wp-admin/post-new.php
1375
+	 *
1376
+	 * @access  protected
1377
+	 * @return void
1378
+	 */
1379
+	protected function _create_new_cpt_item()
1380
+	{
1381
+		// gather template vars for WP_ADMIN_PATH . 'edit-form-advanced.php'
1382
+		global $post, $title, $is_IE, $post_type, $post_type_object;
1383
+		$post_type        = $this->_cpt_routes[$this->_req_action];
1384
+		$post_type_object = $this->_cpt_object;
1385
+		$title            = $post_type_object->labels->add_new_item;
1386
+		$post    = $post = get_default_post_to_edit($this->_cpt_routes[$this->_req_action], true);
1387
+		add_action('admin_print_styles', array($this, 'add_new_admin_page_global'));
1388
+		//modify the default editor title field with default title.
1389
+		add_filter('enter_title_here', array($this, 'add_custom_editor_default_title'), 10);
1390
+		$this->loadEditorTemplate(true);
1391
+	}
1392
+
1393
+
1394
+	/**
1395
+	 * Enqueues auto-save and loads the editor template
1396
+	 *
1397
+	 * @param bool $creating
1398
+	 */
1399
+	private function loadEditorTemplate($creating = true) {
1400
+		global $post, $title, $is_IE, $post_type, $post_type_object;
1401
+		//these vars are used by the template
1402
+		$editing = true;
1403
+		$post_ID = $post->ID;
1404
+		if (apply_filters('FHEE__EE_Admin_Page_CPT___create_new_cpt_item__replace_editor', false, $post) === false) {
1405
+			//only enqueue autosave when creating event (necessary to get permalink/url generated)
1406
+			//otherwise EE doesn't support autosave fully, so to prevent user confusion we disable it in edit context.
1407
+			if ($creating) {
1408
+				wp_enqueue_script('autosave');
1409
+			} else {
1410
+				if (isset($this->_cpt_routes[$this->_req_data['action']])
1411
+					&& ! isset($this->_labels['hide_add_button_on_cpt_route'][$this->_req_data['action']])
1412
+				) {
1413
+					$create_new_action = apply_filters('FHEE__EE_Admin_Page_CPT___edit_cpt_item__create_new_action',
1414
+						'create_new', $this);
1415
+					$post_new_file = EE_Admin_Page::add_query_args_and_nonce(array(
1416
+						'action' => $create_new_action,
1417
+						'page'   => $this->page_slug,
1418
+					), 'admin.php');
1419
+				}
1420
+			}
1421
+			include_once WP_ADMIN_PATH . 'edit-form-advanced.php';
1422
+		}
1423
+	}
1424
+
1425
+
1426
+
1427
+	public function add_new_admin_page_global()
1428
+	{
1429
+		$admin_page = ! empty($this->_req_data['post']) ? 'post-php' : 'post-new-php';
1430
+		?>
1431 1431
         <script type="text/javascript">
1432 1432
             adminpage = '<?php echo $admin_page; ?>';
1433 1433
         </script>
1434 1434
         <?php
1435
-    }
1436
-
1437
-
1438
-
1439
-    /**
1440
-     * default method for the 'edit' route for cpt admin pages
1441
-     * For reference on what to put in here, refer to wp-admin/post.php
1442
-     *
1443
-     * @access protected
1444
-     * @return string   template for edit cpt form
1445
-     */
1446
-    protected function _edit_cpt_item()
1447
-    {
1448
-        global $post, $title, $is_IE, $post_type, $post_type_object;
1449
-        $post_id = isset($this->_req_data['post']) ? $this->_req_data['post'] : null;
1450
-        $post = ! empty($post_id) ? get_post($post_id, OBJECT, 'edit') : null;
1451
-        if (empty ($post)) {
1452
-            wp_die(__('You attempted to edit an item that doesn&#8217;t exist. Perhaps it was deleted?'));
1453
-        }
1454
-        if ( ! empty($_GET['get-post-lock'])) {
1455
-            wp_set_post_lock($post_id);
1456
-            wp_redirect(get_edit_post_link($post_id, 'url'));
1457
-            exit();
1458
-        }
1459
-
1460
-        // template vars for WP_ADMIN_PATH . 'edit-form-advanced.php'
1461
-        $post_type        = $this->_cpt_routes[$this->_req_action];
1462
-        $post_type_object = $this->_cpt_object;
1463
-
1464
-        if ( ! wp_check_post_lock($post->ID)) {
1465
-            wp_set_post_lock($post->ID);
1466
-        }
1467
-        add_action('admin_footer', '_admin_notice_post_locked');
1468
-        if (post_type_supports($this->_cpt_routes[$this->_req_action], 'comments')) {
1469
-            wp_enqueue_script('admin-comments');
1470
-            enqueue_comment_hotkeys_js();
1471
-        }
1472
-        add_action('admin_print_styles', array($this, 'add_new_admin_page_global'));
1473
-        //modify the default editor title field with default title.
1474
-        add_filter('enter_title_here', array($this, 'add_custom_editor_default_title'), 10);
1475
-        $this->loadEditorTemplate(false);
1476
-    }
1477
-
1478
-
1479
-
1480
-    /**
1481
-     * some getters
1482
-     */
1483
-    /**
1484
-     * This returns the protected _cpt_model_obj property
1485
-     *
1486
-     * @return EE_CPT_Base
1487
-     */
1488
-    public function get_cpt_model_obj()
1489
-    {
1490
-        return $this->_cpt_model_obj;
1491
-    }
1435
+	}
1436
+
1437
+
1438
+
1439
+	/**
1440
+	 * default method for the 'edit' route for cpt admin pages
1441
+	 * For reference on what to put in here, refer to wp-admin/post.php
1442
+	 *
1443
+	 * @access protected
1444
+	 * @return string   template for edit cpt form
1445
+	 */
1446
+	protected function _edit_cpt_item()
1447
+	{
1448
+		global $post, $title, $is_IE, $post_type, $post_type_object;
1449
+		$post_id = isset($this->_req_data['post']) ? $this->_req_data['post'] : null;
1450
+		$post = ! empty($post_id) ? get_post($post_id, OBJECT, 'edit') : null;
1451
+		if (empty ($post)) {
1452
+			wp_die(__('You attempted to edit an item that doesn&#8217;t exist. Perhaps it was deleted?'));
1453
+		}
1454
+		if ( ! empty($_GET['get-post-lock'])) {
1455
+			wp_set_post_lock($post_id);
1456
+			wp_redirect(get_edit_post_link($post_id, 'url'));
1457
+			exit();
1458
+		}
1459
+
1460
+		// template vars for WP_ADMIN_PATH . 'edit-form-advanced.php'
1461
+		$post_type        = $this->_cpt_routes[$this->_req_action];
1462
+		$post_type_object = $this->_cpt_object;
1463
+
1464
+		if ( ! wp_check_post_lock($post->ID)) {
1465
+			wp_set_post_lock($post->ID);
1466
+		}
1467
+		add_action('admin_footer', '_admin_notice_post_locked');
1468
+		if (post_type_supports($this->_cpt_routes[$this->_req_action], 'comments')) {
1469
+			wp_enqueue_script('admin-comments');
1470
+			enqueue_comment_hotkeys_js();
1471
+		}
1472
+		add_action('admin_print_styles', array($this, 'add_new_admin_page_global'));
1473
+		//modify the default editor title field with default title.
1474
+		add_filter('enter_title_here', array($this, 'add_custom_editor_default_title'), 10);
1475
+		$this->loadEditorTemplate(false);
1476
+	}
1477
+
1478
+
1479
+
1480
+	/**
1481
+	 * some getters
1482
+	 */
1483
+	/**
1484
+	 * This returns the protected _cpt_model_obj property
1485
+	 *
1486
+	 * @return EE_CPT_Base
1487
+	 */
1488
+	public function get_cpt_model_obj()
1489
+	{
1490
+		return $this->_cpt_model_obj;
1491
+	}
1492 1492
 
1493 1493
 }
Please login to merge, or discard this patch.
Spacing   +25 added lines, -25 removed lines patch added patch discarded remove patch
@@ -239,7 +239,7 @@  discard block
 block discarded – undo
239 239
      */
240 240
     protected function _register_autosave_containers($ids)
241 241
     {
242
-        $this->_autosave_containers = array_merge($this->_autosave_fields, (array)$ids);
242
+        $this->_autosave_containers = array_merge($this->_autosave_fields, (array) $ids);
243 243
     }
244 244
 
245 245
 
@@ -286,7 +286,7 @@  discard block
 block discarded – undo
286 286
         //filter _autosave_containers
287 287
         $containers = apply_filters('FHEE__EE_Admin_Page_CPT___load_autosave_scripts_styles__containers',
288 288
             $this->_autosave_containers, $this);
289
-        $containers = apply_filters('FHEE__EE_Admin_Page_CPT__' . get_class($this) . '___load_autosave_scripts_styles__containers',
289
+        $containers = apply_filters('FHEE__EE_Admin_Page_CPT__'.get_class($this).'___load_autosave_scripts_styles__containers',
290 290
             $containers, $this);
291 291
 
292 292
         wp_localize_script('event_editor_js', 'EE_AUTOSAVE_IDS',
@@ -398,7 +398,7 @@  discard block
 block discarded – undo
398 398
         // This is for any plugins that are doing things properly
399 399
         // and hooking into the load page hook for core wp cpt routes.
400 400
         global $pagenow;
401
-        do_action('load-' . $pagenow);
401
+        do_action('load-'.$pagenow);
402 402
         $this->modify_current_screen();
403 403
         add_action('admin_enqueue_scripts', array($this, 'setup_autosave_hooks'), 30);
404 404
         //we route REALLY early.
@@ -429,8 +429,8 @@  discard block
 block discarded – undo
429 429
                 'admin.php?page=espresso_registrations&action=contact_list',
430 430
             ),
431 431
             1 => array(
432
-                'edit.php?post_type=' . $this->_cpt_object->name,
433
-                'admin.php?page=' . $this->_cpt_object->name,
432
+                'edit.php?post_type='.$this->_cpt_object->name,
433
+                'admin.php?page='.$this->_cpt_object->name,
434 434
             ),
435 435
         );
436 436
         foreach ($routes_to_match as $route_matches) {
@@ -458,7 +458,7 @@  discard block
 block discarded – undo
458 458
         $cpt_has_support = ! empty($cpt_args['page_templates']);
459 459
 
460 460
         //if the installed version of WP is > 4.7 we do some additional checks.
461
-        if (RecommendedVersions::compareWordPressVersion('4.7','>=')) {
461
+        if (RecommendedVersions::compareWordPressVersion('4.7', '>=')) {
462 462
             $post_templates = wp_get_theme()->get_post_templates();
463 463
             //if there are $post_templates for this cpt, then we return false for this method because
464 464
             //that means we aren't going to load our page template manager and leave that up to the native
@@ -481,7 +481,7 @@  discard block
 block discarded – undo
481 481
         global $post;
482 482
         $template = '';
483 483
 
484
-        if (RecommendedVersions::compareWordPressVersion('4.7','>=')) {
484
+        if (RecommendedVersions::compareWordPressVersion('4.7', '>=')) {
485 485
             $page_template_count = count(get_page_templates());
486 486
         } else {
487 487
             $page_template_count = count(get_page_templates($post));
@@ -518,7 +518,7 @@  discard block
 block discarded – undo
518 518
         $post = get_post($id);
519 519
         if ('publish' !== get_post_status($post)) {
520 520
             //include shims for the `get_preview_post_link` function
521
-            require_once( EE_CORE . 'wordpress-shims.php' );
521
+            require_once(EE_CORE.'wordpress-shims.php');
522 522
             $return .= '<span_id="view-post-btn"><a target="_blank" href="'
523 523
                        . get_preview_post_link($id)
524 524
                        . '" class="button button-small">'
@@ -556,7 +556,7 @@  discard block
 block discarded – undo
556 556
             $template_args['statuses']         = $statuses;
557 557
         }
558 558
 
559
-        $template = EE_ADMIN_TEMPLATE . 'status_dropdown.template.php';
559
+        $template = EE_ADMIN_TEMPLATE.'status_dropdown.template.php';
560 560
         EEH_Template::display_template($template, $template_args);
561 561
     }
562 562
 
@@ -610,7 +610,7 @@  discard block
 block discarded – undo
610 610
             $this->_template_args['success'] = true;
611 611
         }
612 612
         do_action('AHEE__EE_Admin_Page_CPT__do_extra_autosave_stuff__global_after', $this);
613
-        do_action('AHEE__EE_Admin_Page_CPT__do_extra_autosave_stuff__after_' . get_class($this), $this);
613
+        do_action('AHEE__EE_Admin_Page_CPT__do_extra_autosave_stuff__after_'.get_class($this), $this);
614 614
         //now let's return json
615 615
         $this->_return_json();
616 616
     }
@@ -1013,7 +1013,7 @@  discard block
 block discarded – undo
1013 1013
         //global action
1014 1014
         do_action('AHEE_EE_Admin_Page_CPT__restore_revision', $post_id, $revision_id);
1015 1015
         //class specific action so you can limit hooking into a specific page.
1016
-        do_action('AHEE_EE_Admin_Page_CPT_' . get_class($this) . '__restore_revision', $post_id, $revision_id);
1016
+        do_action('AHEE_EE_Admin_Page_CPT_'.get_class($this).'__restore_revision', $post_id, $revision_id);
1017 1017
     }
1018 1018
 
1019 1019
 
@@ -1091,7 +1091,7 @@  discard block
 block discarded – undo
1091 1091
         if ( ! empty($id) && get_option('permalink_structure') !== '') {
1092 1092
             $post = get_post($id);
1093 1093
             if (isset($post->post_type) && $this->page_slug === $post->post_type) {
1094
-                $shortlink = home_url('?p=' . $post->ID);
1094
+                $shortlink = home_url('?p='.$post->ID);
1095 1095
             }
1096 1096
         }
1097 1097
         return $shortlink;
@@ -1126,11 +1126,11 @@  discard block
 block discarded – undo
1126 1126
      */
1127 1127
     public function cpt_post_form_hidden_input()
1128 1128
     {
1129
-        echo '<input type="hidden" name="ee_cpt_item_redirect_url" value="' . $this->_admin_base_url . '" />';
1129
+        echo '<input type="hidden" name="ee_cpt_item_redirect_url" value="'.$this->_admin_base_url.'" />';
1130 1130
         //we're also going to add the route value and the current page so we can direct autosave parsing correctly
1131 1131
         echo '<div id="ee-cpt-hidden-inputs">';
1132
-        echo '<input type="hidden" id="current_route" name="current_route" value="' . $this->_current_view . '" />';
1133
-        echo '<input type="hidden" id="current_page" name="current_page" value="' . $this->page_slug . '" />';
1132
+        echo '<input type="hidden" id="current_route" name="current_route" value="'.$this->_current_view.'" />';
1133
+        echo '<input type="hidden" id="current_page" name="current_page" value="'.$this->page_slug.'" />';
1134 1134
         echo '</div>';
1135 1135
     }
1136 1136
 
@@ -1217,7 +1217,7 @@  discard block
 block discarded – undo
1217 1217
         $this->_set_model_object($post->ID, true);
1218 1218
 
1219 1219
         //returns something like `trash_event` or `trash_attendee` or `trash_venue`
1220
-        $action = 'trash_' . str_replace('ee_', '', strtolower(get_class($this->_cpt_model_obj)));
1220
+        $action = 'trash_'.str_replace('ee_', '', strtolower(get_class($this->_cpt_model_obj)));
1221 1221
 
1222 1222
         return EE_Admin_Page::add_query_args_and_nonce(
1223 1223
             array(
@@ -1328,39 +1328,39 @@  discard block
 block discarded – undo
1328 1328
             1 => sprintf(
1329 1329
                 __('%1$s updated. %2$sView %1$s%3$s', 'event_espresso'),
1330 1330
                 $this->_cpt_object->labels->singular_name,
1331
-                '<a href="' . esc_url(get_permalink($id)) . '">',
1331
+                '<a href="'.esc_url(get_permalink($id)).'">',
1332 1332
                 '</a>'
1333 1333
             ),
1334 1334
             2 => __('Custom field updated'),
1335 1335
             3 => __('Custom field deleted.'),
1336 1336
             4 => sprintf(__('%1$s updated.', 'event_espresso'), $this->_cpt_object->labels->singular_name),
1337 1337
             5 => isset($_GET['revision']) ? sprintf(__('%s restored to revision from %s', 'event_espresso'),
1338
-                $this->_cpt_object->labels->singular_name, wp_post_revision_title((int)$_GET['revision'], false))
1338
+                $this->_cpt_object->labels->singular_name, wp_post_revision_title((int) $_GET['revision'], false))
1339 1339
                 : false,
1340 1340
             6 => sprintf(
1341 1341
                 __('%1$s published. %2$sView %1$s%3$s', 'event_espresso'),
1342 1342
                 $this->_cpt_object->labels->singular_name,
1343
-                '<a href="' . esc_url(get_permalink($id)) . '">',
1343
+                '<a href="'.esc_url(get_permalink($id)).'">',
1344 1344
                 '</a>'
1345 1345
             ),
1346 1346
             7 => sprintf(__('%1$s saved.', 'event_espresso'), $this->_cpt_object->labels->singular_name),
1347 1347
             8 => sprintf(
1348 1348
                 __('%1$s submitted. %2$sPreview %1$s%3$s', 'event_espresso'),
1349 1349
                 $this->_cpt_object->labels->singular_name,
1350
-                '<a target="_blank" href="' . esc_url(add_query_arg('preview', 'true', get_permalink($id))) . '">',
1350
+                '<a target="_blank" href="'.esc_url(add_query_arg('preview', 'true', get_permalink($id))).'">',
1351 1351
                 '</a>'
1352 1352
             ),
1353 1353
             9 => sprintf(
1354 1354
                 __('%1$s scheduled for: %2$s. %3$s">Preview %1$s%3$s', 'event_espresso'),
1355 1355
                 $this->_cpt_object->labels->singular_name,
1356
-                '<strong>' . date_i18n(__('M j, Y @ G:i'), strtotime($post->post_date)) . '</strong>',
1357
-                '<a target="_blank" href="' . esc_url(get_permalink($id)),
1356
+                '<strong>'.date_i18n(__('M j, Y @ G:i'), strtotime($post->post_date)).'</strong>',
1357
+                '<a target="_blank" href="'.esc_url(get_permalink($id)),
1358 1358
                 '</a>'
1359 1359
             ),
1360 1360
             10 => sprintf(
1361 1361
                 __('%1$s draft updated. %2$s">Preview page%3$s', 'event_espresso'),
1362 1362
                 $this->_cpt_object->labels->singular_name,
1363
-                '<a target="_blank" href="' . esc_url(add_query_arg('preview', 'true', get_permalink($id))),
1363
+                '<a target="_blank" href="'.esc_url(add_query_arg('preview', 'true', get_permalink($id))),
1364 1364
                 '</a>'
1365 1365
             ),
1366 1366
         );
@@ -1383,7 +1383,7 @@  discard block
 block discarded – undo
1383 1383
         $post_type        = $this->_cpt_routes[$this->_req_action];
1384 1384
         $post_type_object = $this->_cpt_object;
1385 1385
         $title            = $post_type_object->labels->add_new_item;
1386
-        $post    = $post = get_default_post_to_edit($this->_cpt_routes[$this->_req_action], true);
1386
+        $post = $post = get_default_post_to_edit($this->_cpt_routes[$this->_req_action], true);
1387 1387
         add_action('admin_print_styles', array($this, 'add_new_admin_page_global'));
1388 1388
         //modify the default editor title field with default title.
1389 1389
         add_filter('enter_title_here', array($this, 'add_custom_editor_default_title'), 10);
@@ -1418,7 +1418,7 @@  discard block
 block discarded – undo
1418 1418
                     ), 'admin.php');
1419 1419
                 }
1420 1420
             }
1421
-            include_once WP_ADMIN_PATH . 'edit-form-advanced.php';
1421
+            include_once WP_ADMIN_PATH.'edit-form-advanced.php';
1422 1422
         }
1423 1423
     }
1424 1424
 
Please login to merge, or discard this patch.
core/db_classes/EE_Base_Class.class.php 2 patches
Indentation   +3141 added lines, -3141 removed lines patch added patch discarded remove patch
@@ -15,3147 +15,3147 @@
 block discarded – undo
15 15
 abstract class EE_Base_Class
16 16
 {
17 17
 
18
-    /**
19
-     * This is an array of the original properties and values provided during construction
20
-     * of this model object. (keys are model field names, values are their values).
21
-     * This list is important to remember so that when we are merging data from the db, we know
22
-     * which values to override and which to not override.
23
-     *
24
-     * @var array
25
-     */
26
-    protected $_props_n_values_provided_in_constructor;
27
-
28
-    /**
29
-     * Timezone
30
-     * This gets set by the "set_timezone()" method so that we know what timezone incoming strings|timestamps are in.
31
-     * This can also be used before a get to set what timezone you want strings coming out of the object to be in.  NOT
32
-     * all EE_Base_Class child classes use this property but any that use a EE_Datetime_Field data type will have
33
-     * access to it.
34
-     *
35
-     * @var string
36
-     */
37
-    protected $_timezone;
38
-
39
-    /**
40
-     * date format
41
-     * pattern or format for displaying dates
42
-     *
43
-     * @var string $_dt_frmt
44
-     */
45
-    protected $_dt_frmt;
46
-
47
-    /**
48
-     * time format
49
-     * pattern or format for displaying time
50
-     *
51
-     * @var string $_tm_frmt
52
-     */
53
-    protected $_tm_frmt;
54
-
55
-    /**
56
-     * This property is for holding a cached array of object properties indexed by property name as the key.
57
-     * The purpose of this is for setting a cache on properties that may have calculated values after a
58
-     * prepare_for_get.  That way the cache can be checked first and the calculated property returned instead of having
59
-     * to recalculate. Used by _set_cached_property() and _get_cached_property() methods.
60
-     *
61
-     * @var array
62
-     */
63
-    protected $_cached_properties = array();
64
-
65
-    /**
66
-     * An array containing keys of the related model, and values are either an array of related mode objects or a
67
-     * single
68
-     * related model object. see the model's _model_relations. The keys should match those specified. And if the
69
-     * relation is of type EE_Belongs_To (or one of its children), then there should only be ONE related model object,
70
-     * all others have an array)
71
-     *
72
-     * @var array
73
-     */
74
-    protected $_model_relations = array();
75
-
76
-    /**
77
-     * Array where keys are field names (see the model's _fields property) and values are their values. To see what
78
-     * their types should be, look at what that field object returns on its prepare_for_get and prepare_for_set methods)
79
-     *
80
-     * @var array
81
-     */
82
-    protected $_fields = array();
83
-
84
-    /**
85
-     * @var boolean indicating whether or not this model object is intended to ever be saved
86
-     * For example, we might create model objects intended to only be used for the duration
87
-     * of this request and to be thrown away, and if they were accidentally saved
88
-     * it would be a bug.
89
-     */
90
-    protected $_allow_persist = true;
91
-
92
-    /**
93
-     * @var boolean indicating whether or not this model object's properties have changed since construction
94
-     */
95
-    protected $_has_changes = false;
96
-
97
-    /**
98
-     * @var EEM_Base
99
-     */
100
-    protected $_model;
101
-
102
-    /**
103
-     * This is a cache of results from custom selections done on a query that constructs this entity. The only purpose
104
-     * for these values is for retrieval of the results, they are not further queryable and they are not persisted to
105
-     * the db.  They also do not automatically update if there are any changes to the data that produced their results.
106
-     * The format is a simple array of field_alias => field_value.  So for instance if a custom select was something
107
-     * like,  "Select COUNT(Registration.REG_ID) as Registration_Count ...", then the resulting value will be in this
108
-     * array as:
109
-     * array(
110
-     *  'Registration_Count' => 24
111
-     * );
112
-     * Note: if the custom select configuration for the query included a data type, the value will be in the data type
113
-     * provided for the query (@see EventEspresso\core\domain\values\model\CustomSelects::__construct phpdocs for more
114
-     * info)
115
-     *
116
-     * @var array
117
-     */
118
-    protected $custom_selection_results = array();
119
-
120
-
121
-    /**
122
-     * basic constructor for Event Espresso classes, performs any necessary initialization, and verifies it's children
123
-     * play nice
124
-     *
125
-     * @param array   $fieldValues                             where each key is a field (ie, array key in the 2nd
126
-     *                                                         layer of the model's _fields array, (eg, EVT_ID,
127
-     *                                                         TXN_amount, QST_name, etc) and values are their values
128
-     * @param boolean $bydb                                    a flag for setting if the class is instantiated by the
129
-     *                                                         corresponding db model or not.
130
-     * @param string  $timezone                                indicate what timezone you want any datetime fields to
131
-     *                                                         be in when instantiating a EE_Base_Class object.
132
-     * @param array   $date_formats                            An array of date formats to set on construct where first
133
-     *                                                         value is the date_format and second value is the time
134
-     *                                                         format.
135
-     * @throws InvalidArgumentException
136
-     * @throws InvalidInterfaceException
137
-     * @throws InvalidDataTypeException
138
-     * @throws EE_Error
139
-     * @throws ReflectionException
140
-     */
141
-    protected function __construct($fieldValues = array(), $bydb = false, $timezone = '', $date_formats = array())
142
-    {
143
-        $className = get_class($this);
144
-        do_action("AHEE__{$className}__construct", $this, $fieldValues);
145
-        $model        = $this->get_model();
146
-        $model_fields = $model->field_settings(false);
147
-        // ensure $fieldValues is an array
148
-        $fieldValues = is_array($fieldValues) ? $fieldValues : array($fieldValues);
149
-        // verify client code has not passed any invalid field names
150
-        foreach ($fieldValues as $field_name => $field_value) {
151
-            if (! isset($model_fields[ $field_name ])) {
152
-                throw new EE_Error(
153
-                    sprintf(
154
-                        esc_html__(
155
-                            'Invalid field (%s) passed to constructor of %s. Allowed fields are :%s',
156
-                            'event_espresso'
157
-                        ),
158
-                        $field_name,
159
-                        get_class($this),
160
-                        implode(', ', array_keys($model_fields))
161
-                    )
162
-                );
163
-            }
164
-        }
165
-        $this->_timezone = EEH_DTT_Helper::get_valid_timezone_string($timezone);
166
-        if (! empty($date_formats) && is_array($date_formats)) {
167
-            list($this->_dt_frmt, $this->_tm_frmt) = $date_formats;
168
-        } else {
169
-            //set default formats for date and time
170
-            $this->_dt_frmt = (string) get_option('date_format', 'Y-m-d');
171
-            $this->_tm_frmt = (string) get_option('time_format', 'g:i a');
172
-        }
173
-        //if db model is instantiating
174
-        if ($bydb) {
175
-            //client code has indicated these field values are from the database
176
-            foreach ($model_fields as $fieldName => $field) {
177
-                $this->set_from_db(
178
-                    $fieldName,
179
-                    isset($fieldValues[ $fieldName ]) ? $fieldValues[ $fieldName ] : null
180
-                );
181
-            }
182
-        } else {
183
-            //we're constructing a brand
184
-            //new instance of the model object. Generally, this means we'll need to do more field validation
185
-            foreach ($model_fields as $fieldName => $field) {
186
-                $this->set(
187
-                    $fieldName,
188
-                    isset($fieldValues[ $fieldName ]) ? $fieldValues[ $fieldName ] : null, true
189
-                );
190
-            }
191
-        }
192
-        //remember what values were passed to this constructor
193
-        $this->_props_n_values_provided_in_constructor = $fieldValues;
194
-        //remember in entity mapper
195
-        if (! $bydb && $model->has_primary_key_field() && $this->ID()) {
196
-            $model->add_to_entity_map($this);
197
-        }
198
-        //setup all the relations
199
-        foreach ($model->relation_settings() as $relation_name => $relation_obj) {
200
-            if ($relation_obj instanceof EE_Belongs_To_Relation) {
201
-                $this->_model_relations[ $relation_name ] = null;
202
-            } else {
203
-                $this->_model_relations[ $relation_name ] = array();
204
-            }
205
-        }
206
-        /**
207
-         * Action done at the end of each model object construction
208
-         *
209
-         * @param EE_Base_Class $this the model object just created
210
-         */
211
-        do_action('AHEE__EE_Base_Class__construct__finished', $this);
212
-    }
213
-
214
-
215
-    /**
216
-     * Gets whether or not this model object is allowed to persist/be saved to the database.
217
-     *
218
-     * @return boolean
219
-     */
220
-    public function allow_persist()
221
-    {
222
-        return $this->_allow_persist;
223
-    }
224
-
225
-
226
-    /**
227
-     * Sets whether or not this model object should be allowed to be saved to the DB.
228
-     * Normally once this is set to FALSE you wouldn't set it back to TRUE, unless
229
-     * you got new information that somehow made you change your mind.
230
-     *
231
-     * @param boolean $allow_persist
232
-     * @return boolean
233
-     */
234
-    public function set_allow_persist($allow_persist)
235
-    {
236
-        return $this->_allow_persist = $allow_persist;
237
-    }
238
-
239
-
240
-    /**
241
-     * Gets the field's original value when this object was constructed during this request.
242
-     * This can be helpful when determining if a model object has changed or not
243
-     *
244
-     * @param string $field_name
245
-     * @return mixed|null
246
-     * @throws ReflectionException
247
-     * @throws InvalidArgumentException
248
-     * @throws InvalidInterfaceException
249
-     * @throws InvalidDataTypeException
250
-     * @throws EE_Error
251
-     */
252
-    public function get_original($field_name)
253
-    {
254
-        if (isset($this->_props_n_values_provided_in_constructor[ $field_name ])
255
-            && $field_settings = $this->get_model()->field_settings_for($field_name)
256
-        ) {
257
-            return $field_settings->prepare_for_get($this->_props_n_values_provided_in_constructor[ $field_name ]);
258
-        }
259
-        return null;
260
-    }
261
-
262
-
263
-    /**
264
-     * @param EE_Base_Class $obj
265
-     * @return string
266
-     */
267
-    public function get_class($obj)
268
-    {
269
-        return get_class($obj);
270
-    }
271
-
272
-
273
-    /**
274
-     * Overrides parent because parent expects old models.
275
-     * This also doesn't do any validation, and won't work for serialized arrays
276
-     *
277
-     * @param    string $field_name
278
-     * @param    mixed  $field_value
279
-     * @param bool      $use_default
280
-     * @throws InvalidArgumentException
281
-     * @throws InvalidInterfaceException
282
-     * @throws InvalidDataTypeException
283
-     * @throws EE_Error
284
-     * @throws ReflectionException
285
-     * @throws ReflectionException
286
-     * @throws ReflectionException
287
-     */
288
-    public function set($field_name, $field_value, $use_default = false)
289
-    {
290
-        // if not using default and nothing has changed, and object has already been setup (has ID),
291
-        // then don't do anything
292
-        if (
293
-            ! $use_default
294
-            && $this->_fields[ $field_name ] === $field_value
295
-            && $this->ID()
296
-        ) {
297
-            return;
298
-        }
299
-        $model              = $this->get_model();
300
-        $this->_has_changes = true;
301
-        $field_obj          = $model->field_settings_for($field_name);
302
-        if ($field_obj instanceof EE_Model_Field_Base) {
303
-            //			if ( method_exists( $field_obj, 'set_timezone' )) {
304
-            if ($field_obj instanceof EE_Datetime_Field) {
305
-                $field_obj->set_timezone($this->_timezone);
306
-                $field_obj->set_date_format($this->_dt_frmt);
307
-                $field_obj->set_time_format($this->_tm_frmt);
308
-            }
309
-            $holder_of_value = $field_obj->prepare_for_set($field_value);
310
-            //should the value be null?
311
-            if (($field_value === null || $holder_of_value === null || $holder_of_value === '') && $use_default) {
312
-                $this->_fields[ $field_name ] = $field_obj->get_default_value();
313
-                /**
314
-                 * To save having to refactor all the models, if a default value is used for a
315
-                 * EE_Datetime_Field, and that value is not null nor is it a DateTime
316
-                 * object.  Then let's do a set again to ensure that it becomes a DateTime
317
-                 * object.
318
-                 *
319
-                 * @since 4.6.10+
320
-                 */
321
-                if (
322
-                    $field_obj instanceof EE_Datetime_Field
323
-                    && $this->_fields[ $field_name ] !== null
324
-                    && ! $this->_fields[ $field_name ] instanceof DateTime
325
-                ) {
326
-                    empty($this->_fields[ $field_name ])
327
-                        ? $this->set($field_name, time())
328
-                        : $this->set($field_name, $this->_fields[ $field_name ]);
329
-                }
330
-            } else {
331
-                $this->_fields[ $field_name ] = $holder_of_value;
332
-            }
333
-            //if we're not in the constructor...
334
-            //now check if what we set was a primary key
335
-            if (
336
-                //note: props_n_values_provided_in_constructor is only set at the END of the constructor
337
-                $this->_props_n_values_provided_in_constructor
338
-                && $field_value
339
-                && $field_name === $model->primary_key_name()
340
-            ) {
341
-                //if so, we want all this object's fields to be filled either with
342
-                //what we've explicitly set on this model
343
-                //or what we have in the db
344
-                // echo "setting primary key!";
345
-                $fields_on_model = self::_get_model(get_class($this))->field_settings();
346
-                $obj_in_db       = self::_get_model(get_class($this))->get_one_by_ID($field_value);
347
-                foreach ($fields_on_model as $field_obj) {
348
-                    if (! array_key_exists($field_obj->get_name(), $this->_props_n_values_provided_in_constructor)
349
-                        && $field_obj->get_name() !== $field_name
350
-                    ) {
351
-                        $this->set($field_obj->get_name(), $obj_in_db->get($field_obj->get_name()));
352
-                    }
353
-                }
354
-                //oh this model object has an ID? well make sure its in the entity mapper
355
-                $model->add_to_entity_map($this);
356
-            }
357
-            //let's unset any cache for this field_name from the $_cached_properties property.
358
-            $this->_clear_cached_property($field_name);
359
-        } else {
360
-            throw new EE_Error(
361
-                sprintf(
362
-                    esc_html__(
363
-                        'A valid EE_Model_Field_Base could not be found for the given field name: %s',
364
-                        'event_espresso'
365
-                    ),
366
-                    $field_name
367
-                )
368
-            );
369
-        }
370
-    }
371
-
372
-
373
-    /**
374
-     * Set custom select values for model.
375
-     *
376
-     * @param array $custom_select_values
377
-     */
378
-    public function setCustomSelectsValues(array $custom_select_values)
379
-    {
380
-        $this->custom_selection_results = $custom_select_values;
381
-    }
382
-
383
-
384
-    /**
385
-     * Returns the custom select value for the provided alias if its set.
386
-     * If not set, returns null.
387
-     *
388
-     * @param string $alias
389
-     * @return string|int|float|null
390
-     */
391
-    public function getCustomSelect($alias)
392
-    {
393
-        return isset($this->custom_selection_results[ $alias ])
394
-            ? $this->custom_selection_results[ $alias ]
395
-            : null;
396
-    }
397
-
398
-
399
-    /**
400
-     * This sets the field value on the db column if it exists for the given $column_name or
401
-     * saves it to EE_Extra_Meta if the given $column_name does not match a db column.
402
-     *
403
-     * @see EE_message::get_column_value for related documentation on the necessity of this method.
404
-     * @param string $field_name  Must be the exact column name.
405
-     * @param mixed  $field_value The value to set.
406
-     * @return int|bool @see EE_Base_Class::update_extra_meta() for return docs.
407
-     * @throws InvalidArgumentException
408
-     * @throws InvalidInterfaceException
409
-     * @throws InvalidDataTypeException
410
-     * @throws EE_Error
411
-     * @throws ReflectionException
412
-     */
413
-    public function set_field_or_extra_meta($field_name, $field_value)
414
-    {
415
-        if ($this->get_model()->has_field($field_name)) {
416
-            $this->set($field_name, $field_value);
417
-            return true;
418
-        }
419
-        //ensure this object is saved first so that extra meta can be properly related.
420
-        $this->save();
421
-        return $this->update_extra_meta($field_name, $field_value);
422
-    }
423
-
424
-
425
-    /**
426
-     * This retrieves the value of the db column set on this class or if that's not present
427
-     * it will attempt to retrieve from extra_meta if found.
428
-     * Example Usage:
429
-     * Via EE_Message child class:
430
-     * Due to the dynamic nature of the EE_messages system, EE_messengers will always have a "to",
431
-     * "from", "subject", and "content" field (as represented in the EE_Message schema), however they may
432
-     * also have additional main fields specific to the messenger.  The system accommodates those extra
433
-     * fields through the EE_Extra_Meta table.  This method allows for EE_messengers to retrieve the
434
-     * value for those extra fields dynamically via the EE_message object.
435
-     *
436
-     * @param  string $field_name expecting the fully qualified field name.
437
-     * @return mixed|null  value for the field if found.  null if not found.
438
-     * @throws ReflectionException
439
-     * @throws InvalidArgumentException
440
-     * @throws InvalidInterfaceException
441
-     * @throws InvalidDataTypeException
442
-     * @throws EE_Error
443
-     */
444
-    public function get_field_or_extra_meta($field_name)
445
-    {
446
-        if ($this->get_model()->has_field($field_name)) {
447
-            $column_value = $this->get($field_name);
448
-        } else {
449
-            //This isn't a column in the main table, let's see if it is in the extra meta.
450
-            $column_value = $this->get_extra_meta($field_name, true, null);
451
-        }
452
-        return $column_value;
453
-    }
454
-
455
-
456
-    /**
457
-     * See $_timezone property for description of what the timezone property is for.  This SETS the timezone internally
458
-     * for being able to reference what timezone we are running conversions on when converting TO the internal timezone
459
-     * (UTC Unix Timestamp) for the object OR when converting FROM the internal timezone (UTC Unix Timestamp). This is
460
-     * available to all child classes that may be using the EE_Datetime_Field for a field data type.
461
-     *
462
-     * @access public
463
-     * @param string $timezone A valid timezone string as described by @link http://www.php.net/manual/en/timezones.php
464
-     * @return void
465
-     * @throws InvalidArgumentException
466
-     * @throws InvalidInterfaceException
467
-     * @throws InvalidDataTypeException
468
-     * @throws EE_Error
469
-     * @throws ReflectionException
470
-     */
471
-    public function set_timezone($timezone = '')
472
-    {
473
-        $this->_timezone = EEH_DTT_Helper::get_valid_timezone_string($timezone);
474
-        //make sure we clear all cached properties because they won't be relevant now
475
-        $this->_clear_cached_properties();
476
-        //make sure we update field settings and the date for all EE_Datetime_Fields
477
-        $model_fields = $this->get_model()->field_settings(false);
478
-        foreach ($model_fields as $field_name => $field_obj) {
479
-            if ($field_obj instanceof EE_Datetime_Field) {
480
-                $field_obj->set_timezone($this->_timezone);
481
-                if (isset($this->_fields[ $field_name ]) && $this->_fields[ $field_name ] instanceof DateTime) {
482
-                    $this->_fields[ $field_name ]->setTimezone(new DateTimeZone($this->_timezone));
483
-                }
484
-            }
485
-        }
486
-    }
487
-
488
-
489
-    /**
490
-     * This just returns whatever is set for the current timezone.
491
-     *
492
-     * @access public
493
-     * @return string timezone string
494
-     */
495
-    public function get_timezone()
496
-    {
497
-        return $this->_timezone;
498
-    }
499
-
500
-
501
-    /**
502
-     * This sets the internal date format to what is sent in to be used as the new default for the class
503
-     * internally instead of wp set date format options
504
-     *
505
-     * @since 4.6
506
-     * @param string $format should be a format recognizable by PHP date() functions.
507
-     */
508
-    public function set_date_format($format)
509
-    {
510
-        $this->_dt_frmt = $format;
511
-        //clear cached_properties because they won't be relevant now.
512
-        $this->_clear_cached_properties();
513
-    }
514
-
515
-
516
-    /**
517
-     * This sets the internal time format string to what is sent in to be used as the new default for the
518
-     * class internally instead of wp set time format options.
519
-     *
520
-     * @since 4.6
521
-     * @param string $format should be a format recognizable by PHP date() functions.
522
-     */
523
-    public function set_time_format($format)
524
-    {
525
-        $this->_tm_frmt = $format;
526
-        //clear cached_properties because they won't be relevant now.
527
-        $this->_clear_cached_properties();
528
-    }
529
-
530
-
531
-    /**
532
-     * This returns the current internal set format for the date and time formats.
533
-     *
534
-     * @param bool $full           if true (default), then return the full format.  Otherwise will return an array
535
-     *                             where the first value is the date format and the second value is the time format.
536
-     * @return mixed string|array
537
-     */
538
-    public function get_format($full = true)
539
-    {
540
-        return $full ? $this->_dt_frmt . ' ' . $this->_tm_frmt : array($this->_dt_frmt, $this->_tm_frmt);
541
-    }
542
-
543
-
544
-    /**
545
-     * cache
546
-     * stores the passed model object on the current model object.
547
-     * In certain circumstances, we can use this cached model object instead of querying for another one entirely.
548
-     *
549
-     * @param string        $relationName    one of the keys in the _model_relations array on the model. Eg
550
-     *                                       'Registration' associated with this model object
551
-     * @param EE_Base_Class $object_to_cache that has a relation to this model object. (Eg, if this is a Transaction,
552
-     *                                       that could be a payment or a registration)
553
-     * @param null          $cache_id        a string or number that will be used as the key for any Belongs_To_Many
554
-     *                                       items which will be stored in an array on this object
555
-     * @throws ReflectionException
556
-     * @throws InvalidArgumentException
557
-     * @throws InvalidInterfaceException
558
-     * @throws InvalidDataTypeException
559
-     * @throws EE_Error
560
-     * @return mixed    index into cache, or just TRUE if the relation is of type Belongs_To (because there's only one
561
-     *                                       related thing, no array)
562
-     */
563
-    public function cache($relationName = '', $object_to_cache = null, $cache_id = null)
564
-    {
565
-        // its entirely possible that there IS no related object yet in which case there is nothing to cache.
566
-        if (! $object_to_cache instanceof EE_Base_Class) {
567
-            return false;
568
-        }
569
-        // also get "how" the object is related, or throw an error
570
-        if (! $relationship_to_model = $this->get_model()->related_settings_for($relationName)) {
571
-            throw new EE_Error(
572
-                sprintf(
573
-                    esc_html__('There is no relationship to %s on a %s. Cannot cache it', 'event_espresso'),
574
-                    $relationName,
575
-                    get_class($this)
576
-                )
577
-            );
578
-        }
579
-        // how many things are related ?
580
-        if ($relationship_to_model instanceof EE_Belongs_To_Relation) {
581
-            // if it's a "belongs to" relationship, then there's only one related model object
582
-            // eg, if this is a registration, there's only 1 attendee for it
583
-            // so for these model objects just set it to be cached
584
-            $this->_model_relations[ $relationName ] = $object_to_cache;
585
-            $return                                  = true;
586
-        } else {
587
-            // otherwise, this is the "many" side of a one to many relationship,
588
-            // so we'll add the object to the array of related objects for that type.
589
-            // eg: if this is an event, there are many registrations for that event,
590
-            // so we cache the registrations in an array
591
-            if (! is_array($this->_model_relations[ $relationName ])) {
592
-                // if for some reason, the cached item is a model object,
593
-                // then stick that in the array, otherwise start with an empty array
594
-                $this->_model_relations[ $relationName ] = $this->_model_relations[ $relationName ]
595
-                                                           instanceof
596
-                                                           EE_Base_Class
597
-                    ? array($this->_model_relations[ $relationName ]) : array();
598
-            }
599
-            // first check for a cache_id which is normally empty
600
-            if (! empty($cache_id)) {
601
-                // if the cache_id exists, then it means we are purposely trying to cache this
602
-                // with a known key that can then be used to retrieve the object later on
603
-                $this->_model_relations[ $relationName ][ $cache_id ] = $object_to_cache;
604
-                $return                                               = $cache_id;
605
-            } elseif ($object_to_cache->ID()) {
606
-                // OR the cached object originally came from the db, so let's just use it's PK for an ID
607
-                $this->_model_relations[ $relationName ][ $object_to_cache->ID() ] = $object_to_cache;
608
-                $return                                                            = $object_to_cache->ID();
609
-            } else {
610
-                // OR it's a new object with no ID, so just throw it in the array with an auto-incremented ID
611
-                $this->_model_relations[ $relationName ][] = $object_to_cache;
612
-                // move the internal pointer to the end of the array
613
-                end($this->_model_relations[ $relationName ]);
614
-                // and grab the key so that we can return it
615
-                $return = key($this->_model_relations[ $relationName ]);
616
-            }
617
-        }
618
-        return $return;
619
-    }
620
-
621
-
622
-    /**
623
-     * For adding an item to the cached_properties property.
624
-     *
625
-     * @access protected
626
-     * @param string      $fieldname the property item the corresponding value is for.
627
-     * @param mixed       $value     The value we are caching.
628
-     * @param string|null $cache_type
629
-     * @return void
630
-     * @throws ReflectionException
631
-     * @throws InvalidArgumentException
632
-     * @throws InvalidInterfaceException
633
-     * @throws InvalidDataTypeException
634
-     * @throws EE_Error
635
-     */
636
-    protected function _set_cached_property($fieldname, $value, $cache_type = null)
637
-    {
638
-        //first make sure this property exists
639
-        $this->get_model()->field_settings_for($fieldname);
640
-        $cache_type                                            = empty($cache_type) ? 'standard' : $cache_type;
641
-        $this->_cached_properties[ $fieldname ][ $cache_type ] = $value;
642
-    }
643
-
644
-
645
-    /**
646
-     * This returns the value cached property if it exists OR the actual property value if the cache doesn't exist.
647
-     * This also SETS the cache if we return the actual property!
648
-     *
649
-     * @param string $fieldname        the name of the property we're trying to retrieve
650
-     * @param bool   $pretty
651
-     * @param string $extra_cache_ref  This allows the user to specify an extra cache ref for the given property
652
-     *                                 (in cases where the same property may be used for different outputs
653
-     *                                 - i.e. datetime, money etc.)
654
-     *                                 It can also accept certain pre-defined "schema" strings
655
-     *                                 to define how to output the property.
656
-     *                                 see the field's prepare_for_pretty_echoing for what strings can be used
657
-     * @return mixed                   whatever the value for the property is we're retrieving
658
-     * @throws ReflectionException
659
-     * @throws InvalidArgumentException
660
-     * @throws InvalidInterfaceException
661
-     * @throws InvalidDataTypeException
662
-     * @throws EE_Error
663
-     */
664
-    protected function _get_cached_property($fieldname, $pretty = false, $extra_cache_ref = null)
665
-    {
666
-        //verify the field exists
667
-        $model = $this->get_model();
668
-        $model->field_settings_for($fieldname);
669
-        $cache_type = $pretty ? 'pretty' : 'standard';
670
-        $cache_type .= ! empty($extra_cache_ref) ? '_' . $extra_cache_ref : '';
671
-        if (isset($this->_cached_properties[ $fieldname ][ $cache_type ])) {
672
-            return $this->_cached_properties[ $fieldname ][ $cache_type ];
673
-        }
674
-        $value = $this->_get_fresh_property($fieldname, $pretty, $extra_cache_ref);
675
-        $this->_set_cached_property($fieldname, $value, $cache_type);
676
-        return $value;
677
-    }
678
-
679
-
680
-    /**
681
-     * If the cache didn't fetch the needed item, this fetches it.
682
-     *
683
-     * @param string $fieldname
684
-     * @param bool   $pretty
685
-     * @param string $extra_cache_ref
686
-     * @return mixed
687
-     * @throws InvalidArgumentException
688
-     * @throws InvalidInterfaceException
689
-     * @throws InvalidDataTypeException
690
-     * @throws EE_Error
691
-     * @throws ReflectionException
692
-     */
693
-    protected function _get_fresh_property($fieldname, $pretty = false, $extra_cache_ref = null)
694
-    {
695
-        $field_obj = $this->get_model()->field_settings_for($fieldname);
696
-        // If this is an EE_Datetime_Field we need to make sure timezone, formats, and output are correct
697
-        if ($field_obj instanceof EE_Datetime_Field) {
698
-            $this->_prepare_datetime_field($field_obj, $pretty, $extra_cache_ref);
699
-        }
700
-        if (! isset($this->_fields[ $fieldname ])) {
701
-            $this->_fields[ $fieldname ] = null;
702
-        }
703
-        $value = $pretty
704
-            ? $field_obj->prepare_for_pretty_echoing($this->_fields[ $fieldname ], $extra_cache_ref)
705
-            : $field_obj->prepare_for_get($this->_fields[ $fieldname ]);
706
-        return $value;
707
-    }
708
-
709
-
710
-    /**
711
-     * set timezone, formats, and output for EE_Datetime_Field objects
712
-     *
713
-     * @param \EE_Datetime_Field $datetime_field
714
-     * @param bool               $pretty
715
-     * @param null               $date_or_time
716
-     * @return void
717
-     * @throws InvalidArgumentException
718
-     * @throws InvalidInterfaceException
719
-     * @throws InvalidDataTypeException
720
-     * @throws EE_Error
721
-     */
722
-    protected function _prepare_datetime_field(
723
-        EE_Datetime_Field $datetime_field,
724
-        $pretty = false,
725
-        $date_or_time = null
726
-    ) {
727
-        $datetime_field->set_timezone($this->_timezone);
728
-        $datetime_field->set_date_format($this->_dt_frmt, $pretty);
729
-        $datetime_field->set_time_format($this->_tm_frmt, $pretty);
730
-        //set the output returned
731
-        switch ($date_or_time) {
732
-            case 'D' :
733
-                $datetime_field->set_date_time_output('date');
734
-                break;
735
-            case 'T' :
736
-                $datetime_field->set_date_time_output('time');
737
-                break;
738
-            default :
739
-                $datetime_field->set_date_time_output();
740
-        }
741
-    }
742
-
743
-
744
-    /**
745
-     * This just takes care of clearing out the cached_properties
746
-     *
747
-     * @return void
748
-     */
749
-    protected function _clear_cached_properties()
750
-    {
751
-        $this->_cached_properties = array();
752
-    }
753
-
754
-
755
-    /**
756
-     * This just clears out ONE property if it exists in the cache
757
-     *
758
-     * @param  string $property_name the property to remove if it exists (from the _cached_properties array)
759
-     * @return void
760
-     */
761
-    protected function _clear_cached_property($property_name)
762
-    {
763
-        if (isset($this->_cached_properties[ $property_name ])) {
764
-            unset($this->_cached_properties[ $property_name ]);
765
-        }
766
-    }
767
-
768
-
769
-    /**
770
-     * Ensures that this related thing is a model object.
771
-     *
772
-     * @param mixed  $object_or_id EE_base_Class/int/string either a related model object, or its ID
773
-     * @param string $model_name   name of the related thing, eg 'Attendee',
774
-     * @return EE_Base_Class
775
-     * @throws ReflectionException
776
-     * @throws InvalidArgumentException
777
-     * @throws InvalidInterfaceException
778
-     * @throws InvalidDataTypeException
779
-     * @throws EE_Error
780
-     */
781
-    protected function ensure_related_thing_is_model_obj($object_or_id, $model_name)
782
-    {
783
-        $other_model_instance = self::_get_model_instance_with_name(
784
-            self::_get_model_classname($model_name),
785
-            $this->_timezone
786
-        );
787
-        return $other_model_instance->ensure_is_obj($object_or_id);
788
-    }
789
-
790
-
791
-    /**
792
-     * Forgets the cached model of the given relation Name. So the next time we request it,
793
-     * we will fetch it again from the database. (Handy if you know it's changed somehow).
794
-     * If a specific object is supplied, and the relationship to it is either a HasMany or HABTM,
795
-     * then only remove that one object from our cached array. Otherwise, clear the entire list
796
-     *
797
-     * @param string $relationName                         one of the keys in the _model_relations array on the model.
798
-     *                                                     Eg 'Registration'
799
-     * @param mixed  $object_to_remove_or_index_into_array or an index into the array of cached things, or NULL
800
-     *                                                     if you intend to use $clear_all = TRUE, or the relation only
801
-     *                                                     has 1 object anyways (ie, it's a BelongsToRelation)
802
-     * @param bool   $clear_all                            This flags clearing the entire cache relation property if
803
-     *                                                     this is HasMany or HABTM.
804
-     * @throws ReflectionException
805
-     * @throws InvalidArgumentException
806
-     * @throws InvalidInterfaceException
807
-     * @throws InvalidDataTypeException
808
-     * @throws EE_Error
809
-     * @return EE_Base_Class | boolean from which was cleared from the cache, or true if we requested to remove a
810
-     *                                                     relation from all
811
-     */
812
-    public function clear_cache($relationName, $object_to_remove_or_index_into_array = null, $clear_all = false)
813
-    {
814
-        $relationship_to_model = $this->get_model()->related_settings_for($relationName);
815
-        $index_in_cache        = '';
816
-        if (! $relationship_to_model) {
817
-            throw new EE_Error(
818
-                sprintf(
819
-                    esc_html__('There is no relationship to %s on a %s. Cannot clear that cache', 'event_espresso'),
820
-                    $relationName,
821
-                    get_class($this)
822
-                )
823
-            );
824
-        }
825
-        if ($clear_all) {
826
-            $obj_removed                             = true;
827
-            $this->_model_relations[ $relationName ] = null;
828
-        } elseif ($relationship_to_model instanceof EE_Belongs_To_Relation) {
829
-            $obj_removed                             = $this->_model_relations[ $relationName ];
830
-            $this->_model_relations[ $relationName ] = null;
831
-        } else {
832
-            if ($object_to_remove_or_index_into_array instanceof EE_Base_Class
833
-                && $object_to_remove_or_index_into_array->ID()
834
-            ) {
835
-                $index_in_cache = $object_to_remove_or_index_into_array->ID();
836
-                if (is_array($this->_model_relations[ $relationName ])
837
-                    && ! isset($this->_model_relations[ $relationName ][ $index_in_cache ])
838
-                ) {
839
-                    $index_found_at = null;
840
-                    //find this object in the array even though it has a different key
841
-                    foreach ($this->_model_relations[ $relationName ] as $index => $obj) {
842
-                        /** @noinspection TypeUnsafeComparisonInspection */
843
-                        if (
844
-                            $obj instanceof EE_Base_Class
845
-                            && (
846
-                                $obj == $object_to_remove_or_index_into_array
847
-                                || $obj->ID() === $object_to_remove_or_index_into_array->ID()
848
-                            )
849
-                        ) {
850
-                            $index_found_at = $index;
851
-                            break;
852
-                        }
853
-                    }
854
-                    if ($index_found_at) {
855
-                        $index_in_cache = $index_found_at;
856
-                    } else {
857
-                        //it wasn't found. huh. well obviously it doesn't need to be removed from teh cache
858
-                        //if it wasn't in it to begin with. So we're done
859
-                        return $object_to_remove_or_index_into_array;
860
-                    }
861
-                }
862
-            } elseif ($object_to_remove_or_index_into_array instanceof EE_Base_Class) {
863
-                //so they provided a model object, but it's not yet saved to the DB... so let's go hunting for it!
864
-                foreach ($this->get_all_from_cache($relationName) as $index => $potentially_obj_we_want) {
865
-                    /** @noinspection TypeUnsafeComparisonInspection */
866
-                    if ($potentially_obj_we_want == $object_to_remove_or_index_into_array) {
867
-                        $index_in_cache = $index;
868
-                    }
869
-                }
870
-            } else {
871
-                $index_in_cache = $object_to_remove_or_index_into_array;
872
-            }
873
-            //supposedly we've found it. But it could just be that the client code
874
-            //provided a bad index/object
875
-            if (isset($this->_model_relations[ $relationName ][ $index_in_cache ])) {
876
-                $obj_removed = $this->_model_relations[ $relationName ][ $index_in_cache ];
877
-                unset($this->_model_relations[ $relationName ][ $index_in_cache ]);
878
-            } else {
879
-                //that thing was never cached anyways.
880
-                $obj_removed = null;
881
-            }
882
-        }
883
-        return $obj_removed;
884
-    }
885
-
886
-
887
-    /**
888
-     * update_cache_after_object_save
889
-     * Allows a cached item to have it's cache ID (within the array of cached items) reset using the new ID it has
890
-     * obtained after being saved to the db
891
-     *
892
-     * @param string        $relationName       - the type of object that is cached
893
-     * @param EE_Base_Class $newly_saved_object - the newly saved object to be re-cached
894
-     * @param string        $current_cache_id   - the ID that was used when originally caching the object
895
-     * @return boolean TRUE on success, FALSE on fail
896
-     * @throws ReflectionException
897
-     * @throws InvalidArgumentException
898
-     * @throws InvalidInterfaceException
899
-     * @throws InvalidDataTypeException
900
-     * @throws EE_Error
901
-     */
902
-    public function update_cache_after_object_save(
903
-        $relationName,
904
-        EE_Base_Class $newly_saved_object,
905
-        $current_cache_id = ''
906
-    ) {
907
-        // verify that incoming object is of the correct type
908
-        $obj_class = 'EE_' . $relationName;
909
-        if ($newly_saved_object instanceof $obj_class) {
910
-            /* @type EE_Base_Class $newly_saved_object */
911
-            // now get the type of relation
912
-            $relationship_to_model = $this->get_model()->related_settings_for($relationName);
913
-            // if this is a 1:1 relationship
914
-            if ($relationship_to_model instanceof EE_Belongs_To_Relation) {
915
-                // then just replace the cached object with the newly saved object
916
-                $this->_model_relations[ $relationName ] = $newly_saved_object;
917
-                return true;
918
-                // or if it's some kind of sordid feral polyamorous relationship...
919
-            }
920
-            if (is_array($this->_model_relations[ $relationName ])
921
-                      && isset($this->_model_relations[ $relationName ][ $current_cache_id ])
922
-            ) {
923
-                // then remove the current cached item
924
-                unset($this->_model_relations[ $relationName ][ $current_cache_id ]);
925
-                // and cache the newly saved object using it's new ID
926
-                $this->_model_relations[ $relationName ][ $newly_saved_object->ID() ] = $newly_saved_object;
927
-                return true;
928
-            }
929
-        }
930
-        return false;
931
-    }
932
-
933
-
934
-    /**
935
-     * Fetches a single EE_Base_Class on that relation. (If the relation is of type
936
-     * BelongsTo, it will only ever have 1 object. However, other relations could have an array of objects)
937
-     *
938
-     * @param string $relationName
939
-     * @return EE_Base_Class
940
-     */
941
-    public function get_one_from_cache($relationName)
942
-    {
943
-        $cached_array_or_object = isset($this->_model_relations[ $relationName ])
944
-            ? $this->_model_relations[ $relationName ]
945
-            : null;
946
-        if (is_array($cached_array_or_object)) {
947
-            return array_shift($cached_array_or_object);
948
-        }
949
-        return $cached_array_or_object;
950
-    }
951
-
952
-
953
-    /**
954
-     * Fetches a single EE_Base_Class on that relation. (If the relation is of type
955
-     * BelongsTo, it will only ever have 1 object. However, other relations could have an array of objects)
956
-     *
957
-     * @param string $relationName
958
-     * @throws ReflectionException
959
-     * @throws InvalidArgumentException
960
-     * @throws InvalidInterfaceException
961
-     * @throws InvalidDataTypeException
962
-     * @throws EE_Error
963
-     * @return EE_Base_Class[] NOT necessarily indexed by primary keys
964
-     */
965
-    public function get_all_from_cache($relationName)
966
-    {
967
-        $objects = isset($this->_model_relations[ $relationName ]) ? $this->_model_relations[ $relationName ] : array();
968
-        // if the result is not an array, but exists, make it an array
969
-        $objects = is_array($objects) ? $objects : array($objects);
970
-        //bugfix for https://events.codebasehq.com/projects/event-espresso/tickets/7143
971
-        //basically, if this model object was stored in the session, and these cached model objects
972
-        //already have IDs, let's make sure they're in their model's entity mapper
973
-        //otherwise we will have duplicates next time we call
974
-        // EE_Registry::instance()->load_model( $relationName )->get_one_by_ID( $result->ID() );
975
-        $model = EE_Registry::instance()->load_model($relationName);
976
-        foreach ($objects as $model_object) {
977
-            if ($model instanceof EEM_Base && $model_object instanceof EE_Base_Class) {
978
-                //ensure its in the map if it has an ID; otherwise it will be added to the map when its saved
979
-                if ($model_object->ID()) {
980
-                    $model->add_to_entity_map($model_object);
981
-                }
982
-            } else {
983
-                throw new EE_Error(
984
-                    sprintf(
985
-                        esc_html__(
986
-                            'Error retrieving related model objects. Either $1%s is not a model or $2%s is not a model object',
987
-                            'event_espresso'
988
-                        ),
989
-                        $relationName,
990
-                        gettype($model_object)
991
-                    )
992
-                );
993
-            }
994
-        }
995
-        return $objects;
996
-    }
997
-
998
-
999
-    /**
1000
-     * Returns the next x number of EE_Base_Class objects in sequence from this object as found in the database
1001
-     * matching the given query conditions.
1002
-     *
1003
-     * @param null  $field_to_order_by  What field is being used as the reference point.
1004
-     * @param int   $limit              How many objects to return.
1005
-     * @param array $query_params       Any additional conditions on the query.
1006
-     * @param null  $columns_to_select  If left null, then an array of EE_Base_Class objects is returned, otherwise
1007
-     *                                  you can indicate just the columns you want returned
1008
-     * @return array|EE_Base_Class[]
1009
-     * @throws ReflectionException
1010
-     * @throws InvalidArgumentException
1011
-     * @throws InvalidInterfaceException
1012
-     * @throws InvalidDataTypeException
1013
-     * @throws EE_Error
1014
-     */
1015
-    public function next_x($field_to_order_by = null, $limit = 1, $query_params = array(), $columns_to_select = null)
1016
-    {
1017
-        $model         = $this->get_model();
1018
-        $field         = empty($field_to_order_by) && $model->has_primary_key_field()
1019
-            ? $model->get_primary_key_field()->get_name()
1020
-            : $field_to_order_by;
1021
-        $current_value = ! empty($field) ? $this->get($field) : null;
1022
-        if (empty($field) || empty($current_value)) {
1023
-            return array();
1024
-        }
1025
-        return $model->next_x($current_value, $field, $limit, $query_params, $columns_to_select);
1026
-    }
1027
-
1028
-
1029
-    /**
1030
-     * Returns the previous x number of EE_Base_Class objects in sequence from this object as found in the database
1031
-     * matching the given query conditions.
1032
-     *
1033
-     * @param null  $field_to_order_by  What field is being used as the reference point.
1034
-     * @param int   $limit              How many objects to return.
1035
-     * @param array $query_params       Any additional conditions on the query.
1036
-     * @param null  $columns_to_select  If left null, then an array of EE_Base_Class objects is returned, otherwise
1037
-     *                                  you can indicate just the columns you want returned
1038
-     * @return array|EE_Base_Class[]
1039
-     * @throws ReflectionException
1040
-     * @throws InvalidArgumentException
1041
-     * @throws InvalidInterfaceException
1042
-     * @throws InvalidDataTypeException
1043
-     * @throws EE_Error
1044
-     */
1045
-    public function previous_x(
1046
-        $field_to_order_by = null,
1047
-        $limit = 1,
1048
-        $query_params = array(),
1049
-        $columns_to_select = null
1050
-    ) {
1051
-        $model         = $this->get_model();
1052
-        $field         = empty($field_to_order_by) && $model->has_primary_key_field()
1053
-            ? $model->get_primary_key_field()->get_name()
1054
-            : $field_to_order_by;
1055
-        $current_value = ! empty($field) ? $this->get($field) : null;
1056
-        if (empty($field) || empty($current_value)) {
1057
-            return array();
1058
-        }
1059
-        return $model->previous_x($current_value, $field, $limit, $query_params, $columns_to_select);
1060
-    }
1061
-
1062
-
1063
-    /**
1064
-     * Returns the next EE_Base_Class object in sequence from this object as found in the database
1065
-     * matching the given query conditions.
1066
-     *
1067
-     * @param null  $field_to_order_by  What field is being used as the reference point.
1068
-     * @param array $query_params       Any additional conditions on the query.
1069
-     * @param null  $columns_to_select  If left null, then an array of EE_Base_Class objects is returned, otherwise
1070
-     *                                  you can indicate just the columns you want returned
1071
-     * @return array|EE_Base_Class
1072
-     * @throws ReflectionException
1073
-     * @throws InvalidArgumentException
1074
-     * @throws InvalidInterfaceException
1075
-     * @throws InvalidDataTypeException
1076
-     * @throws EE_Error
1077
-     */
1078
-    public function next($field_to_order_by = null, $query_params = array(), $columns_to_select = null)
1079
-    {
1080
-        $model         = $this->get_model();
1081
-        $field         = empty($field_to_order_by) && $model->has_primary_key_field()
1082
-            ? $model->get_primary_key_field()->get_name()
1083
-            : $field_to_order_by;
1084
-        $current_value = ! empty($field) ? $this->get($field) : null;
1085
-        if (empty($field) || empty($current_value)) {
1086
-            return array();
1087
-        }
1088
-        return $model->next($current_value, $field, $query_params, $columns_to_select);
1089
-    }
1090
-
1091
-
1092
-    /**
1093
-     * Returns the previous EE_Base_Class object in sequence from this object as found in the database
1094
-     * matching the given query conditions.
1095
-     *
1096
-     * @param null  $field_to_order_by  What field is being used as the reference point.
1097
-     * @param array $query_params       Any additional conditions on the query.
1098
-     * @param null  $columns_to_select  If left null, then an EE_Base_Class object is returned, otherwise
1099
-     *                                  you can indicate just the column you want returned
1100
-     * @return array|EE_Base_Class
1101
-     * @throws ReflectionException
1102
-     * @throws InvalidArgumentException
1103
-     * @throws InvalidInterfaceException
1104
-     * @throws InvalidDataTypeException
1105
-     * @throws EE_Error
1106
-     */
1107
-    public function previous($field_to_order_by = null, $query_params = array(), $columns_to_select = null)
1108
-    {
1109
-        $model         = $this->get_model();
1110
-        $field         = empty($field_to_order_by) && $model->has_primary_key_field()
1111
-            ? $model->get_primary_key_field()->get_name()
1112
-            : $field_to_order_by;
1113
-        $current_value = ! empty($field) ? $this->get($field) : null;
1114
-        if (empty($field) || empty($current_value)) {
1115
-            return array();
1116
-        }
1117
-        return $model->previous($current_value, $field, $query_params, $columns_to_select);
1118
-    }
1119
-
1120
-
1121
-    /**
1122
-     * Overrides parent because parent expects old models.
1123
-     * This also doesn't do any validation, and won't work for serialized arrays
1124
-     *
1125
-     * @param string $field_name
1126
-     * @param mixed  $field_value_from_db
1127
-     * @throws ReflectionException
1128
-     * @throws InvalidArgumentException
1129
-     * @throws InvalidInterfaceException
1130
-     * @throws InvalidDataTypeException
1131
-     * @throws EE_Error
1132
-     */
1133
-    public function set_from_db($field_name, $field_value_from_db)
1134
-    {
1135
-        $field_obj = $this->get_model()->field_settings_for($field_name);
1136
-        if ($field_obj instanceof EE_Model_Field_Base) {
1137
-            //you would think the DB has no NULLs for non-null label fields right? wrong!
1138
-            //eg, a CPT model object could have an entry in the posts table, but no
1139
-            //entry in the meta table. Meaning that all its columns in the meta table
1140
-            //are null! yikes! so when we find one like that, use defaults for its meta columns
1141
-            if ($field_value_from_db === null) {
1142
-                if ($field_obj->is_nullable()) {
1143
-                    //if the field allows nulls, then let it be null
1144
-                    $field_value = null;
1145
-                } else {
1146
-                    $field_value = $field_obj->get_default_value();
1147
-                }
1148
-            } else {
1149
-                $field_value = $field_obj->prepare_for_set_from_db($field_value_from_db);
1150
-            }
1151
-            $this->_fields[ $field_name ] = $field_value;
1152
-            $this->_clear_cached_property($field_name);
1153
-        }
1154
-    }
1155
-
1156
-
1157
-    /**
1158
-     * verifies that the specified field is of the correct type
1159
-     *
1160
-     * @param string $field_name
1161
-     * @param string $extra_cache_ref This allows the user to specify an extra cache ref for the given property
1162
-     *                                (in cases where the same property may be used for different outputs
1163
-     *                                - i.e. datetime, money etc.)
1164
-     * @return mixed
1165
-     * @throws ReflectionException
1166
-     * @throws InvalidArgumentException
1167
-     * @throws InvalidInterfaceException
1168
-     * @throws InvalidDataTypeException
1169
-     * @throws EE_Error
1170
-     */
1171
-    public function get($field_name, $extra_cache_ref = null)
1172
-    {
1173
-        return $this->_get_cached_property($field_name, false, $extra_cache_ref);
1174
-    }
1175
-
1176
-
1177
-    /**
1178
-     * This method simply returns the RAW unprocessed value for the given property in this class
1179
-     *
1180
-     * @param  string $field_name A valid fieldname
1181
-     * @return mixed              Whatever the raw value stored on the property is.
1182
-     * @throws ReflectionException
1183
-     * @throws InvalidArgumentException
1184
-     * @throws InvalidInterfaceException
1185
-     * @throws InvalidDataTypeException
1186
-     * @throws EE_Error if fieldSettings is misconfigured or the field doesn't exist.
1187
-     */
1188
-    public function get_raw($field_name)
1189
-    {
1190
-        $field_settings = $this->get_model()->field_settings_for($field_name);
1191
-        return $field_settings instanceof EE_Datetime_Field && $this->_fields[ $field_name ] instanceof DateTime
1192
-            ? $this->_fields[ $field_name ]->format('U')
1193
-            : $this->_fields[ $field_name ];
1194
-    }
1195
-
1196
-
1197
-    /**
1198
-     * This is used to return the internal DateTime object used for a field that is a
1199
-     * EE_Datetime_Field.
1200
-     *
1201
-     * @param string $field_name               The field name retrieving the DateTime object.
1202
-     * @return mixed null | false | DateTime  If the requested field is NOT a EE_Datetime_Field then
1203
-     * @throws EE_Error an error is set and false returned.  If the field IS an
1204
-     *                                         EE_Datetime_Field and but the field value is null, then
1205
-     *                                         just null is returned (because that indicates that likely
1206
-     *                                         this field is nullable).
1207
-     * @throws InvalidArgumentException
1208
-     * @throws InvalidDataTypeException
1209
-     * @throws InvalidInterfaceException
1210
-     * @throws ReflectionException
1211
-     */
1212
-    public function get_DateTime_object($field_name)
1213
-    {
1214
-        $field_settings = $this->get_model()->field_settings_for($field_name);
1215
-        if (! $field_settings instanceof EE_Datetime_Field) {
1216
-            EE_Error::add_error(
1217
-                sprintf(
1218
-                    esc_html__(
1219
-                        'The field %s is not an EE_Datetime_Field field.  There is no DateTime object stored on this field type.',
1220
-                        'event_espresso'
1221
-                    ),
1222
-                    $field_name
1223
-                ),
1224
-                __FILE__,
1225
-                __FUNCTION__,
1226
-                __LINE__
1227
-            );
1228
-            return false;
1229
-        }
1230
-        return isset($this->_fields[$field_name]) && $this->_fields[$field_name] instanceof DateTime
1231
-            ? clone $this->_fields[$field_name]
1232
-            : null;
1233
-    }
1234
-
1235
-
1236
-    /**
1237
-     * To be used in template to immediately echo out the value, and format it for output.
1238
-     * Eg, should call stripslashes and whatnot before echoing
1239
-     *
1240
-     * @param string $field_name      the name of the field as it appears in the DB
1241
-     * @param string $extra_cache_ref This allows the user to specify an extra cache ref for the given property
1242
-     *                                (in cases where the same property may be used for different outputs
1243
-     *                                - i.e. datetime, money etc.)
1244
-     * @return void
1245
-     * @throws ReflectionException
1246
-     * @throws InvalidArgumentException
1247
-     * @throws InvalidInterfaceException
1248
-     * @throws InvalidDataTypeException
1249
-     * @throws EE_Error
1250
-     */
1251
-    public function e($field_name, $extra_cache_ref = null)
1252
-    {
1253
-        echo $this->get_pretty($field_name, $extra_cache_ref);
1254
-    }
1255
-
1256
-
1257
-    /**
1258
-     * Exactly like e(), echoes out the field, but sets its schema to 'form_input', so that it
1259
-     * can be easily used as the value of form input.
1260
-     *
1261
-     * @param string $field_name
1262
-     * @return void
1263
-     * @throws ReflectionException
1264
-     * @throws InvalidArgumentException
1265
-     * @throws InvalidInterfaceException
1266
-     * @throws InvalidDataTypeException
1267
-     * @throws EE_Error
1268
-     */
1269
-    public function f($field_name)
1270
-    {
1271
-        $this->e($field_name, 'form_input');
1272
-    }
1273
-
1274
-
1275
-    /**
1276
-     * Same as `f()` but just returns the value instead of echoing it
1277
-     *
1278
-     * @param string $field_name
1279
-     * @return string
1280
-     * @throws ReflectionException
1281
-     * @throws InvalidArgumentException
1282
-     * @throws InvalidInterfaceException
1283
-     * @throws InvalidDataTypeException
1284
-     * @throws EE_Error
1285
-     */
1286
-    public function get_f($field_name)
1287
-    {
1288
-        return (string) $this->get_pretty($field_name, 'form_input');
1289
-    }
1290
-
1291
-
1292
-    /**
1293
-     * Gets a pretty view of the field's value. $extra_cache_ref can specify different formats for this.
1294
-     * The $extra_cache_ref will be passed to the model field's prepare_for_pretty_echoing, so consult the field's class
1295
-     * to see what options are available.
1296
-     *
1297
-     * @param string $field_name
1298
-     * @param string $extra_cache_ref This allows the user to specify an extra cache ref for the given property
1299
-     *                                (in cases where the same property may be used for different outputs
1300
-     *                                - i.e. datetime, money etc.)
1301
-     * @return mixed
1302
-     * @throws ReflectionException
1303
-     * @throws InvalidArgumentException
1304
-     * @throws InvalidInterfaceException
1305
-     * @throws InvalidDataTypeException
1306
-     * @throws EE_Error
1307
-     */
1308
-    public function get_pretty($field_name, $extra_cache_ref = null)
1309
-    {
1310
-        return $this->_get_cached_property($field_name, true, $extra_cache_ref);
1311
-    }
1312
-
1313
-
1314
-    /**
1315
-     * This simply returns the datetime for the given field name
1316
-     * Note: this protected function is called by the wrapper get_date or get_time or get_datetime functions
1317
-     * (and the equivalent e_date, e_time, e_datetime).
1318
-     *
1319
-     * @access   protected
1320
-     * @param string   $field_name   Field on the instantiated EE_Base_Class child object
1321
-     * @param string   $dt_frmt      valid datetime format used for date
1322
-     *                               (if '' then we just use the default on the field,
1323
-     *                               if NULL we use the last-used format)
1324
-     * @param string   $tm_frmt      Same as above except this is for time format
1325
-     * @param string   $date_or_time if NULL then both are returned, otherwise "D" = only date and "T" = only time.
1326
-     * @param  boolean $echo         Whether the dtt is echoing using pretty echoing or just returned using vanilla get
1327
-     * @return string|bool|EE_Error string on success, FALSE on fail, or EE_Error Exception is thrown
1328
-     *                               if field is not a valid dtt field, or void if echoing
1329
-     * @throws ReflectionException
1330
-     * @throws InvalidArgumentException
1331
-     * @throws InvalidInterfaceException
1332
-     * @throws InvalidDataTypeException
1333
-     * @throws EE_Error
1334
-     */
1335
-    protected function _get_datetime($field_name, $dt_frmt = '', $tm_frmt = '', $date_or_time = '', $echo = false)
1336
-    {
1337
-        // clear cached property
1338
-        $this->_clear_cached_property($field_name);
1339
-        //reset format properties because they are used in get()
1340
-        $this->_dt_frmt = $dt_frmt !== '' ? $dt_frmt : $this->_dt_frmt;
1341
-        $this->_tm_frmt = $tm_frmt !== '' ? $tm_frmt : $this->_tm_frmt;
1342
-        if ($echo) {
1343
-            $this->e($field_name, $date_or_time);
1344
-            return '';
1345
-        }
1346
-        return $this->get($field_name, $date_or_time);
1347
-    }
1348
-
1349
-
1350
-    /**
1351
-     * below are wrapper functions for the various datetime outputs that can be obtained for JUST returning the date
1352
-     * portion of a datetime value. (note the only difference between get_ and e_ is one returns the value and the
1353
-     * other echoes the pretty value for dtt)
1354
-     *
1355
-     * @param  string $field_name name of model object datetime field holding the value
1356
-     * @param  string $format     format for the date returned (if NULL we use default in dt_frmt property)
1357
-     * @return string            datetime value formatted
1358
-     * @throws ReflectionException
1359
-     * @throws InvalidArgumentException
1360
-     * @throws InvalidInterfaceException
1361
-     * @throws InvalidDataTypeException
1362
-     * @throws EE_Error
1363
-     */
1364
-    public function get_date($field_name, $format = '')
1365
-    {
1366
-        return $this->_get_datetime($field_name, $format, null, 'D');
1367
-    }
1368
-
1369
-
1370
-    /**
1371
-     * @param        $field_name
1372
-     * @param string $format
1373
-     * @throws ReflectionException
1374
-     * @throws InvalidArgumentException
1375
-     * @throws InvalidInterfaceException
1376
-     * @throws InvalidDataTypeException
1377
-     * @throws EE_Error
1378
-     */
1379
-    public function e_date($field_name, $format = '')
1380
-    {
1381
-        $this->_get_datetime($field_name, $format, null, 'D', true);
1382
-    }
1383
-
1384
-
1385
-    /**
1386
-     * below are wrapper functions for the various datetime outputs that can be obtained for JUST returning the time
1387
-     * portion of a datetime value. (note the only difference between get_ and e_ is one returns the value and the
1388
-     * other echoes the pretty value for dtt)
1389
-     *
1390
-     * @param  string $field_name name of model object datetime field holding the value
1391
-     * @param  string $format     format for the time returned ( if NULL we use default in tm_frmt property)
1392
-     * @return string             datetime value formatted
1393
-     * @throws ReflectionException
1394
-     * @throws InvalidArgumentException
1395
-     * @throws InvalidInterfaceException
1396
-     * @throws InvalidDataTypeException
1397
-     * @throws EE_Error
1398
-     */
1399
-    public function get_time($field_name, $format = '')
1400
-    {
1401
-        return $this->_get_datetime($field_name, null, $format, 'T');
1402
-    }
1403
-
1404
-
1405
-    /**
1406
-     * @param        $field_name
1407
-     * @param string $format
1408
-     * @throws ReflectionException
1409
-     * @throws InvalidArgumentException
1410
-     * @throws InvalidInterfaceException
1411
-     * @throws InvalidDataTypeException
1412
-     * @throws EE_Error
1413
-     */
1414
-    public function e_time($field_name, $format = '')
1415
-    {
1416
-        $this->_get_datetime($field_name, null, $format, 'T', true);
1417
-    }
1418
-
1419
-
1420
-    /**
1421
-     * below are wrapper functions for the various datetime outputs that can be obtained for returning the date AND
1422
-     * time portion of a datetime value. (note the only difference between get_ and e_ is one returns the value and the
1423
-     * other echoes the pretty value for dtt)
1424
-     *
1425
-     * @param  string $field_name name of model object datetime field holding the value
1426
-     * @param  string $dt_frmt    format for the date returned (if NULL we use default in dt_frmt property)
1427
-     * @param  string $tm_frmt    format for the time returned (if NULL we use default in tm_frmt property)
1428
-     * @return string             datetime value formatted
1429
-     * @throws ReflectionException
1430
-     * @throws InvalidArgumentException
1431
-     * @throws InvalidInterfaceException
1432
-     * @throws InvalidDataTypeException
1433
-     * @throws EE_Error
1434
-     */
1435
-    public function get_datetime($field_name, $dt_frmt = '', $tm_frmt = '')
1436
-    {
1437
-        return $this->_get_datetime($field_name, $dt_frmt, $tm_frmt);
1438
-    }
1439
-
1440
-
1441
-    /**
1442
-     * @param string $field_name
1443
-     * @param string $dt_frmt
1444
-     * @param string $tm_frmt
1445
-     * @throws ReflectionException
1446
-     * @throws InvalidArgumentException
1447
-     * @throws InvalidInterfaceException
1448
-     * @throws InvalidDataTypeException
1449
-     * @throws EE_Error
1450
-     */
1451
-    public function e_datetime($field_name, $dt_frmt = '', $tm_frmt = '')
1452
-    {
1453
-        $this->_get_datetime($field_name, $dt_frmt, $tm_frmt, null, true);
1454
-    }
1455
-
1456
-
1457
-    /**
1458
-     * Get the i8ln value for a date using the WordPress @see date_i18n function.
1459
-     *
1460
-     * @param string $field_name The EE_Datetime_Field reference for the date being retrieved.
1461
-     * @param string $format     PHP valid date/time string format.  If none is provided then the internal set format
1462
-     *                           on the object will be used.
1463
-     * @return string Date and time string in set locale or false if no field exists for the given
1464
-     * @throws ReflectionException
1465
-     * @throws InvalidArgumentException
1466
-     * @throws InvalidInterfaceException
1467
-     * @throws InvalidDataTypeException
1468
-     * @throws EE_Error
1469
-     *                           field name.
1470
-     */
1471
-    public function get_i18n_datetime($field_name, $format = '')
1472
-    {
1473
-        $format = empty($format) ? $this->_dt_frmt . ' ' . $this->_tm_frmt : $format;
1474
-        return date_i18n(
1475
-            $format,
1476
-            EEH_DTT_Helper::get_timestamp_with_offset(
1477
-                $this->get_raw($field_name),
1478
-                $this->_timezone
1479
-            )
1480
-        );
1481
-    }
1482
-
1483
-
1484
-    /**
1485
-     * This method validates whether the given field name is a valid field on the model object as well as it is of a
1486
-     * type EE_Datetime_Field.  On success there will be returned the field settings.  On fail an EE_Error exception is
1487
-     * thrown.
1488
-     *
1489
-     * @param  string $field_name The field name being checked
1490
-     * @throws ReflectionException
1491
-     * @throws InvalidArgumentException
1492
-     * @throws InvalidInterfaceException
1493
-     * @throws InvalidDataTypeException
1494
-     * @throws EE_Error
1495
-     * @return EE_Datetime_Field
1496
-     */
1497
-    protected function _get_dtt_field_settings($field_name)
1498
-    {
1499
-        $field = $this->get_model()->field_settings_for($field_name);
1500
-        //check if field is dtt
1501
-        if ($field instanceof EE_Datetime_Field) {
1502
-            return $field;
1503
-        }
1504
-        throw new EE_Error(
1505
-            sprintf(
1506
-                esc_html__(
1507
-                    'The field name "%s" has been requested for the EE_Base_Class datetime functions and it is not a valid EE_Datetime_Field.  Please check the spelling of the field and make sure it has been setup as a EE_Datetime_Field in the %s model constructor',
1508
-                    'event_espresso'
1509
-                ),
1510
-                $field_name,
1511
-                self::_get_model_classname(get_class($this))
1512
-            )
1513
-        );
1514
-    }
1515
-
1516
-
1517
-
1518
-
1519
-    /**
1520
-     * NOTE ABOUT BELOW:
1521
-     * These convenience date and time setters are for setting date and time independently.  In other words you might
1522
-     * want to change the time on a datetime_field but leave the date the same (or vice versa). IF on the other hand
1523
-     * you want to set both date and time at the same time, you can just use the models default set($fieldname,$value)
1524
-     * method and make sure you send the entire datetime value for setting.
1525
-     */
1526
-    /**
1527
-     * sets the time on a datetime property
1528
-     *
1529
-     * @access protected
1530
-     * @param string|Datetime $time      a valid time string for php datetime functions (or DateTime object)
1531
-     * @param string          $fieldname the name of the field the time is being set on (must match a EE_Datetime_Field)
1532
-     * @throws ReflectionException
1533
-     * @throws InvalidArgumentException
1534
-     * @throws InvalidInterfaceException
1535
-     * @throws InvalidDataTypeException
1536
-     * @throws EE_Error
1537
-     */
1538
-    protected function _set_time_for($time, $fieldname)
1539
-    {
1540
-        $this->_set_date_time('T', $time, $fieldname);
1541
-    }
1542
-
1543
-
1544
-    /**
1545
-     * sets the date on a datetime property
1546
-     *
1547
-     * @access protected
1548
-     * @param string|DateTime $date      a valid date string for php datetime functions ( or DateTime object)
1549
-     * @param string          $fieldname the name of the field the date is being set on (must match a EE_Datetime_Field)
1550
-     * @throws ReflectionException
1551
-     * @throws InvalidArgumentException
1552
-     * @throws InvalidInterfaceException
1553
-     * @throws InvalidDataTypeException
1554
-     * @throws EE_Error
1555
-     */
1556
-    protected function _set_date_for($date, $fieldname)
1557
-    {
1558
-        $this->_set_date_time('D', $date, $fieldname);
1559
-    }
1560
-
1561
-
1562
-    /**
1563
-     * This takes care of setting a date or time independently on a given model object property. This method also
1564
-     * verifies that the given fieldname matches a model object property and is for a EE_Datetime_Field field
1565
-     *
1566
-     * @access protected
1567
-     * @param string          $what           "T" for time, 'B' for both, 'D' for Date.
1568
-     * @param string|DateTime $datetime_value A valid Date or Time string (or DateTime object)
1569
-     * @param string          $fieldname      the name of the field the date OR time is being set on (must match a
1570
-     *                                        EE_Datetime_Field property)
1571
-     * @throws ReflectionException
1572
-     * @throws InvalidArgumentException
1573
-     * @throws InvalidInterfaceException
1574
-     * @throws InvalidDataTypeException
1575
-     * @throws EE_Error
1576
-     */
1577
-    protected function _set_date_time($what = 'T', $datetime_value, $fieldname)
1578
-    {
1579
-        $field = $this->_get_dtt_field_settings($fieldname);
1580
-        $field->set_timezone($this->_timezone);
1581
-        $field->set_date_format($this->_dt_frmt);
1582
-        $field->set_time_format($this->_tm_frmt);
1583
-        switch ($what) {
1584
-            case 'T' :
1585
-                $this->_fields[ $fieldname ] = $field->prepare_for_set_with_new_time(
1586
-                    $datetime_value,
1587
-                    $this->_fields[ $fieldname ]
1588
-                );
1589
-                break;
1590
-            case 'D' :
1591
-                $this->_fields[ $fieldname ] = $field->prepare_for_set_with_new_date(
1592
-                    $datetime_value,
1593
-                    $this->_fields[ $fieldname ]
1594
-                );
1595
-                break;
1596
-            case 'B' :
1597
-                $this->_fields[ $fieldname ] = $field->prepare_for_set($datetime_value);
1598
-                break;
1599
-        }
1600
-        $this->_clear_cached_property($fieldname);
1601
-    }
1602
-
1603
-
1604
-    /**
1605
-     * This will return a timestamp for the website timezone but ONLY when the current website timezone is different
1606
-     * than the timezone set for the website. NOTE, this currently only works well with methods that return values.  If
1607
-     * you use it with methods that echo values the $_timestamp property may not get reset to its original value and
1608
-     * that could lead to some unexpected results!
1609
-     *
1610
-     * @access public
1611
-     * @param string $field_name               This is the name of the field on the object that contains the date/time
1612
-     *                                         value being returned.
1613
-     * @param string $callback                 must match a valid method in this class (defaults to get_datetime)
1614
-     * @param mixed (array|string) $args       This is the arguments that will be passed to the callback.
1615
-     * @param string $prepend                  You can include something to prepend on the timestamp
1616
-     * @param string $append                   You can include something to append on the timestamp
1617
-     * @throws ReflectionException
1618
-     * @throws InvalidArgumentException
1619
-     * @throws InvalidInterfaceException
1620
-     * @throws InvalidDataTypeException
1621
-     * @throws EE_Error
1622
-     * @return string timestamp
1623
-     */
1624
-    public function display_in_my_timezone(
1625
-        $field_name,
1626
-        $callback = 'get_datetime',
1627
-        $args = null,
1628
-        $prepend = '',
1629
-        $append = ''
1630
-    ) {
1631
-        $timezone = EEH_DTT_Helper::get_timezone();
1632
-        if ($timezone === $this->_timezone) {
1633
-            return '';
1634
-        }
1635
-        $original_timezone = $this->_timezone;
1636
-        $this->set_timezone($timezone);
1637
-        $fn   = (array) $field_name;
1638
-        $args = array_merge($fn, (array) $args);
1639
-        if (! method_exists($this, $callback)) {
1640
-            throw new EE_Error(
1641
-                sprintf(
1642
-                    esc_html__(
1643
-                        'The method named "%s" given as the callback param in "display_in_my_timezone" does not exist.  Please check your spelling',
1644
-                        'event_espresso'
1645
-                    ),
1646
-                    $callback
1647
-                )
1648
-            );
1649
-        }
1650
-        $args   = (array) $args;
1651
-        $return = $prepend . call_user_func_array(array($this, $callback), $args) . $append;
1652
-        $this->set_timezone($original_timezone);
1653
-        return $return;
1654
-    }
1655
-
1656
-
1657
-    /**
1658
-     * Deletes this model object.
1659
-     * This calls the `EE_Base_Class::_delete` method.  Child classes wishing to change default behaviour should
1660
-     * override
1661
-     * `EE_Base_Class::_delete` NOT this class.
1662
-     *
1663
-     * @return boolean | int
1664
-     * @throws ReflectionException
1665
-     * @throws InvalidArgumentException
1666
-     * @throws InvalidInterfaceException
1667
-     * @throws InvalidDataTypeException
1668
-     * @throws EE_Error
1669
-     */
1670
-    public function delete()
1671
-    {
1672
-        /**
1673
-         * Called just before the `EE_Base_Class::_delete` method call.
1674
-         * Note:
1675
-         * `EE_Base_Class::_delete` might be overridden by child classes so any client code hooking into these actions
1676
-         * should be aware that `_delete` may not always result in a permanent delete.
1677
-         * For example, `EE_Soft_Delete_Base_Class::_delete`
1678
-         * soft deletes (trash) the object and does not permanently delete it.
1679
-         *
1680
-         * @param EE_Base_Class $model_object about to be 'deleted'
1681
-         */
1682
-        do_action('AHEE__EE_Base_Class__delete__before', $this);
1683
-        $result = $this->_delete();
1684
-        /**
1685
-         * Called just after the `EE_Base_Class::_delete` method call.
1686
-         * Note:
1687
-         * `EE_Base_Class::_delete` might be overridden by child classes so any client code hooking into these actions
1688
-         * should be aware that `_delete` may not always result in a permanent delete.
1689
-         * For example `EE_Soft_Base_Class::_delete`
1690
-         * soft deletes (trash) the object and does not permanently delete it.
1691
-         *
1692
-         * @param EE_Base_Class $model_object that was just 'deleted'
1693
-         * @param boolean       $result
1694
-         */
1695
-        do_action('AHEE__EE_Base_Class__delete__end', $this, $result);
1696
-        return $result;
1697
-    }
1698
-
1699
-
1700
-    /**
1701
-     * Calls the specific delete method for the instantiated class.
1702
-     * This method is called by the public `EE_Base_Class::delete` method.  Any child classes desiring to override
1703
-     * default functionality for "delete" (which is to call `permanently_delete`) should override this method NOT
1704
-     * `EE_Base_Class::delete`
1705
-     *
1706
-     * @return bool|int
1707
-     * @throws ReflectionException
1708
-     * @throws InvalidArgumentException
1709
-     * @throws InvalidInterfaceException
1710
-     * @throws InvalidDataTypeException
1711
-     * @throws EE_Error
1712
-     */
1713
-    protected function _delete()
1714
-    {
1715
-        return $this->delete_permanently();
1716
-    }
1717
-
1718
-
1719
-    /**
1720
-     * Deletes this model object permanently from db
1721
-     * (but keep in mind related models may block the delete and return an error)
1722
-     *
1723
-     * @return bool | int
1724
-     * @throws ReflectionException
1725
-     * @throws InvalidArgumentException
1726
-     * @throws InvalidInterfaceException
1727
-     * @throws InvalidDataTypeException
1728
-     * @throws EE_Error
1729
-     */
1730
-    public function delete_permanently()
1731
-    {
1732
-        /**
1733
-         * Called just before HARD deleting a model object
1734
-         *
1735
-         * @param EE_Base_Class $model_object about to be 'deleted'
1736
-         */
1737
-        do_action('AHEE__EE_Base_Class__delete_permanently__before', $this);
1738
-        $model  = $this->get_model();
1739
-        $result = $model->delete_permanently_by_ID($this->ID());
1740
-        $this->refresh_cache_of_related_objects();
1741
-        /**
1742
-         * Called just after HARD deleting a model object
1743
-         *
1744
-         * @param EE_Base_Class $model_object that was just 'deleted'
1745
-         * @param boolean       $result
1746
-         */
1747
-        do_action('AHEE__EE_Base_Class__delete_permanently__end', $this, $result);
1748
-        return $result;
1749
-    }
1750
-
1751
-
1752
-    /**
1753
-     * When this model object is deleted, it may still be cached on related model objects. This clears the cache of
1754
-     * related model objects
1755
-     *
1756
-     * @throws ReflectionException
1757
-     * @throws InvalidArgumentException
1758
-     * @throws InvalidInterfaceException
1759
-     * @throws InvalidDataTypeException
1760
-     * @throws EE_Error
1761
-     */
1762
-    public function refresh_cache_of_related_objects()
1763
-    {
1764
-        $model = $this->get_model();
1765
-        foreach ($model->relation_settings() as $relation_name => $relation_obj) {
1766
-            if (! empty($this->_model_relations[ $relation_name ])) {
1767
-                $related_objects = $this->_model_relations[ $relation_name ];
1768
-                if ($relation_obj instanceof EE_Belongs_To_Relation) {
1769
-                    //this relation only stores a single model object, not an array
1770
-                    //but let's make it consistent
1771
-                    $related_objects = array($related_objects);
1772
-                }
1773
-                foreach ($related_objects as $related_object) {
1774
-                    //only refresh their cache if they're in memory
1775
-                    if ($related_object instanceof EE_Base_Class) {
1776
-                        $related_object->clear_cache(
1777
-                            $model->get_this_model_name(),
1778
-                            $this
1779
-                        );
1780
-                    }
1781
-                }
1782
-            }
1783
-        }
1784
-    }
1785
-
1786
-
1787
-    /**
1788
-     *        Saves this object to the database. An array may be supplied to set some values on this
1789
-     * object just before saving.
1790
-     *
1791
-     * @access public
1792
-     * @param array $set_cols_n_values keys are field names, values are their new values,
1793
-     *                                 if provided during the save() method (often client code will change the fields'
1794
-     *                                 values before calling save)
1795
-     * @throws InvalidArgumentException
1796
-     * @throws InvalidInterfaceException
1797
-     * @throws InvalidDataTypeException
1798
-     * @throws EE_Error
1799
-     * @return int , 1 on a successful update, the ID of the new entry on insert; 0 on failure or if the model object
1800
-     *                                 isn't allowed to persist (as determined by EE_Base_Class::allow_persist())
1801
-     * @throws ReflectionException
1802
-     * @throws ReflectionException
1803
-     * @throws ReflectionException
1804
-     */
1805
-    public function save($set_cols_n_values = array())
1806
-    {
1807
-        $model = $this->get_model();
1808
-        /**
1809
-         * Filters the fields we're about to save on the model object
1810
-         *
1811
-         * @param array         $set_cols_n_values
1812
-         * @param EE_Base_Class $model_object
1813
-         */
1814
-        $set_cols_n_values = (array) apply_filters(
1815
-            'FHEE__EE_Base_Class__save__set_cols_n_values',
1816
-            $set_cols_n_values,
1817
-            $this
1818
-        );
1819
-        //set attributes as provided in $set_cols_n_values
1820
-        foreach ($set_cols_n_values as $column => $value) {
1821
-            $this->set($column, $value);
1822
-        }
1823
-        // no changes ? then don't do anything
1824
-        if (! $this->_has_changes && $this->ID() && $model->get_primary_key_field()->is_auto_increment()) {
1825
-            return 0;
1826
-        }
1827
-        /**
1828
-         * Saving a model object.
1829
-         * Before we perform a save, this action is fired.
1830
-         *
1831
-         * @param EE_Base_Class $model_object the model object about to be saved.
1832
-         */
1833
-        do_action('AHEE__EE_Base_Class__save__begin', $this);
1834
-        if (! $this->allow_persist()) {
1835
-            return 0;
1836
-        }
1837
-        // now get current attribute values
1838
-        $save_cols_n_values = $this->_fields;
1839
-        // if the object already has an ID, update it. Otherwise, insert it
1840
-        // also: change the assumption about values passed to the model NOT being prepare dby the model object.
1841
-        // They have been
1842
-        $old_assumption_concerning_value_preparation = $model
1843
-            ->get_assumption_concerning_values_already_prepared_by_model_object();
1844
-        $model->assume_values_already_prepared_by_model_object(true);
1845
-        //does this model have an autoincrement PK?
1846
-        if ($model->has_primary_key_field()) {
1847
-            if ($model->get_primary_key_field()->is_auto_increment()) {
1848
-                //ok check if it's set, if so: update; if not, insert
1849
-                if (! empty($save_cols_n_values[ $model->primary_key_name() ])) {
1850
-                    $results = $model->update_by_ID($save_cols_n_values, $this->ID());
1851
-                } else {
1852
-                    unset($save_cols_n_values[ $model->primary_key_name() ]);
1853
-                    $results = $model->insert($save_cols_n_values);
1854
-                    if ($results) {
1855
-                        //if successful, set the primary key
1856
-                        //but don't use the normal SET method, because it will check if
1857
-                        //an item with the same ID exists in the mapper & db, then
1858
-                        //will find it in the db (because we just added it) and THAT object
1859
-                        //will get added to the mapper before we can add this one!
1860
-                        //but if we just avoid using the SET method, all that headache can be avoided
1861
-                        $pk_field_name                   = $model->primary_key_name();
1862
-                        $this->_fields[ $pk_field_name ] = $results;
1863
-                        $this->_clear_cached_property($pk_field_name);
1864
-                        $model->add_to_entity_map($this);
1865
-                        $this->_update_cached_related_model_objs_fks();
1866
-                    }
1867
-                }
1868
-            } else {//PK is NOT auto-increment
1869
-                //so check if one like it already exists in the db
1870
-                if ($model->exists_by_ID($this->ID())) {
1871
-                    if (WP_DEBUG && ! $this->in_entity_map()) {
1872
-                        throw new EE_Error(
1873
-                            sprintf(
1874
-                                esc_html__(
1875
-                                    'Using a model object %1$s that is NOT in the entity map, can lead to unexpected errors. You should either: %4$s 1. Put it in the entity mapper by calling %2$s %4$s 2. Discard this model object and use what is in the entity mapper %4$s 3. Fetch from the database using %3$s',
1876
-                                    'event_espresso'
1877
-                                ),
1878
-                                get_class($this),
1879
-                                get_class($model) . '::instance()->add_to_entity_map()',
1880
-                                get_class($model) . '::instance()->get_one_by_ID()',
1881
-                                '<br />'
1882
-                            )
1883
-                        );
1884
-                    }
1885
-                    $results = $model->update_by_ID($save_cols_n_values, $this->ID());
1886
-                } else {
1887
-                    $results = $model->insert($save_cols_n_values);
1888
-                    $this->_update_cached_related_model_objs_fks();
1889
-                }
1890
-            }
1891
-        } else {//there is NO primary key
1892
-            $already_in_db = false;
1893
-            foreach ($model->unique_indexes() as $index) {
1894
-                $uniqueness_where_params = array_intersect_key($save_cols_n_values, $index->fields());
1895
-                if ($model->exists(array($uniqueness_where_params))) {
1896
-                    $already_in_db = true;
1897
-                }
1898
-            }
1899
-            if ($already_in_db) {
1900
-                $combined_pk_fields_n_values = array_intersect_key($save_cols_n_values,
1901
-                    $model->get_combined_primary_key_fields());
1902
-                $results                     = $model->update(
1903
-                    $save_cols_n_values,
1904
-                    $combined_pk_fields_n_values
1905
-                );
1906
-            } else {
1907
-                $results = $model->insert($save_cols_n_values);
1908
-            }
1909
-        }
1910
-        //restore the old assumption about values being prepared by the model object
1911
-        $model->assume_values_already_prepared_by_model_object(
1912
-                $old_assumption_concerning_value_preparation
1913
-            );
1914
-        /**
1915
-         * After saving the model object this action is called
1916
-         *
1917
-         * @param EE_Base_Class $model_object which was just saved
1918
-         * @param boolean|int   $results      if it were updated, TRUE or FALSE; if it were newly inserted
1919
-         *                                    the new ID (or 0 if an error occurred and it wasn't updated)
1920
-         */
1921
-        do_action('AHEE__EE_Base_Class__save__end', $this, $results);
1922
-        $this->_has_changes = false;
1923
-        return $results;
1924
-    }
1925
-
1926
-
1927
-    /**
1928
-     * Updates the foreign key on related models objects pointing to this to have this model object's ID
1929
-     * as their foreign key.  If the cached related model objects already exist in the db, saves them (so that the DB
1930
-     * is consistent) Especially useful in case we JUST added this model object ot the database and we want to let its
1931
-     * cached relations with foreign keys to it know about that change. Eg: we've created a transaction but haven't
1932
-     * saved it to the db. We also create a registration and don't save it to the DB, but we DO cache it on the
1933
-     * transaction. Now, when we save the transaction, the registration's TXN_ID will be automatically updated, whether
1934
-     * or not they exist in the DB (if they do, their DB records will be automatically updated)
1935
-     *
1936
-     * @return void
1937
-     * @throws ReflectionException
1938
-     * @throws InvalidArgumentException
1939
-     * @throws InvalidInterfaceException
1940
-     * @throws InvalidDataTypeException
1941
-     * @throws EE_Error
1942
-     */
1943
-    protected function _update_cached_related_model_objs_fks()
1944
-    {
1945
-        $model = $this->get_model();
1946
-        foreach ($model->relation_settings() as $relation_name => $relation_obj) {
1947
-            if ($relation_obj instanceof EE_Has_Many_Relation) {
1948
-                foreach ($this->get_all_from_cache($relation_name) as $related_model_obj_in_cache) {
1949
-                    $fk_to_this = $related_model_obj_in_cache->get_model()->get_foreign_key_to(
1950
-                        $model->get_this_model_name()
1951
-                    );
1952
-                    $related_model_obj_in_cache->set($fk_to_this->get_name(), $this->ID());
1953
-                    if ($related_model_obj_in_cache->ID()) {
1954
-                        $related_model_obj_in_cache->save();
1955
-                    }
1956
-                }
1957
-            }
1958
-        }
1959
-    }
1960
-
1961
-
1962
-    /**
1963
-     * Saves this model object and its NEW cached relations to the database.
1964
-     * (Meaning, for now, IT DOES NOT WORK if the cached items already exist in the DB.
1965
-     * In order for that to work, we would need to mark model objects as dirty/clean...
1966
-     * because otherwise, there's a potential for infinite looping of saving
1967
-     * Saves the cached related model objects, and ensures the relation between them
1968
-     * and this object and properly setup
1969
-     *
1970
-     * @return int ID of new model object on save; 0 on failure+
1971
-     * @throws ReflectionException
1972
-     * @throws InvalidArgumentException
1973
-     * @throws InvalidInterfaceException
1974
-     * @throws InvalidDataTypeException
1975
-     * @throws EE_Error
1976
-     */
1977
-    public function save_new_cached_related_model_objs()
1978
-    {
1979
-        //make sure this has been saved
1980
-        if (! $this->ID()) {
1981
-            $id = $this->save();
1982
-        } else {
1983
-            $id = $this->ID();
1984
-        }
1985
-        //now save all the NEW cached model objects  (ie they don't exist in the DB)
1986
-        foreach ($this->get_model()->relation_settings() as $relationName => $relationObj) {
1987
-            if ($this->_model_relations[ $relationName ]) {
1988
-                //is this a relation where we should expect just ONE related object (ie, EE_Belongs_To_relation)
1989
-                //or MANY related objects (ie, EE_HABTM_Relation or EE_Has_Many_Relation)?
1990
-                /* @var $related_model_obj EE_Base_Class */
1991
-                if ($relationObj instanceof EE_Belongs_To_Relation) {
1992
-                    //add a relation to that relation type (which saves the appropriate thing in the process)
1993
-                    //but ONLY if it DOES NOT exist in the DB
1994
-                    $related_model_obj = $this->_model_relations[ $relationName ];
1995
-                    //					if( ! $related_model_obj->ID()){
1996
-                    $this->_add_relation_to($related_model_obj, $relationName);
1997
-                    $related_model_obj->save_new_cached_related_model_objs();
1998
-                    //					}
1999
-                } else {
2000
-                    foreach ($this->_model_relations[ $relationName ] as $related_model_obj) {
2001
-                        //add a relation to that relation type (which saves the appropriate thing in the process)
2002
-                        //but ONLY if it DOES NOT exist in the DB
2003
-                        //						if( ! $related_model_obj->ID()){
2004
-                        $this->_add_relation_to($related_model_obj, $relationName);
2005
-                        $related_model_obj->save_new_cached_related_model_objs();
2006
-                        //						}
2007
-                    }
2008
-                }
2009
-            }
2010
-        }
2011
-        return $id;
2012
-    }
2013
-
2014
-
2015
-    /**
2016
-     * for getting a model while instantiated.
2017
-     *
2018
-     * @return EEM_Base | EEM_CPT_Base
2019
-     * @throws ReflectionException
2020
-     * @throws InvalidArgumentException
2021
-     * @throws InvalidInterfaceException
2022
-     * @throws InvalidDataTypeException
2023
-     * @throws EE_Error
2024
-     */
2025
-    public function get_model()
2026
-    {
2027
-        if (! $this->_model) {
2028
-            $modelName    = self::_get_model_classname(get_class($this));
2029
-            $this->_model = self::_get_model_instance_with_name($modelName, $this->_timezone);
2030
-        } else {
2031
-            $this->_model->set_timezone($this->_timezone);
2032
-        }
2033
-        return $this->_model;
2034
-    }
2035
-
2036
-
2037
-    /**
2038
-     * @param $props_n_values
2039
-     * @param $classname
2040
-     * @return mixed bool|EE_Base_Class|EEM_CPT_Base
2041
-     * @throws ReflectionException
2042
-     * @throws InvalidArgumentException
2043
-     * @throws InvalidInterfaceException
2044
-     * @throws InvalidDataTypeException
2045
-     * @throws EE_Error
2046
-     */
2047
-    protected static function _get_object_from_entity_mapper($props_n_values, $classname)
2048
-    {
2049
-        //TODO: will not work for Term_Relationships because they have no PK!
2050
-        $primary_id_ref = self::_get_primary_key_name($classname);
2051
-        if (
2052
-            array_key_exists($primary_id_ref, $props_n_values)
2053
-            && ! empty($props_n_values[ $primary_id_ref ])
2054
-        ) {
2055
-            $id = $props_n_values[ $primary_id_ref ];
2056
-            return self::_get_model($classname)->get_from_entity_map($id);
2057
-        }
2058
-        return false;
2059
-    }
2060
-
2061
-
2062
-    /**
2063
-     * This is called by child static "new_instance" method and we'll check to see if there is an existing db entry for
2064
-     * the primary key (if present in incoming values). If there is a key in the incoming array that matches the
2065
-     * primary key for the model AND it is not null, then we check the db. If there's a an object we return it.  If not
2066
-     * we return false.
2067
-     *
2068
-     * @param  array  $props_n_values   incoming array of properties and their values
2069
-     * @param  string $classname        the classname of the child class
2070
-     * @param null    $timezone
2071
-     * @param array   $date_formats     incoming date_formats in an array where the first value is the
2072
-     *                                  date_format and the second value is the time format
2073
-     * @return mixed (EE_Base_Class|bool)
2074
-     * @throws InvalidArgumentException
2075
-     * @throws InvalidInterfaceException
2076
-     * @throws InvalidDataTypeException
2077
-     * @throws EE_Error
2078
-     * @throws ReflectionException
2079
-     * @throws ReflectionException
2080
-     * @throws ReflectionException
2081
-     */
2082
-    protected static function _check_for_object($props_n_values, $classname, $timezone = null, $date_formats = array())
2083
-    {
2084
-        $existing = null;
2085
-        $model    = self::_get_model($classname, $timezone);
2086
-        if ($model->has_primary_key_field()) {
2087
-            $primary_id_ref = self::_get_primary_key_name($classname);
2088
-            if (array_key_exists($primary_id_ref, $props_n_values)
2089
-                && ! empty($props_n_values[ $primary_id_ref ])
2090
-            ) {
2091
-                $existing = $model->get_one_by_ID(
2092
-                    $props_n_values[ $primary_id_ref ]
2093
-                );
2094
-            }
2095
-        } elseif ($model->has_all_combined_primary_key_fields($props_n_values)) {
2096
-            //no primary key on this model, but there's still a matching item in the DB
2097
-            $existing = self::_get_model($classname, $timezone)->get_one_by_ID(
2098
-                self::_get_model($classname, $timezone)
2099
-                    ->get_index_primary_key_string($props_n_values)
2100
-            );
2101
-        }
2102
-        if ($existing) {
2103
-            //set date formats if present before setting values
2104
-            if (! empty($date_formats) && is_array($date_formats)) {
2105
-                $existing->set_date_format($date_formats[0]);
2106
-                $existing->set_time_format($date_formats[1]);
2107
-            } else {
2108
-                //set default formats for date and time
2109
-                $existing->set_date_format(get_option('date_format'));
2110
-                $existing->set_time_format(get_option('time_format'));
2111
-            }
2112
-            foreach ($props_n_values as $property => $field_value) {
2113
-                $existing->set($property, $field_value);
2114
-            }
2115
-            return $existing;
2116
-        }
2117
-        return false;
2118
-    }
2119
-
2120
-
2121
-    /**
2122
-     * Gets the EEM_*_Model for this class
2123
-     *
2124
-     * @access public now, as this is more convenient
2125
-     * @param      $classname
2126
-     * @param null $timezone
2127
-     * @throws ReflectionException
2128
-     * @throws InvalidArgumentException
2129
-     * @throws InvalidInterfaceException
2130
-     * @throws InvalidDataTypeException
2131
-     * @throws EE_Error
2132
-     * @return EEM_Base
2133
-     */
2134
-    protected static function _get_model($classname, $timezone = null)
2135
-    {
2136
-        //find model for this class
2137
-        if (! $classname) {
2138
-            throw new EE_Error(
2139
-                sprintf(
2140
-                    esc_html__(
2141
-                        'What were you thinking calling _get_model(%s)?? You need to specify the class name',
2142
-                        'event_espresso'
2143
-                    ),
2144
-                    $classname
2145
-                )
2146
-            );
2147
-        }
2148
-        $modelName = self::_get_model_classname($classname);
2149
-        return self::_get_model_instance_with_name($modelName, $timezone);
2150
-    }
2151
-
2152
-
2153
-    /**
2154
-     * Gets the model instance (eg instance of EEM_Attendee) given its classname (eg EE_Attendee)
2155
-     *
2156
-     * @param string $model_classname
2157
-     * @param null   $timezone
2158
-     * @return EEM_Base
2159
-     * @throws ReflectionException
2160
-     * @throws InvalidArgumentException
2161
-     * @throws InvalidInterfaceException
2162
-     * @throws InvalidDataTypeException
2163
-     * @throws EE_Error
2164
-     */
2165
-    protected static function _get_model_instance_with_name($model_classname, $timezone = null)
2166
-    {
2167
-        $model_classname = str_replace('EEM_', '', $model_classname);
2168
-        $model           = EE_Registry::instance()->load_model($model_classname);
2169
-        $model->set_timezone($timezone);
2170
-        return $model;
2171
-    }
2172
-
2173
-
2174
-    /**
2175
-     * If a model name is provided (eg Registration), gets the model classname for that model.
2176
-     * Also works if a model class's classname is provided (eg EE_Registration).
2177
-     *
2178
-     * @param null $model_name
2179
-     * @return string like EEM_Attendee
2180
-     */
2181
-    private static function _get_model_classname($model_name = null)
2182
-    {
2183
-        if (strpos($model_name, 'EE_') === 0) {
2184
-            $model_classname = str_replace('EE_', 'EEM_', $model_name);
2185
-        } else {
2186
-            $model_classname = 'EEM_' . $model_name;
2187
-        }
2188
-        return $model_classname;
2189
-    }
2190
-
2191
-
2192
-    /**
2193
-     * returns the name of the primary key attribute
2194
-     *
2195
-     * @param null $classname
2196
-     * @throws ReflectionException
2197
-     * @throws InvalidArgumentException
2198
-     * @throws InvalidInterfaceException
2199
-     * @throws InvalidDataTypeException
2200
-     * @throws EE_Error
2201
-     * @return string
2202
-     */
2203
-    protected static function _get_primary_key_name($classname = null)
2204
-    {
2205
-        if (! $classname) {
2206
-            throw new EE_Error(
2207
-                sprintf(
2208
-                    esc_html__('What were you thinking calling _get_primary_key_name(%s)', 'event_espresso'),
2209
-                    $classname
2210
-                )
2211
-            );
2212
-        }
2213
-        return self::_get_model($classname)->get_primary_key_field()->get_name();
2214
-    }
2215
-
2216
-
2217
-    /**
2218
-     * Gets the value of the primary key.
2219
-     * If the object hasn't yet been saved, it should be whatever the model field's default was
2220
-     * (eg, if this were the EE_Event class, look at the primary key field on EEM_Event and see what its default value
2221
-     * is. Usually defaults for integer primary keys are 0; string primary keys are usually NULL).
2222
-     *
2223
-     * @return mixed, if the primary key is of type INT it'll be an int. Otherwise it could be a string
2224
-     * @throws ReflectionException
2225
-     * @throws InvalidArgumentException
2226
-     * @throws InvalidInterfaceException
2227
-     * @throws InvalidDataTypeException
2228
-     * @throws EE_Error
2229
-     */
2230
-    public function ID()
2231
-    {
2232
-        $model = $this->get_model();
2233
-        //now that we know the name of the variable, use a variable variable to get its value and return its
2234
-        if ($model->has_primary_key_field()) {
2235
-            return $this->_fields[ $model->primary_key_name() ];
2236
-        }
2237
-        return $model->get_index_primary_key_string($this->_fields);
2238
-    }
2239
-
2240
-
2241
-    /**
2242
-     * Adds a relationship to the specified EE_Base_Class object, given the relationship's name. Eg, if the current
2243
-     * model is related to a group of events, the $relationName should be 'Event', and should be a key in the EE
2244
-     * Model's $_model_relations array. If this model object doesn't exist in the DB, just caches the related thing
2245
-     *
2246
-     * @param mixed  $otherObjectModelObjectOrID       EE_Base_Class or the ID of the other object
2247
-     * @param string $relationName                     eg 'Events','Question',etc.
2248
-     *                                                 an attendee to a group, you also want to specify which role they
2249
-     *                                                 will have in that group. So you would use this parameter to
2250
-     *                                                 specify array('role-column-name'=>'role-id')
2251
-     * @param array  $extra_join_model_fields_n_values You can optionally include an array of key=>value pairs that
2252
-     *                                                 allow you to further constrict the relation to being added.
2253
-     *                                                 However, keep in mind that the columns (keys) given must match a
2254
-     *                                                 column on the JOIN table and currently only the HABTM models
2255
-     *                                                 accept these additional conditions.  Also remember that if an
2256
-     *                                                 exact match isn't found for these extra cols/val pairs, then a
2257
-     *                                                 NEW row is created in the join table.
2258
-     * @param null   $cache_id
2259
-     * @throws ReflectionException
2260
-     * @throws InvalidArgumentException
2261
-     * @throws InvalidInterfaceException
2262
-     * @throws InvalidDataTypeException
2263
-     * @throws EE_Error
2264
-     * @return EE_Base_Class the object the relation was added to
2265
-     */
2266
-    public function _add_relation_to(
2267
-        $otherObjectModelObjectOrID,
2268
-        $relationName,
2269
-        $extra_join_model_fields_n_values = array(),
2270
-        $cache_id = null
2271
-    ) {
2272
-        $model = $this->get_model();
2273
-        //if this thing exists in the DB, save the relation to the DB
2274
-        if ($this->ID()) {
2275
-            $otherObject = $model->add_relationship_to(
2276
-                $this,
2277
-                $otherObjectModelObjectOrID,
2278
-                $relationName,
2279
-                $extra_join_model_fields_n_values
2280
-            );
2281
-            //clear cache so future get_many_related and get_first_related() return new results.
2282
-            $this->clear_cache($relationName, $otherObject, true);
2283
-            if ($otherObject instanceof EE_Base_Class) {
2284
-                $otherObject->clear_cache($model->get_this_model_name(), $this);
2285
-            }
2286
-        } else {
2287
-            //this thing doesn't exist in the DB,  so just cache it
2288
-            if (! $otherObjectModelObjectOrID instanceof EE_Base_Class) {
2289
-                throw new EE_Error(
2290
-                    sprintf(
2291
-                        esc_html__(
2292
-                            'Before a model object is saved to the database, calls to _add_relation_to must be passed an actual object, not just an ID. You provided %s as the model object to a %s',
2293
-                            'event_espresso'
2294
-                        ),
2295
-                        $otherObjectModelObjectOrID,
2296
-                        get_class($this)
2297
-                    )
2298
-                );
2299
-            }
2300
-            $otherObject = $otherObjectModelObjectOrID;
2301
-            $this->cache($relationName, $otherObjectModelObjectOrID, $cache_id);
2302
-        }
2303
-        if ($otherObject instanceof EE_Base_Class) {
2304
-            //fix the reciprocal relation too
2305
-            if ($otherObject->ID()) {
2306
-                //its saved so assumed relations exist in the DB, so we can just
2307
-                //clear the cache so future queries use the updated info in the DB
2308
-                $otherObject->clear_cache(
2309
-                    $model->get_this_model_name(),
2310
-                    null,
2311
-                    true
2312
-                );
2313
-            } else {
2314
-                //it's not saved, so it caches relations like this
2315
-                $otherObject->cache($model->get_this_model_name(), $this);
2316
-            }
2317
-        }
2318
-        return $otherObject;
2319
-    }
2320
-
2321
-
2322
-    /**
2323
-     * Removes a relationship to the specified EE_Base_Class object, given the relationships' name. Eg, if the current
2324
-     * model is related to a group of events, the $relationName should be 'Events', and should be a key in the EE
2325
-     * Model's $_model_relations array. If this model object doesn't exist in the DB, just removes the related thing
2326
-     * from the cache
2327
-     *
2328
-     * @param mixed  $otherObjectModelObjectOrID
2329
-     *                EE_Base_Class or the ID of the other object, OR an array key into the cache if this isn't saved
2330
-     *                to the DB yet
2331
-     * @param string $relationName
2332
-     * @param array  $where_query
2333
-     *                You can optionally include an array of key=>value pairs that allow you to further constrict the
2334
-     *                relation to being added. However, keep in mind that the columns (keys) given must match a column
2335
-     *                on the JOIN table and currently only the HABTM models accept these additional conditions. Also
2336
-     *                remember that if an exact match isn't found for these extra cols/val pairs, then a NEW row is
2337
-     *                created in the join table.
2338
-     * @return EE_Base_Class the relation was removed from
2339
-     * @throws ReflectionException
2340
-     * @throws InvalidArgumentException
2341
-     * @throws InvalidInterfaceException
2342
-     * @throws InvalidDataTypeException
2343
-     * @throws EE_Error
2344
-     */
2345
-    public function _remove_relation_to($otherObjectModelObjectOrID, $relationName, $where_query = array())
2346
-    {
2347
-        if ($this->ID()) {
2348
-            //if this exists in the DB, save the relation change to the DB too
2349
-            $otherObject = $this->get_model()->remove_relationship_to(
2350
-                $this,
2351
-                $otherObjectModelObjectOrID,
2352
-                $relationName,
2353
-                $where_query
2354
-            );
2355
-            $this->clear_cache(
2356
-                $relationName,
2357
-                $otherObject
2358
-            );
2359
-        } else {
2360
-            //this doesn't exist in the DB, just remove it from the cache
2361
-            $otherObject = $this->clear_cache(
2362
-                $relationName,
2363
-                $otherObjectModelObjectOrID
2364
-            );
2365
-        }
2366
-        if ($otherObject instanceof EE_Base_Class) {
2367
-            $otherObject->clear_cache(
2368
-                $this->get_model()->get_this_model_name(),
2369
-                $this
2370
-            );
2371
-        }
2372
-        return $otherObject;
2373
-    }
2374
-
2375
-
2376
-    /**
2377
-     * Removes ALL the related things for the $relationName.
2378
-     *
2379
-     * @param string $relationName
2380
-     * @param array  $where_query_params like EEM_Base::get_all's $query_params[0] (where conditions)
2381
-     * @return EE_Base_Class
2382
-     * @throws ReflectionException
2383
-     * @throws InvalidArgumentException
2384
-     * @throws InvalidInterfaceException
2385
-     * @throws InvalidDataTypeException
2386
-     * @throws EE_Error
2387
-     */
2388
-    public function _remove_relations($relationName, $where_query_params = array())
2389
-    {
2390
-        if ($this->ID()) {
2391
-            //if this exists in the DB, save the relation change to the DB too
2392
-            $otherObjects = $this->get_model()->remove_relations(
2393
-                $this,
2394
-                $relationName,
2395
-                $where_query_params
2396
-            );
2397
-            $this->clear_cache(
2398
-                $relationName,
2399
-                null,
2400
-                true
2401
-            );
2402
-        } else {
2403
-            //this doesn't exist in the DB, just remove it from the cache
2404
-            $otherObjects = $this->clear_cache(
2405
-                $relationName,
2406
-                null,
2407
-                true
2408
-            );
2409
-        }
2410
-        if (is_array($otherObjects)) {
2411
-            foreach ($otherObjects as $otherObject) {
2412
-                $otherObject->clear_cache(
2413
-                    $this->get_model()->get_this_model_name(),
2414
-                    $this
2415
-                );
2416
-            }
2417
-        }
2418
-        return $otherObjects;
2419
-    }
2420
-
2421
-
2422
-    /**
2423
-     * Gets all the related model objects of the specified type. Eg, if the current class if
2424
-     * EE_Event, you could call $this->get_many_related('Registration') to get an array of all the
2425
-     * EE_Registration objects which related to this event. Note: by default, we remove the "default query params"
2426
-     * because we want to get even deleted items etc.
2427
-     *
2428
-     * @param string $relationName key in the model's _model_relations array
2429
-     * @param array  $query_params like EEM_Base::get_all
2430
-     * @return EE_Base_Class[]     Results not necessarily indexed by IDs, because some results might not have primary
2431
-     *                             keys or might not be saved yet. Consider using EEM_Base::get_IDs() on these
2432
-     *                             results if you want IDs
2433
-     * @throws ReflectionException
2434
-     * @throws InvalidArgumentException
2435
-     * @throws InvalidInterfaceException
2436
-     * @throws InvalidDataTypeException
2437
-     * @throws EE_Error
2438
-     */
2439
-    public function get_many_related($relationName, $query_params = array())
2440
-    {
2441
-        if ($this->ID()) {
2442
-            //this exists in the DB, so get the related things from either the cache or the DB
2443
-            //if there are query parameters, forget about caching the related model objects.
2444
-            if ($query_params) {
2445
-                $related_model_objects = $this->get_model()->get_all_related(
2446
-                    $this,
2447
-                    $relationName,
2448
-                    $query_params
2449
-                );
2450
-            } else {
2451
-                //did we already cache the result of this query?
2452
-                $cached_results = $this->get_all_from_cache($relationName);
2453
-                if (! $cached_results) {
2454
-                    $related_model_objects = $this->get_model()->get_all_related(
2455
-                        $this,
2456
-                        $relationName,
2457
-                        $query_params
2458
-                    );
2459
-                    //if no query parameters were passed, then we got all the related model objects
2460
-                    //for that relation. We can cache them then.
2461
-                    foreach ($related_model_objects as $related_model_object) {
2462
-                        $this->cache($relationName, $related_model_object);
2463
-                    }
2464
-                } else {
2465
-                    $related_model_objects = $cached_results;
2466
-                }
2467
-            }
2468
-        } else {
2469
-            //this doesn't exist in the DB, so just get the related things from the cache
2470
-            $related_model_objects = $this->get_all_from_cache($relationName);
2471
-        }
2472
-        return $related_model_objects;
2473
-    }
2474
-
2475
-
2476
-    /**
2477
-     * Instead of getting the related model objects, simply counts them. Ignores default_where_conditions by default,
2478
-     * unless otherwise specified in the $query_params
2479
-     *
2480
-     * @param string $relation_name  model_name like 'Event', or 'Registration'
2481
-     * @param array  $query_params   like EEM_Base::get_all's
2482
-     * @param string $field_to_count name of field to count by. By default, uses primary key
2483
-     * @param bool   $distinct       if we want to only count the distinct values for the column then you can trigger
2484
-     *                               that by the setting $distinct to TRUE;
2485
-     * @return int
2486
-     * @throws ReflectionException
2487
-     * @throws InvalidArgumentException
2488
-     * @throws InvalidInterfaceException
2489
-     * @throws InvalidDataTypeException
2490
-     * @throws EE_Error
2491
-     */
2492
-    public function count_related($relation_name, $query_params = array(), $field_to_count = null, $distinct = false)
2493
-    {
2494
-        return $this->get_model()->count_related(
2495
-            $this,
2496
-            $relation_name,
2497
-            $query_params,
2498
-            $field_to_count,
2499
-            $distinct
2500
-        );
2501
-    }
2502
-
2503
-
2504
-    /**
2505
-     * Instead of getting the related model objects, simply sums up the values of the specified field.
2506
-     * Note: ignores default_where_conditions by default, unless otherwise specified in the $query_params
2507
-     *
2508
-     * @param string $relation_name model_name like 'Event', or 'Registration'
2509
-     * @param array  $query_params  like EEM_Base::get_all's
2510
-     * @param string $field_to_sum  name of field to count by.
2511
-     *                              By default, uses primary key
2512
-     *                              (which doesn't make much sense, so you should probably change it)
2513
-     * @return int
2514
-     * @throws ReflectionException
2515
-     * @throws InvalidArgumentException
2516
-     * @throws InvalidInterfaceException
2517
-     * @throws InvalidDataTypeException
2518
-     * @throws EE_Error
2519
-     */
2520
-    public function sum_related($relation_name, $query_params = array(), $field_to_sum = null)
2521
-    {
2522
-        return $this->get_model()->sum_related(
2523
-            $this,
2524
-            $relation_name,
2525
-            $query_params,
2526
-            $field_to_sum
2527
-        );
2528
-    }
2529
-
2530
-
2531
-    /**
2532
-     * Gets the first (ie, one) related model object of the specified type.
2533
-     *
2534
-     * @param string $relationName key in the model's _model_relations array
2535
-     * @param array  $query_params like EEM_Base::get_all
2536
-     * @return EE_Base_Class (not an array, a single object)
2537
-     * @throws ReflectionException
2538
-     * @throws InvalidArgumentException
2539
-     * @throws InvalidInterfaceException
2540
-     * @throws InvalidDataTypeException
2541
-     * @throws EE_Error
2542
-     */
2543
-    public function get_first_related($relationName, $query_params = array())
2544
-    {
2545
-        $model = $this->get_model();
2546
-        if ($this->ID()) {//this exists in the DB, get from the cache OR the DB
2547
-            //if they've provided some query parameters, don't bother trying to cache the result
2548
-            //also make sure we're not caching the result of get_first_related
2549
-            //on a relation which should have an array of objects (because the cache might have an array of objects)
2550
-            if ($query_params
2551
-                || ! $model->related_settings_for($relationName)
2552
-                     instanceof
2553
-                     EE_Belongs_To_Relation
2554
-            ) {
2555
-                $related_model_object = $model->get_first_related(
2556
-                    $this,
2557
-                    $relationName,
2558
-                    $query_params
2559
-                );
2560
-            } else {
2561
-                //first, check if we've already cached the result of this query
2562
-                $cached_result = $this->get_one_from_cache($relationName);
2563
-                if (! $cached_result) {
2564
-                    $related_model_object = $model->get_first_related(
2565
-                        $this,
2566
-                        $relationName,
2567
-                        $query_params
2568
-                    );
2569
-                    $this->cache($relationName, $related_model_object);
2570
-                } else {
2571
-                    $related_model_object = $cached_result;
2572
-                }
2573
-            }
2574
-        } else {
2575
-            $related_model_object = null;
2576
-            // this doesn't exist in the Db,
2577
-            // but maybe the relation is of type belongs to, and so the related thing might
2578
-            if ($model->related_settings_for($relationName) instanceof EE_Belongs_To_Relation) {
2579
-                $related_model_object = $model->get_first_related(
2580
-                    $this,
2581
-                    $relationName,
2582
-                    $query_params
2583
-                );
2584
-            }
2585
-            // this doesn't exist in the DB and apparently the thing it belongs to doesn't either,
2586
-            // just get what's cached on this object
2587
-            if (! $related_model_object) {
2588
-                $related_model_object = $this->get_one_from_cache($relationName);
2589
-            }
2590
-        }
2591
-        return $related_model_object;
2592
-    }
2593
-
2594
-
2595
-    /**
2596
-     * Does a delete on all related objects of type $relationName and removes
2597
-     * the current model object's relation to them. If they can't be deleted (because
2598
-     * of blocking related model objects) does nothing. If the related model objects are
2599
-     * soft-deletable, they will be soft-deleted regardless of related blocking model objects.
2600
-     * If this model object doesn't exist yet in the DB, just removes its related things
2601
-     *
2602
-     * @param string $relationName
2603
-     * @param array  $query_params like EEM_Base::get_all's
2604
-     * @return int how many deleted
2605
-     * @throws ReflectionException
2606
-     * @throws InvalidArgumentException
2607
-     * @throws InvalidInterfaceException
2608
-     * @throws InvalidDataTypeException
2609
-     * @throws EE_Error
2610
-     */
2611
-    public function delete_related($relationName, $query_params = array())
2612
-    {
2613
-        if ($this->ID()) {
2614
-            $count = $this->get_model()->delete_related(
2615
-                $this,
2616
-                $relationName,
2617
-                $query_params
2618
-            );
2619
-        } else {
2620
-            $count = count($this->get_all_from_cache($relationName));
2621
-            $this->clear_cache($relationName, null, true);
2622
-        }
2623
-        return $count;
2624
-    }
2625
-
2626
-
2627
-    /**
2628
-     * Does a hard delete (ie, removes the DB row) on all related objects of type $relationName and removes
2629
-     * the current model object's relation to them. If they can't be deleted (because
2630
-     * of blocking related model objects) just does a soft delete on it instead, if possible.
2631
-     * If the related thing isn't a soft-deletable model object, this function is identical
2632
-     * to delete_related(). If this model object doesn't exist in the DB, just remove its related things
2633
-     *
2634
-     * @param string $relationName
2635
-     * @param array  $query_params like EEM_Base::get_all's
2636
-     * @return int how many deleted (including those soft deleted)
2637
-     * @throws ReflectionException
2638
-     * @throws InvalidArgumentException
2639
-     * @throws InvalidInterfaceException
2640
-     * @throws InvalidDataTypeException
2641
-     * @throws EE_Error
2642
-     */
2643
-    public function delete_related_permanently($relationName, $query_params = array())
2644
-    {
2645
-        if ($this->ID()) {
2646
-            $count = $this->get_model()->delete_related_permanently(
2647
-                $this,
2648
-                $relationName,
2649
-                $query_params
2650
-            );
2651
-        } else {
2652
-            $count = count($this->get_all_from_cache($relationName));
2653
-        }
2654
-        $this->clear_cache($relationName, null, true);
2655
-        return $count;
2656
-    }
2657
-
2658
-
2659
-    /**
2660
-     * is_set
2661
-     * Just a simple utility function children can use for checking if property exists
2662
-     *
2663
-     * @access  public
2664
-     * @param  string $field_name property to check
2665
-     * @return bool                              TRUE if existing,FALSE if not.
2666
-     */
2667
-    public function is_set($field_name)
2668
-    {
2669
-        return isset($this->_fields[ $field_name ]);
2670
-    }
2671
-
2672
-
2673
-    /**
2674
-     * Just a simple utility function children can use for checking if property (or properties) exists and throwing an
2675
-     * EE_Error exception if they don't
2676
-     *
2677
-     * @param  mixed (string|array) $properties properties to check
2678
-     * @throws EE_Error
2679
-     * @return bool                              TRUE if existing, throw EE_Error if not.
2680
-     */
2681
-    protected function _property_exists($properties)
2682
-    {
2683
-        foreach ((array) $properties as $property_name) {
2684
-            //first make sure this property exists
2685
-            if (! $this->_fields[ $property_name ]) {
2686
-                throw new EE_Error(
2687
-                    sprintf(
2688
-                        esc_html__(
2689
-                            'Trying to retrieve a non-existent property (%s).  Double check the spelling please',
2690
-                            'event_espresso'
2691
-                        ),
2692
-                        $property_name
2693
-                    )
2694
-                );
2695
-            }
2696
-        }
2697
-        return true;
2698
-    }
2699
-
2700
-
2701
-    /**
2702
-     * This simply returns an array of model fields for this object
2703
-     *
2704
-     * @return array
2705
-     * @throws ReflectionException
2706
-     * @throws InvalidArgumentException
2707
-     * @throws InvalidInterfaceException
2708
-     * @throws InvalidDataTypeException
2709
-     * @throws EE_Error
2710
-     */
2711
-    public function model_field_array()
2712
-    {
2713
-        $fields     = $this->get_model()->field_settings(false);
2714
-        $properties = array();
2715
-        //remove prepended underscore
2716
-        foreach ($fields as $field_name => $settings) {
2717
-            $properties[ $field_name ] = $this->get($field_name);
2718
-        }
2719
-        return $properties;
2720
-    }
2721
-
2722
-
2723
-    /**
2724
-     * Very handy general function to allow for plugins to extend any child of EE_Base_Class.
2725
-     * If a method is called on a child of EE_Base_Class that doesn't exist, this function is called
2726
-     * (http://www.garfieldtech.com/blog/php-magic-call) and passed the method's name and arguments.
2727
-     * Instead of requiring a plugin to extend the EE_Base_Class
2728
-     * (which works fine is there's only 1 plugin, but when will that happen?)
2729
-     * they can add a hook onto 'filters_hook_espresso__{className}__{methodName}'
2730
-     * (eg, filters_hook_espresso__EE_Answer__my_great_function)
2731
-     * and accepts 2 arguments: the object on which the function was called,
2732
-     * and an array of the original arguments passed to the function.
2733
-     * Whatever their callback function returns will be returned by this function.
2734
-     * Example: in functions.php (or in a plugin):
2735
-     *      add_filter('FHEE__EE_Answer__my_callback','my_callback',10,3);
2736
-     *      function my_callback($previousReturnValue,EE_Base_Class $object,$argsArray){
2737
-     *          $returnString= "you called my_callback! and passed args:".implode(",",$argsArray);
2738
-     *          return $previousReturnValue.$returnString;
2739
-     *      }
2740
-     * require('EE_Answer.class.php');
2741
-     * $answer= EE_Answer::new_instance(array('REG_ID' => 2,'QST_ID' => 3,'ANS_value' => The answer is 42'));
2742
-     * echo $answer->my_callback('monkeys',100);
2743
-     * //will output "you called my_callback! and passed args:monkeys,100"
2744
-     *
2745
-     * @param string $methodName name of method which was called on a child of EE_Base_Class, but which
2746
-     * @param array  $args       array of original arguments passed to the function
2747
-     * @throws EE_Error
2748
-     * @return mixed whatever the plugin which calls add_filter decides
2749
-     */
2750
-    public function __call($methodName, $args)
2751
-    {
2752
-        $className = get_class($this);
2753
-        $tagName   = "FHEE__{$className}__{$methodName}";
2754
-        if (! has_filter($tagName)) {
2755
-            throw new EE_Error(
2756
-                sprintf(
2757
-                    esc_html__(
2758
-                        "Method %s on class %s does not exist! You can create one with the following code in functions.php or in a plugin: add_filter('%s','my_callback',10,3);function my_callback(\$previousReturnValue,EE_Base_Class \$object, \$argsArray){/*function body*/return \$whatever;}",
2759
-                        'event_espresso'
2760
-                    ),
2761
-                    $methodName,
2762
-                    $className,
2763
-                    $tagName
2764
-                )
2765
-            );
2766
-        }
2767
-        return apply_filters($tagName, null, $this, $args);
2768
-    }
2769
-
2770
-
2771
-    /**
2772
-     * Similar to insert_post_meta, adds a record in the Extra_Meta model's table with the given key and value.
2773
-     * A $previous_value can be specified in case there are many meta rows with the same key
2774
-     *
2775
-     * @param string $meta_key
2776
-     * @param mixed  $meta_value
2777
-     * @param mixed  $previous_value
2778
-     * @return bool|int # of records updated (or BOOLEAN if we actually ended up inserting the extra meta row)
2779
-     *                  NOTE: if the values haven't changed, returns 0
2780
-     * @throws InvalidArgumentException
2781
-     * @throws InvalidInterfaceException
2782
-     * @throws InvalidDataTypeException
2783
-     * @throws EE_Error
2784
-     * @throws ReflectionException
2785
-     */
2786
-    public function update_extra_meta($meta_key, $meta_value, $previous_value = null)
2787
-    {
2788
-        $query_params = array(
2789
-            array(
2790
-                'EXM_key'  => $meta_key,
2791
-                'OBJ_ID'   => $this->ID(),
2792
-                'EXM_type' => $this->get_model()->get_this_model_name(),
2793
-            ),
2794
-        );
2795
-        if ($previous_value !== null) {
2796
-            $query_params[0]['EXM_value'] = $meta_value;
2797
-        }
2798
-        $existing_rows_like_that = EEM_Extra_Meta::instance()->get_all($query_params);
2799
-        if (! $existing_rows_like_that) {
2800
-            return $this->add_extra_meta($meta_key, $meta_value);
2801
-        }
2802
-        foreach ($existing_rows_like_that as $existing_row) {
2803
-            $existing_row->save(array('EXM_value' => $meta_value));
2804
-        }
2805
-        return count($existing_rows_like_that);
2806
-    }
2807
-
2808
-
2809
-    /**
2810
-     * Adds a new extra meta record. If $unique is set to TRUE, we'll first double-check
2811
-     * no other extra meta for this model object have the same key. Returns TRUE if the
2812
-     * extra meta row was entered, false if not
2813
-     *
2814
-     * @param string  $meta_key
2815
-     * @param mixed   $meta_value
2816
-     * @param boolean $unique
2817
-     * @return boolean
2818
-     * @throws InvalidArgumentException
2819
-     * @throws InvalidInterfaceException
2820
-     * @throws InvalidDataTypeException
2821
-     * @throws EE_Error
2822
-     * @throws ReflectionException
2823
-     * @throws ReflectionException
2824
-     */
2825
-    public function add_extra_meta($meta_key, $meta_value, $unique = false)
2826
-    {
2827
-        if ($unique) {
2828
-            $existing_extra_meta = EEM_Extra_Meta::instance()->get_one(
2829
-                array(
2830
-                    array(
2831
-                        'EXM_key'  => $meta_key,
2832
-                        'OBJ_ID'   => $this->ID(),
2833
-                        'EXM_type' => $this->get_model()->get_this_model_name(),
2834
-                    ),
2835
-                )
2836
-            );
2837
-            if ($existing_extra_meta) {
2838
-                return false;
2839
-            }
2840
-        }
2841
-        $new_extra_meta = EE_Extra_Meta::new_instance(
2842
-            array(
2843
-                'EXM_key'   => $meta_key,
2844
-                'EXM_value' => $meta_value,
2845
-                'OBJ_ID'    => $this->ID(),
2846
-                'EXM_type'  => $this->get_model()->get_this_model_name(),
2847
-            )
2848
-        );
2849
-        $new_extra_meta->save();
2850
-        return true;
2851
-    }
2852
-
2853
-
2854
-    /**
2855
-     * Deletes all the extra meta rows for this record as specified by key. If $meta_value
2856
-     * is specified, only deletes extra meta records with that value.
2857
-     *
2858
-     * @param string $meta_key
2859
-     * @param mixed  $meta_value
2860
-     * @return int number of extra meta rows deleted
2861
-     * @throws InvalidArgumentException
2862
-     * @throws InvalidInterfaceException
2863
-     * @throws InvalidDataTypeException
2864
-     * @throws EE_Error
2865
-     * @throws ReflectionException
2866
-     */
2867
-    public function delete_extra_meta($meta_key, $meta_value = null)
2868
-    {
2869
-        $query_params = array(
2870
-            array(
2871
-                'EXM_key'  => $meta_key,
2872
-                'OBJ_ID'   => $this->ID(),
2873
-                'EXM_type' => $this->get_model()->get_this_model_name(),
2874
-            ),
2875
-        );
2876
-        if ($meta_value !== null) {
2877
-            $query_params[0]['EXM_value'] = $meta_value;
2878
-        }
2879
-        return EEM_Extra_Meta::instance()->delete($query_params);
2880
-    }
2881
-
2882
-
2883
-    /**
2884
-     * Gets the extra meta with the given meta key. If you specify "single" we just return 1, otherwise
2885
-     * an array of everything found. Requires that this model actually have a relation of type EE_Has_Many_Any_Relation.
2886
-     * You can specify $default is case you haven't found the extra meta
2887
-     *
2888
-     * @param string  $meta_key
2889
-     * @param boolean $single
2890
-     * @param mixed   $default if we don't find anything, what should we return?
2891
-     * @return mixed single value if $single; array if ! $single
2892
-     * @throws ReflectionException
2893
-     * @throws InvalidArgumentException
2894
-     * @throws InvalidInterfaceException
2895
-     * @throws InvalidDataTypeException
2896
-     * @throws EE_Error
2897
-     */
2898
-    public function get_extra_meta($meta_key, $single = false, $default = null)
2899
-    {
2900
-        if ($single) {
2901
-            $result = $this->get_first_related(
2902
-                'Extra_Meta',
2903
-                array(array('EXM_key' => $meta_key))
2904
-            );
2905
-            if ($result instanceof EE_Extra_Meta) {
2906
-                return $result->value();
2907
-            }
2908
-        } else {
2909
-            $results = $this->get_many_related(
2910
-                'Extra_Meta',
2911
-                array(array('EXM_key' => $meta_key))
2912
-            );
2913
-            if ($results) {
2914
-                $values = array();
2915
-                foreach ($results as $result) {
2916
-                    if ($result instanceof EE_Extra_Meta) {
2917
-                        $values[ $result->ID() ] = $result->value();
2918
-                    }
2919
-                }
2920
-                return $values;
2921
-            }
2922
-        }
2923
-        //if nothing discovered yet return default.
2924
-        return apply_filters(
2925
-            'FHEE__EE_Base_Class__get_extra_meta__default_value',
2926
-            $default,
2927
-            $meta_key,
2928
-            $single,
2929
-            $this
2930
-        );
2931
-    }
2932
-
2933
-
2934
-    /**
2935
-     * Returns a simple array of all the extra meta associated with this model object.
2936
-     * If $one_of_each_key is true (Default), it will be an array of simple key-value pairs, keys being the
2937
-     * extra meta's key, and teh value being its value. However, if there are duplicate extra meta rows with
2938
-     * the same key, only one will be used. (eg array('foo'=>'bar','monkey'=>123))
2939
-     * If $one_of_each_key is false, it will return an array with the top-level keys being
2940
-     * the extra meta keys, but their values are also arrays, which have the extra-meta's ID as their sub-key, and
2941
-     * finally the extra meta's value as each sub-value. (eg
2942
-     * array('foo'=>array(1=>'bar',2=>'bill'),'monkey'=>array(3=>123)))
2943
-     *
2944
-     * @param boolean $one_of_each_key
2945
-     * @return array
2946
-     * @throws ReflectionException
2947
-     * @throws InvalidArgumentException
2948
-     * @throws InvalidInterfaceException
2949
-     * @throws InvalidDataTypeException
2950
-     * @throws EE_Error
2951
-     */
2952
-    public function all_extra_meta_array($one_of_each_key = true)
2953
-    {
2954
-        $return_array = array();
2955
-        if ($one_of_each_key) {
2956
-            $extra_meta_objs = $this->get_many_related(
2957
-                'Extra_Meta',
2958
-                array('group_by' => 'EXM_key')
2959
-            );
2960
-            foreach ($extra_meta_objs as $extra_meta_obj) {
2961
-                if ($extra_meta_obj instanceof EE_Extra_Meta) {
2962
-                    $return_array[ $extra_meta_obj->key() ] = $extra_meta_obj->value();
2963
-                }
2964
-            }
2965
-        } else {
2966
-            $extra_meta_objs = $this->get_many_related('Extra_Meta');
2967
-            foreach ($extra_meta_objs as $extra_meta_obj) {
2968
-                if ($extra_meta_obj instanceof EE_Extra_Meta) {
2969
-                    if (! isset($return_array[ $extra_meta_obj->key() ])) {
2970
-                        $return_array[ $extra_meta_obj->key() ] = array();
2971
-                    }
2972
-                    $return_array[ $extra_meta_obj->key() ][ $extra_meta_obj->ID() ] = $extra_meta_obj->value();
2973
-                }
2974
-            }
2975
-        }
2976
-        return $return_array;
2977
-    }
2978
-
2979
-
2980
-    /**
2981
-     * Gets a pretty nice displayable nice for this model object. Often overridden
2982
-     *
2983
-     * @return string
2984
-     * @throws ReflectionException
2985
-     * @throws InvalidArgumentException
2986
-     * @throws InvalidInterfaceException
2987
-     * @throws InvalidDataTypeException
2988
-     * @throws EE_Error
2989
-     */
2990
-    public function name()
2991
-    {
2992
-        //find a field that's not a text field
2993
-        $field_we_can_use = $this->get_model()->get_a_field_of_type('EE_Text_Field_Base');
2994
-        if ($field_we_can_use) {
2995
-            return $this->get($field_we_can_use->get_name());
2996
-        }
2997
-        $first_few_properties = $this->model_field_array();
2998
-        $first_few_properties = array_slice($first_few_properties, 0, 3);
2999
-        $name_parts           = array();
3000
-        foreach ($first_few_properties as $name => $value) {
3001
-            $name_parts[] = "$name:$value";
3002
-        }
3003
-        return implode(',', $name_parts);
3004
-    }
3005
-
3006
-
3007
-    /**
3008
-     * in_entity_map
3009
-     * Checks if this model object has been proven to already be in the entity map
3010
-     *
3011
-     * @return boolean
3012
-     * @throws ReflectionException
3013
-     * @throws InvalidArgumentException
3014
-     * @throws InvalidInterfaceException
3015
-     * @throws InvalidDataTypeException
3016
-     * @throws EE_Error
3017
-     */
3018
-    public function in_entity_map()
3019
-    {
3020
-        // well, if we looked, did we find it in the entity map?
3021
-        return $this->ID() && $this->get_model()->get_from_entity_map($this->ID()) === $this;
3022
-    }
3023
-
3024
-
3025
-    /**
3026
-     * refresh_from_db
3027
-     * Makes sure the fields and values on this model object are in-sync with what's in the database.
3028
-     *
3029
-     * @throws ReflectionException
3030
-     * @throws InvalidArgumentException
3031
-     * @throws InvalidInterfaceException
3032
-     * @throws InvalidDataTypeException
3033
-     * @throws EE_Error if this model object isn't in the entity mapper (because then you should
3034
-     * just use what's in the entity mapper and refresh it) and WP_DEBUG is TRUE
3035
-     */
3036
-    public function refresh_from_db()
3037
-    {
3038
-        if ($this->ID() && $this->in_entity_map()) {
3039
-            $this->get_model()->refresh_entity_map_from_db($this->ID());
3040
-        } else {
3041
-            //if it doesn't have ID, you shouldn't be asking to refresh it from teh database (because its not in the database)
3042
-            //if it has an ID but it's not in the map, and you're asking me to refresh it
3043
-            //that's kinda dangerous. You should just use what's in the entity map, or add this to the entity map if there's
3044
-            //absolutely nothing in it for this ID
3045
-            if (WP_DEBUG) {
3046
-                throw new EE_Error(
3047
-                    sprintf(
3048
-                        esc_html__('Trying to refresh a model object with ID "%1$s" that\'s not in the entity map? First off: you should put it in the entity map by calling %2$s. Second off, if you want what\'s in the database right now, you should just call %3$s yourself and discard this model object.',
3049
-                            'event_espresso'),
3050
-                        $this->ID(),
3051
-                        get_class($this->get_model()) . '::instance()->add_to_entity_map()',
3052
-                        get_class($this->get_model()) . '::instance()->refresh_entity_map()'
3053
-                    )
3054
-                );
3055
-            }
3056
-        }
3057
-    }
3058
-
3059
-
3060
-    /**
3061
-     * Because some other plugins, like Advanced Cron Manager, expect all objects to have this method
3062
-     * (probably a bad assumption they have made, oh well)
3063
-     *
3064
-     * @return string
3065
-     */
3066
-    public function __toString()
3067
-    {
3068
-        try {
3069
-            return sprintf('%s (%s)', $this->name(), $this->ID());
3070
-        } catch (Exception $e) {
3071
-            EE_Error::add_error($e->getMessage(), __FILE__, __FUNCTION__, __LINE__);
3072
-            return '';
3073
-        }
3074
-    }
3075
-
3076
-
3077
-    /**
3078
-     * Clear related model objects if they're already in the DB, because otherwise when we
3079
-     * UN-serialize this model object we'll need to be careful to add them to the entity map.
3080
-     * This means if we have made changes to those related model objects, and want to unserialize
3081
-     * the this model object on a subsequent request, changes to those related model objects will be lost.
3082
-     * Instead, those related model objects should be directly serialized and stored.
3083
-     * Eg, the following won't work:
3084
-     * $reg = EEM_Registration::instance()->get_one_by_ID( 123 );
3085
-     * $att = $reg->attendee();
3086
-     * $att->set( 'ATT_fname', 'Dirk' );
3087
-     * update_option( 'my_option', serialize( $reg ) );
3088
-     * //END REQUEST
3089
-     * //START NEXT REQUEST
3090
-     * $reg = get_option( 'my_option' );
3091
-     * $reg->attendee()->save();
3092
-     * And would need to be replace with:
3093
-     * $reg = EEM_Registration::instance()->get_one_by_ID( 123 );
3094
-     * $att = $reg->attendee();
3095
-     * $att->set( 'ATT_fname', 'Dirk' );
3096
-     * update_option( 'my_option', serialize( $reg ) );
3097
-     * //END REQUEST
3098
-     * //START NEXT REQUEST
3099
-     * $att = get_option( 'my_option' );
3100
-     * $att->save();
3101
-     *
3102
-     * @return array
3103
-     * @throws ReflectionException
3104
-     * @throws InvalidArgumentException
3105
-     * @throws InvalidInterfaceException
3106
-     * @throws InvalidDataTypeException
3107
-     * @throws EE_Error
3108
-     */
3109
-    public function __sleep()
3110
-    {
3111
-        $model = $this->get_model();
3112
-        foreach ($model->relation_settings() as $relation_name => $relation_obj) {
3113
-            if ($relation_obj instanceof EE_Belongs_To_Relation) {
3114
-                $classname = 'EE_' . $model->get_this_model_name();
3115
-                if (
3116
-                    $this->get_one_from_cache($relation_name) instanceof $classname
3117
-                    && $this->get_one_from_cache($relation_name)->ID()
3118
-                ) {
3119
-                    $this->clear_cache(
3120
-                        $relation_name,
3121
-                        $this->get_one_from_cache($relation_name)->ID()
3122
-                    );
3123
-                }
3124
-            }
3125
-        }
3126
-        $this->_props_n_values_provided_in_constructor = array();
3127
-        $properties_to_serialize                       = get_object_vars($this);
3128
-        //don't serialize the model. It's big and that risks recursion
3129
-        unset($properties_to_serialize['_model']);
3130
-        return array_keys($properties_to_serialize);
3131
-    }
3132
-
3133
-
3134
-    /**
3135
-     * restore _props_n_values_provided_in_constructor
3136
-     * PLZ NOTE: this will reset the array to whatever fields values were present prior to serialization,
3137
-     * and therefore should NOT be used to determine if state change has occurred since initial construction.
3138
-     * At best, you would only be able to detect if state change has occurred during THIS request.
3139
-     */
3140
-    public function __wakeup()
3141
-    {
3142
-        $this->_props_n_values_provided_in_constructor = $this->_fields;
3143
-    }
3144
-
3145
-
3146
-    /**
3147
-     * Usage of this magic method is to ensure any internally cached references to object instances that must remain
3148
-     * distinct with the clone host instance are also cloned.
3149
-     */
3150
-    public function __clone()
3151
-    {
3152
-        //handle DateTimes (this is handled in here because there's no one specific child class that uses datetimes).
3153
-        foreach ($this->_fields as $field => $value) {
3154
-            if ($value instanceof DateTime) {
3155
-                $this->_fields[$field] = clone $value;
3156
-            }
3157
-        }
3158
-    }
18
+	/**
19
+	 * This is an array of the original properties and values provided during construction
20
+	 * of this model object. (keys are model field names, values are their values).
21
+	 * This list is important to remember so that when we are merging data from the db, we know
22
+	 * which values to override and which to not override.
23
+	 *
24
+	 * @var array
25
+	 */
26
+	protected $_props_n_values_provided_in_constructor;
27
+
28
+	/**
29
+	 * Timezone
30
+	 * This gets set by the "set_timezone()" method so that we know what timezone incoming strings|timestamps are in.
31
+	 * This can also be used before a get to set what timezone you want strings coming out of the object to be in.  NOT
32
+	 * all EE_Base_Class child classes use this property but any that use a EE_Datetime_Field data type will have
33
+	 * access to it.
34
+	 *
35
+	 * @var string
36
+	 */
37
+	protected $_timezone;
38
+
39
+	/**
40
+	 * date format
41
+	 * pattern or format for displaying dates
42
+	 *
43
+	 * @var string $_dt_frmt
44
+	 */
45
+	protected $_dt_frmt;
46
+
47
+	/**
48
+	 * time format
49
+	 * pattern or format for displaying time
50
+	 *
51
+	 * @var string $_tm_frmt
52
+	 */
53
+	protected $_tm_frmt;
54
+
55
+	/**
56
+	 * This property is for holding a cached array of object properties indexed by property name as the key.
57
+	 * The purpose of this is for setting a cache on properties that may have calculated values after a
58
+	 * prepare_for_get.  That way the cache can be checked first and the calculated property returned instead of having
59
+	 * to recalculate. Used by _set_cached_property() and _get_cached_property() methods.
60
+	 *
61
+	 * @var array
62
+	 */
63
+	protected $_cached_properties = array();
64
+
65
+	/**
66
+	 * An array containing keys of the related model, and values are either an array of related mode objects or a
67
+	 * single
68
+	 * related model object. see the model's _model_relations. The keys should match those specified. And if the
69
+	 * relation is of type EE_Belongs_To (or one of its children), then there should only be ONE related model object,
70
+	 * all others have an array)
71
+	 *
72
+	 * @var array
73
+	 */
74
+	protected $_model_relations = array();
75
+
76
+	/**
77
+	 * Array where keys are field names (see the model's _fields property) and values are their values. To see what
78
+	 * their types should be, look at what that field object returns on its prepare_for_get and prepare_for_set methods)
79
+	 *
80
+	 * @var array
81
+	 */
82
+	protected $_fields = array();
83
+
84
+	/**
85
+	 * @var boolean indicating whether or not this model object is intended to ever be saved
86
+	 * For example, we might create model objects intended to only be used for the duration
87
+	 * of this request and to be thrown away, and if they were accidentally saved
88
+	 * it would be a bug.
89
+	 */
90
+	protected $_allow_persist = true;
91
+
92
+	/**
93
+	 * @var boolean indicating whether or not this model object's properties have changed since construction
94
+	 */
95
+	protected $_has_changes = false;
96
+
97
+	/**
98
+	 * @var EEM_Base
99
+	 */
100
+	protected $_model;
101
+
102
+	/**
103
+	 * This is a cache of results from custom selections done on a query that constructs this entity. The only purpose
104
+	 * for these values is for retrieval of the results, they are not further queryable and they are not persisted to
105
+	 * the db.  They also do not automatically update if there are any changes to the data that produced their results.
106
+	 * The format is a simple array of field_alias => field_value.  So for instance if a custom select was something
107
+	 * like,  "Select COUNT(Registration.REG_ID) as Registration_Count ...", then the resulting value will be in this
108
+	 * array as:
109
+	 * array(
110
+	 *  'Registration_Count' => 24
111
+	 * );
112
+	 * Note: if the custom select configuration for the query included a data type, the value will be in the data type
113
+	 * provided for the query (@see EventEspresso\core\domain\values\model\CustomSelects::__construct phpdocs for more
114
+	 * info)
115
+	 *
116
+	 * @var array
117
+	 */
118
+	protected $custom_selection_results = array();
119
+
120
+
121
+	/**
122
+	 * basic constructor for Event Espresso classes, performs any necessary initialization, and verifies it's children
123
+	 * play nice
124
+	 *
125
+	 * @param array   $fieldValues                             where each key is a field (ie, array key in the 2nd
126
+	 *                                                         layer of the model's _fields array, (eg, EVT_ID,
127
+	 *                                                         TXN_amount, QST_name, etc) and values are their values
128
+	 * @param boolean $bydb                                    a flag for setting if the class is instantiated by the
129
+	 *                                                         corresponding db model or not.
130
+	 * @param string  $timezone                                indicate what timezone you want any datetime fields to
131
+	 *                                                         be in when instantiating a EE_Base_Class object.
132
+	 * @param array   $date_formats                            An array of date formats to set on construct where first
133
+	 *                                                         value is the date_format and second value is the time
134
+	 *                                                         format.
135
+	 * @throws InvalidArgumentException
136
+	 * @throws InvalidInterfaceException
137
+	 * @throws InvalidDataTypeException
138
+	 * @throws EE_Error
139
+	 * @throws ReflectionException
140
+	 */
141
+	protected function __construct($fieldValues = array(), $bydb = false, $timezone = '', $date_formats = array())
142
+	{
143
+		$className = get_class($this);
144
+		do_action("AHEE__{$className}__construct", $this, $fieldValues);
145
+		$model        = $this->get_model();
146
+		$model_fields = $model->field_settings(false);
147
+		// ensure $fieldValues is an array
148
+		$fieldValues = is_array($fieldValues) ? $fieldValues : array($fieldValues);
149
+		// verify client code has not passed any invalid field names
150
+		foreach ($fieldValues as $field_name => $field_value) {
151
+			if (! isset($model_fields[ $field_name ])) {
152
+				throw new EE_Error(
153
+					sprintf(
154
+						esc_html__(
155
+							'Invalid field (%s) passed to constructor of %s. Allowed fields are :%s',
156
+							'event_espresso'
157
+						),
158
+						$field_name,
159
+						get_class($this),
160
+						implode(', ', array_keys($model_fields))
161
+					)
162
+				);
163
+			}
164
+		}
165
+		$this->_timezone = EEH_DTT_Helper::get_valid_timezone_string($timezone);
166
+		if (! empty($date_formats) && is_array($date_formats)) {
167
+			list($this->_dt_frmt, $this->_tm_frmt) = $date_formats;
168
+		} else {
169
+			//set default formats for date and time
170
+			$this->_dt_frmt = (string) get_option('date_format', 'Y-m-d');
171
+			$this->_tm_frmt = (string) get_option('time_format', 'g:i a');
172
+		}
173
+		//if db model is instantiating
174
+		if ($bydb) {
175
+			//client code has indicated these field values are from the database
176
+			foreach ($model_fields as $fieldName => $field) {
177
+				$this->set_from_db(
178
+					$fieldName,
179
+					isset($fieldValues[ $fieldName ]) ? $fieldValues[ $fieldName ] : null
180
+				);
181
+			}
182
+		} else {
183
+			//we're constructing a brand
184
+			//new instance of the model object. Generally, this means we'll need to do more field validation
185
+			foreach ($model_fields as $fieldName => $field) {
186
+				$this->set(
187
+					$fieldName,
188
+					isset($fieldValues[ $fieldName ]) ? $fieldValues[ $fieldName ] : null, true
189
+				);
190
+			}
191
+		}
192
+		//remember what values were passed to this constructor
193
+		$this->_props_n_values_provided_in_constructor = $fieldValues;
194
+		//remember in entity mapper
195
+		if (! $bydb && $model->has_primary_key_field() && $this->ID()) {
196
+			$model->add_to_entity_map($this);
197
+		}
198
+		//setup all the relations
199
+		foreach ($model->relation_settings() as $relation_name => $relation_obj) {
200
+			if ($relation_obj instanceof EE_Belongs_To_Relation) {
201
+				$this->_model_relations[ $relation_name ] = null;
202
+			} else {
203
+				$this->_model_relations[ $relation_name ] = array();
204
+			}
205
+		}
206
+		/**
207
+		 * Action done at the end of each model object construction
208
+		 *
209
+		 * @param EE_Base_Class $this the model object just created
210
+		 */
211
+		do_action('AHEE__EE_Base_Class__construct__finished', $this);
212
+	}
213
+
214
+
215
+	/**
216
+	 * Gets whether or not this model object is allowed to persist/be saved to the database.
217
+	 *
218
+	 * @return boolean
219
+	 */
220
+	public function allow_persist()
221
+	{
222
+		return $this->_allow_persist;
223
+	}
224
+
225
+
226
+	/**
227
+	 * Sets whether or not this model object should be allowed to be saved to the DB.
228
+	 * Normally once this is set to FALSE you wouldn't set it back to TRUE, unless
229
+	 * you got new information that somehow made you change your mind.
230
+	 *
231
+	 * @param boolean $allow_persist
232
+	 * @return boolean
233
+	 */
234
+	public function set_allow_persist($allow_persist)
235
+	{
236
+		return $this->_allow_persist = $allow_persist;
237
+	}
238
+
239
+
240
+	/**
241
+	 * Gets the field's original value when this object was constructed during this request.
242
+	 * This can be helpful when determining if a model object has changed or not
243
+	 *
244
+	 * @param string $field_name
245
+	 * @return mixed|null
246
+	 * @throws ReflectionException
247
+	 * @throws InvalidArgumentException
248
+	 * @throws InvalidInterfaceException
249
+	 * @throws InvalidDataTypeException
250
+	 * @throws EE_Error
251
+	 */
252
+	public function get_original($field_name)
253
+	{
254
+		if (isset($this->_props_n_values_provided_in_constructor[ $field_name ])
255
+			&& $field_settings = $this->get_model()->field_settings_for($field_name)
256
+		) {
257
+			return $field_settings->prepare_for_get($this->_props_n_values_provided_in_constructor[ $field_name ]);
258
+		}
259
+		return null;
260
+	}
261
+
262
+
263
+	/**
264
+	 * @param EE_Base_Class $obj
265
+	 * @return string
266
+	 */
267
+	public function get_class($obj)
268
+	{
269
+		return get_class($obj);
270
+	}
271
+
272
+
273
+	/**
274
+	 * Overrides parent because parent expects old models.
275
+	 * This also doesn't do any validation, and won't work for serialized arrays
276
+	 *
277
+	 * @param    string $field_name
278
+	 * @param    mixed  $field_value
279
+	 * @param bool      $use_default
280
+	 * @throws InvalidArgumentException
281
+	 * @throws InvalidInterfaceException
282
+	 * @throws InvalidDataTypeException
283
+	 * @throws EE_Error
284
+	 * @throws ReflectionException
285
+	 * @throws ReflectionException
286
+	 * @throws ReflectionException
287
+	 */
288
+	public function set($field_name, $field_value, $use_default = false)
289
+	{
290
+		// if not using default and nothing has changed, and object has already been setup (has ID),
291
+		// then don't do anything
292
+		if (
293
+			! $use_default
294
+			&& $this->_fields[ $field_name ] === $field_value
295
+			&& $this->ID()
296
+		) {
297
+			return;
298
+		}
299
+		$model              = $this->get_model();
300
+		$this->_has_changes = true;
301
+		$field_obj          = $model->field_settings_for($field_name);
302
+		if ($field_obj instanceof EE_Model_Field_Base) {
303
+			//			if ( method_exists( $field_obj, 'set_timezone' )) {
304
+			if ($field_obj instanceof EE_Datetime_Field) {
305
+				$field_obj->set_timezone($this->_timezone);
306
+				$field_obj->set_date_format($this->_dt_frmt);
307
+				$field_obj->set_time_format($this->_tm_frmt);
308
+			}
309
+			$holder_of_value = $field_obj->prepare_for_set($field_value);
310
+			//should the value be null?
311
+			if (($field_value === null || $holder_of_value === null || $holder_of_value === '') && $use_default) {
312
+				$this->_fields[ $field_name ] = $field_obj->get_default_value();
313
+				/**
314
+				 * To save having to refactor all the models, if a default value is used for a
315
+				 * EE_Datetime_Field, and that value is not null nor is it a DateTime
316
+				 * object.  Then let's do a set again to ensure that it becomes a DateTime
317
+				 * object.
318
+				 *
319
+				 * @since 4.6.10+
320
+				 */
321
+				if (
322
+					$field_obj instanceof EE_Datetime_Field
323
+					&& $this->_fields[ $field_name ] !== null
324
+					&& ! $this->_fields[ $field_name ] instanceof DateTime
325
+				) {
326
+					empty($this->_fields[ $field_name ])
327
+						? $this->set($field_name, time())
328
+						: $this->set($field_name, $this->_fields[ $field_name ]);
329
+				}
330
+			} else {
331
+				$this->_fields[ $field_name ] = $holder_of_value;
332
+			}
333
+			//if we're not in the constructor...
334
+			//now check if what we set was a primary key
335
+			if (
336
+				//note: props_n_values_provided_in_constructor is only set at the END of the constructor
337
+				$this->_props_n_values_provided_in_constructor
338
+				&& $field_value
339
+				&& $field_name === $model->primary_key_name()
340
+			) {
341
+				//if so, we want all this object's fields to be filled either with
342
+				//what we've explicitly set on this model
343
+				//or what we have in the db
344
+				// echo "setting primary key!";
345
+				$fields_on_model = self::_get_model(get_class($this))->field_settings();
346
+				$obj_in_db       = self::_get_model(get_class($this))->get_one_by_ID($field_value);
347
+				foreach ($fields_on_model as $field_obj) {
348
+					if (! array_key_exists($field_obj->get_name(), $this->_props_n_values_provided_in_constructor)
349
+						&& $field_obj->get_name() !== $field_name
350
+					) {
351
+						$this->set($field_obj->get_name(), $obj_in_db->get($field_obj->get_name()));
352
+					}
353
+				}
354
+				//oh this model object has an ID? well make sure its in the entity mapper
355
+				$model->add_to_entity_map($this);
356
+			}
357
+			//let's unset any cache for this field_name from the $_cached_properties property.
358
+			$this->_clear_cached_property($field_name);
359
+		} else {
360
+			throw new EE_Error(
361
+				sprintf(
362
+					esc_html__(
363
+						'A valid EE_Model_Field_Base could not be found for the given field name: %s',
364
+						'event_espresso'
365
+					),
366
+					$field_name
367
+				)
368
+			);
369
+		}
370
+	}
371
+
372
+
373
+	/**
374
+	 * Set custom select values for model.
375
+	 *
376
+	 * @param array $custom_select_values
377
+	 */
378
+	public function setCustomSelectsValues(array $custom_select_values)
379
+	{
380
+		$this->custom_selection_results = $custom_select_values;
381
+	}
382
+
383
+
384
+	/**
385
+	 * Returns the custom select value for the provided alias if its set.
386
+	 * If not set, returns null.
387
+	 *
388
+	 * @param string $alias
389
+	 * @return string|int|float|null
390
+	 */
391
+	public function getCustomSelect($alias)
392
+	{
393
+		return isset($this->custom_selection_results[ $alias ])
394
+			? $this->custom_selection_results[ $alias ]
395
+			: null;
396
+	}
397
+
398
+
399
+	/**
400
+	 * This sets the field value on the db column if it exists for the given $column_name or
401
+	 * saves it to EE_Extra_Meta if the given $column_name does not match a db column.
402
+	 *
403
+	 * @see EE_message::get_column_value for related documentation on the necessity of this method.
404
+	 * @param string $field_name  Must be the exact column name.
405
+	 * @param mixed  $field_value The value to set.
406
+	 * @return int|bool @see EE_Base_Class::update_extra_meta() for return docs.
407
+	 * @throws InvalidArgumentException
408
+	 * @throws InvalidInterfaceException
409
+	 * @throws InvalidDataTypeException
410
+	 * @throws EE_Error
411
+	 * @throws ReflectionException
412
+	 */
413
+	public function set_field_or_extra_meta($field_name, $field_value)
414
+	{
415
+		if ($this->get_model()->has_field($field_name)) {
416
+			$this->set($field_name, $field_value);
417
+			return true;
418
+		}
419
+		//ensure this object is saved first so that extra meta can be properly related.
420
+		$this->save();
421
+		return $this->update_extra_meta($field_name, $field_value);
422
+	}
423
+
424
+
425
+	/**
426
+	 * This retrieves the value of the db column set on this class or if that's not present
427
+	 * it will attempt to retrieve from extra_meta if found.
428
+	 * Example Usage:
429
+	 * Via EE_Message child class:
430
+	 * Due to the dynamic nature of the EE_messages system, EE_messengers will always have a "to",
431
+	 * "from", "subject", and "content" field (as represented in the EE_Message schema), however they may
432
+	 * also have additional main fields specific to the messenger.  The system accommodates those extra
433
+	 * fields through the EE_Extra_Meta table.  This method allows for EE_messengers to retrieve the
434
+	 * value for those extra fields dynamically via the EE_message object.
435
+	 *
436
+	 * @param  string $field_name expecting the fully qualified field name.
437
+	 * @return mixed|null  value for the field if found.  null if not found.
438
+	 * @throws ReflectionException
439
+	 * @throws InvalidArgumentException
440
+	 * @throws InvalidInterfaceException
441
+	 * @throws InvalidDataTypeException
442
+	 * @throws EE_Error
443
+	 */
444
+	public function get_field_or_extra_meta($field_name)
445
+	{
446
+		if ($this->get_model()->has_field($field_name)) {
447
+			$column_value = $this->get($field_name);
448
+		} else {
449
+			//This isn't a column in the main table, let's see if it is in the extra meta.
450
+			$column_value = $this->get_extra_meta($field_name, true, null);
451
+		}
452
+		return $column_value;
453
+	}
454
+
455
+
456
+	/**
457
+	 * See $_timezone property for description of what the timezone property is for.  This SETS the timezone internally
458
+	 * for being able to reference what timezone we are running conversions on when converting TO the internal timezone
459
+	 * (UTC Unix Timestamp) for the object OR when converting FROM the internal timezone (UTC Unix Timestamp). This is
460
+	 * available to all child classes that may be using the EE_Datetime_Field for a field data type.
461
+	 *
462
+	 * @access public
463
+	 * @param string $timezone A valid timezone string as described by @link http://www.php.net/manual/en/timezones.php
464
+	 * @return void
465
+	 * @throws InvalidArgumentException
466
+	 * @throws InvalidInterfaceException
467
+	 * @throws InvalidDataTypeException
468
+	 * @throws EE_Error
469
+	 * @throws ReflectionException
470
+	 */
471
+	public function set_timezone($timezone = '')
472
+	{
473
+		$this->_timezone = EEH_DTT_Helper::get_valid_timezone_string($timezone);
474
+		//make sure we clear all cached properties because they won't be relevant now
475
+		$this->_clear_cached_properties();
476
+		//make sure we update field settings and the date for all EE_Datetime_Fields
477
+		$model_fields = $this->get_model()->field_settings(false);
478
+		foreach ($model_fields as $field_name => $field_obj) {
479
+			if ($field_obj instanceof EE_Datetime_Field) {
480
+				$field_obj->set_timezone($this->_timezone);
481
+				if (isset($this->_fields[ $field_name ]) && $this->_fields[ $field_name ] instanceof DateTime) {
482
+					$this->_fields[ $field_name ]->setTimezone(new DateTimeZone($this->_timezone));
483
+				}
484
+			}
485
+		}
486
+	}
487
+
488
+
489
+	/**
490
+	 * This just returns whatever is set for the current timezone.
491
+	 *
492
+	 * @access public
493
+	 * @return string timezone string
494
+	 */
495
+	public function get_timezone()
496
+	{
497
+		return $this->_timezone;
498
+	}
499
+
500
+
501
+	/**
502
+	 * This sets the internal date format to what is sent in to be used as the new default for the class
503
+	 * internally instead of wp set date format options
504
+	 *
505
+	 * @since 4.6
506
+	 * @param string $format should be a format recognizable by PHP date() functions.
507
+	 */
508
+	public function set_date_format($format)
509
+	{
510
+		$this->_dt_frmt = $format;
511
+		//clear cached_properties because they won't be relevant now.
512
+		$this->_clear_cached_properties();
513
+	}
514
+
515
+
516
+	/**
517
+	 * This sets the internal time format string to what is sent in to be used as the new default for the
518
+	 * class internally instead of wp set time format options.
519
+	 *
520
+	 * @since 4.6
521
+	 * @param string $format should be a format recognizable by PHP date() functions.
522
+	 */
523
+	public function set_time_format($format)
524
+	{
525
+		$this->_tm_frmt = $format;
526
+		//clear cached_properties because they won't be relevant now.
527
+		$this->_clear_cached_properties();
528
+	}
529
+
530
+
531
+	/**
532
+	 * This returns the current internal set format for the date and time formats.
533
+	 *
534
+	 * @param bool $full           if true (default), then return the full format.  Otherwise will return an array
535
+	 *                             where the first value is the date format and the second value is the time format.
536
+	 * @return mixed string|array
537
+	 */
538
+	public function get_format($full = true)
539
+	{
540
+		return $full ? $this->_dt_frmt . ' ' . $this->_tm_frmt : array($this->_dt_frmt, $this->_tm_frmt);
541
+	}
542
+
543
+
544
+	/**
545
+	 * cache
546
+	 * stores the passed model object on the current model object.
547
+	 * In certain circumstances, we can use this cached model object instead of querying for another one entirely.
548
+	 *
549
+	 * @param string        $relationName    one of the keys in the _model_relations array on the model. Eg
550
+	 *                                       'Registration' associated with this model object
551
+	 * @param EE_Base_Class $object_to_cache that has a relation to this model object. (Eg, if this is a Transaction,
552
+	 *                                       that could be a payment or a registration)
553
+	 * @param null          $cache_id        a string or number that will be used as the key for any Belongs_To_Many
554
+	 *                                       items which will be stored in an array on this object
555
+	 * @throws ReflectionException
556
+	 * @throws InvalidArgumentException
557
+	 * @throws InvalidInterfaceException
558
+	 * @throws InvalidDataTypeException
559
+	 * @throws EE_Error
560
+	 * @return mixed    index into cache, or just TRUE if the relation is of type Belongs_To (because there's only one
561
+	 *                                       related thing, no array)
562
+	 */
563
+	public function cache($relationName = '', $object_to_cache = null, $cache_id = null)
564
+	{
565
+		// its entirely possible that there IS no related object yet in which case there is nothing to cache.
566
+		if (! $object_to_cache instanceof EE_Base_Class) {
567
+			return false;
568
+		}
569
+		// also get "how" the object is related, or throw an error
570
+		if (! $relationship_to_model = $this->get_model()->related_settings_for($relationName)) {
571
+			throw new EE_Error(
572
+				sprintf(
573
+					esc_html__('There is no relationship to %s on a %s. Cannot cache it', 'event_espresso'),
574
+					$relationName,
575
+					get_class($this)
576
+				)
577
+			);
578
+		}
579
+		// how many things are related ?
580
+		if ($relationship_to_model instanceof EE_Belongs_To_Relation) {
581
+			// if it's a "belongs to" relationship, then there's only one related model object
582
+			// eg, if this is a registration, there's only 1 attendee for it
583
+			// so for these model objects just set it to be cached
584
+			$this->_model_relations[ $relationName ] = $object_to_cache;
585
+			$return                                  = true;
586
+		} else {
587
+			// otherwise, this is the "many" side of a one to many relationship,
588
+			// so we'll add the object to the array of related objects for that type.
589
+			// eg: if this is an event, there are many registrations for that event,
590
+			// so we cache the registrations in an array
591
+			if (! is_array($this->_model_relations[ $relationName ])) {
592
+				// if for some reason, the cached item is a model object,
593
+				// then stick that in the array, otherwise start with an empty array
594
+				$this->_model_relations[ $relationName ] = $this->_model_relations[ $relationName ]
595
+														   instanceof
596
+														   EE_Base_Class
597
+					? array($this->_model_relations[ $relationName ]) : array();
598
+			}
599
+			// first check for a cache_id which is normally empty
600
+			if (! empty($cache_id)) {
601
+				// if the cache_id exists, then it means we are purposely trying to cache this
602
+				// with a known key that can then be used to retrieve the object later on
603
+				$this->_model_relations[ $relationName ][ $cache_id ] = $object_to_cache;
604
+				$return                                               = $cache_id;
605
+			} elseif ($object_to_cache->ID()) {
606
+				// OR the cached object originally came from the db, so let's just use it's PK for an ID
607
+				$this->_model_relations[ $relationName ][ $object_to_cache->ID() ] = $object_to_cache;
608
+				$return                                                            = $object_to_cache->ID();
609
+			} else {
610
+				// OR it's a new object with no ID, so just throw it in the array with an auto-incremented ID
611
+				$this->_model_relations[ $relationName ][] = $object_to_cache;
612
+				// move the internal pointer to the end of the array
613
+				end($this->_model_relations[ $relationName ]);
614
+				// and grab the key so that we can return it
615
+				$return = key($this->_model_relations[ $relationName ]);
616
+			}
617
+		}
618
+		return $return;
619
+	}
620
+
621
+
622
+	/**
623
+	 * For adding an item to the cached_properties property.
624
+	 *
625
+	 * @access protected
626
+	 * @param string      $fieldname the property item the corresponding value is for.
627
+	 * @param mixed       $value     The value we are caching.
628
+	 * @param string|null $cache_type
629
+	 * @return void
630
+	 * @throws ReflectionException
631
+	 * @throws InvalidArgumentException
632
+	 * @throws InvalidInterfaceException
633
+	 * @throws InvalidDataTypeException
634
+	 * @throws EE_Error
635
+	 */
636
+	protected function _set_cached_property($fieldname, $value, $cache_type = null)
637
+	{
638
+		//first make sure this property exists
639
+		$this->get_model()->field_settings_for($fieldname);
640
+		$cache_type                                            = empty($cache_type) ? 'standard' : $cache_type;
641
+		$this->_cached_properties[ $fieldname ][ $cache_type ] = $value;
642
+	}
643
+
644
+
645
+	/**
646
+	 * This returns the value cached property if it exists OR the actual property value if the cache doesn't exist.
647
+	 * This also SETS the cache if we return the actual property!
648
+	 *
649
+	 * @param string $fieldname        the name of the property we're trying to retrieve
650
+	 * @param bool   $pretty
651
+	 * @param string $extra_cache_ref  This allows the user to specify an extra cache ref for the given property
652
+	 *                                 (in cases where the same property may be used for different outputs
653
+	 *                                 - i.e. datetime, money etc.)
654
+	 *                                 It can also accept certain pre-defined "schema" strings
655
+	 *                                 to define how to output the property.
656
+	 *                                 see the field's prepare_for_pretty_echoing for what strings can be used
657
+	 * @return mixed                   whatever the value for the property is we're retrieving
658
+	 * @throws ReflectionException
659
+	 * @throws InvalidArgumentException
660
+	 * @throws InvalidInterfaceException
661
+	 * @throws InvalidDataTypeException
662
+	 * @throws EE_Error
663
+	 */
664
+	protected function _get_cached_property($fieldname, $pretty = false, $extra_cache_ref = null)
665
+	{
666
+		//verify the field exists
667
+		$model = $this->get_model();
668
+		$model->field_settings_for($fieldname);
669
+		$cache_type = $pretty ? 'pretty' : 'standard';
670
+		$cache_type .= ! empty($extra_cache_ref) ? '_' . $extra_cache_ref : '';
671
+		if (isset($this->_cached_properties[ $fieldname ][ $cache_type ])) {
672
+			return $this->_cached_properties[ $fieldname ][ $cache_type ];
673
+		}
674
+		$value = $this->_get_fresh_property($fieldname, $pretty, $extra_cache_ref);
675
+		$this->_set_cached_property($fieldname, $value, $cache_type);
676
+		return $value;
677
+	}
678
+
679
+
680
+	/**
681
+	 * If the cache didn't fetch the needed item, this fetches it.
682
+	 *
683
+	 * @param string $fieldname
684
+	 * @param bool   $pretty
685
+	 * @param string $extra_cache_ref
686
+	 * @return mixed
687
+	 * @throws InvalidArgumentException
688
+	 * @throws InvalidInterfaceException
689
+	 * @throws InvalidDataTypeException
690
+	 * @throws EE_Error
691
+	 * @throws ReflectionException
692
+	 */
693
+	protected function _get_fresh_property($fieldname, $pretty = false, $extra_cache_ref = null)
694
+	{
695
+		$field_obj = $this->get_model()->field_settings_for($fieldname);
696
+		// If this is an EE_Datetime_Field we need to make sure timezone, formats, and output are correct
697
+		if ($field_obj instanceof EE_Datetime_Field) {
698
+			$this->_prepare_datetime_field($field_obj, $pretty, $extra_cache_ref);
699
+		}
700
+		if (! isset($this->_fields[ $fieldname ])) {
701
+			$this->_fields[ $fieldname ] = null;
702
+		}
703
+		$value = $pretty
704
+			? $field_obj->prepare_for_pretty_echoing($this->_fields[ $fieldname ], $extra_cache_ref)
705
+			: $field_obj->prepare_for_get($this->_fields[ $fieldname ]);
706
+		return $value;
707
+	}
708
+
709
+
710
+	/**
711
+	 * set timezone, formats, and output for EE_Datetime_Field objects
712
+	 *
713
+	 * @param \EE_Datetime_Field $datetime_field
714
+	 * @param bool               $pretty
715
+	 * @param null               $date_or_time
716
+	 * @return void
717
+	 * @throws InvalidArgumentException
718
+	 * @throws InvalidInterfaceException
719
+	 * @throws InvalidDataTypeException
720
+	 * @throws EE_Error
721
+	 */
722
+	protected function _prepare_datetime_field(
723
+		EE_Datetime_Field $datetime_field,
724
+		$pretty = false,
725
+		$date_or_time = null
726
+	) {
727
+		$datetime_field->set_timezone($this->_timezone);
728
+		$datetime_field->set_date_format($this->_dt_frmt, $pretty);
729
+		$datetime_field->set_time_format($this->_tm_frmt, $pretty);
730
+		//set the output returned
731
+		switch ($date_or_time) {
732
+			case 'D' :
733
+				$datetime_field->set_date_time_output('date');
734
+				break;
735
+			case 'T' :
736
+				$datetime_field->set_date_time_output('time');
737
+				break;
738
+			default :
739
+				$datetime_field->set_date_time_output();
740
+		}
741
+	}
742
+
743
+
744
+	/**
745
+	 * This just takes care of clearing out the cached_properties
746
+	 *
747
+	 * @return void
748
+	 */
749
+	protected function _clear_cached_properties()
750
+	{
751
+		$this->_cached_properties = array();
752
+	}
753
+
754
+
755
+	/**
756
+	 * This just clears out ONE property if it exists in the cache
757
+	 *
758
+	 * @param  string $property_name the property to remove if it exists (from the _cached_properties array)
759
+	 * @return void
760
+	 */
761
+	protected function _clear_cached_property($property_name)
762
+	{
763
+		if (isset($this->_cached_properties[ $property_name ])) {
764
+			unset($this->_cached_properties[ $property_name ]);
765
+		}
766
+	}
767
+
768
+
769
+	/**
770
+	 * Ensures that this related thing is a model object.
771
+	 *
772
+	 * @param mixed  $object_or_id EE_base_Class/int/string either a related model object, or its ID
773
+	 * @param string $model_name   name of the related thing, eg 'Attendee',
774
+	 * @return EE_Base_Class
775
+	 * @throws ReflectionException
776
+	 * @throws InvalidArgumentException
777
+	 * @throws InvalidInterfaceException
778
+	 * @throws InvalidDataTypeException
779
+	 * @throws EE_Error
780
+	 */
781
+	protected function ensure_related_thing_is_model_obj($object_or_id, $model_name)
782
+	{
783
+		$other_model_instance = self::_get_model_instance_with_name(
784
+			self::_get_model_classname($model_name),
785
+			$this->_timezone
786
+		);
787
+		return $other_model_instance->ensure_is_obj($object_or_id);
788
+	}
789
+
790
+
791
+	/**
792
+	 * Forgets the cached model of the given relation Name. So the next time we request it,
793
+	 * we will fetch it again from the database. (Handy if you know it's changed somehow).
794
+	 * If a specific object is supplied, and the relationship to it is either a HasMany or HABTM,
795
+	 * then only remove that one object from our cached array. Otherwise, clear the entire list
796
+	 *
797
+	 * @param string $relationName                         one of the keys in the _model_relations array on the model.
798
+	 *                                                     Eg 'Registration'
799
+	 * @param mixed  $object_to_remove_or_index_into_array or an index into the array of cached things, or NULL
800
+	 *                                                     if you intend to use $clear_all = TRUE, or the relation only
801
+	 *                                                     has 1 object anyways (ie, it's a BelongsToRelation)
802
+	 * @param bool   $clear_all                            This flags clearing the entire cache relation property if
803
+	 *                                                     this is HasMany or HABTM.
804
+	 * @throws ReflectionException
805
+	 * @throws InvalidArgumentException
806
+	 * @throws InvalidInterfaceException
807
+	 * @throws InvalidDataTypeException
808
+	 * @throws EE_Error
809
+	 * @return EE_Base_Class | boolean from which was cleared from the cache, or true if we requested to remove a
810
+	 *                                                     relation from all
811
+	 */
812
+	public function clear_cache($relationName, $object_to_remove_or_index_into_array = null, $clear_all = false)
813
+	{
814
+		$relationship_to_model = $this->get_model()->related_settings_for($relationName);
815
+		$index_in_cache        = '';
816
+		if (! $relationship_to_model) {
817
+			throw new EE_Error(
818
+				sprintf(
819
+					esc_html__('There is no relationship to %s on a %s. Cannot clear that cache', 'event_espresso'),
820
+					$relationName,
821
+					get_class($this)
822
+				)
823
+			);
824
+		}
825
+		if ($clear_all) {
826
+			$obj_removed                             = true;
827
+			$this->_model_relations[ $relationName ] = null;
828
+		} elseif ($relationship_to_model instanceof EE_Belongs_To_Relation) {
829
+			$obj_removed                             = $this->_model_relations[ $relationName ];
830
+			$this->_model_relations[ $relationName ] = null;
831
+		} else {
832
+			if ($object_to_remove_or_index_into_array instanceof EE_Base_Class
833
+				&& $object_to_remove_or_index_into_array->ID()
834
+			) {
835
+				$index_in_cache = $object_to_remove_or_index_into_array->ID();
836
+				if (is_array($this->_model_relations[ $relationName ])
837
+					&& ! isset($this->_model_relations[ $relationName ][ $index_in_cache ])
838
+				) {
839
+					$index_found_at = null;
840
+					//find this object in the array even though it has a different key
841
+					foreach ($this->_model_relations[ $relationName ] as $index => $obj) {
842
+						/** @noinspection TypeUnsafeComparisonInspection */
843
+						if (
844
+							$obj instanceof EE_Base_Class
845
+							&& (
846
+								$obj == $object_to_remove_or_index_into_array
847
+								|| $obj->ID() === $object_to_remove_or_index_into_array->ID()
848
+							)
849
+						) {
850
+							$index_found_at = $index;
851
+							break;
852
+						}
853
+					}
854
+					if ($index_found_at) {
855
+						$index_in_cache = $index_found_at;
856
+					} else {
857
+						//it wasn't found. huh. well obviously it doesn't need to be removed from teh cache
858
+						//if it wasn't in it to begin with. So we're done
859
+						return $object_to_remove_or_index_into_array;
860
+					}
861
+				}
862
+			} elseif ($object_to_remove_or_index_into_array instanceof EE_Base_Class) {
863
+				//so they provided a model object, but it's not yet saved to the DB... so let's go hunting for it!
864
+				foreach ($this->get_all_from_cache($relationName) as $index => $potentially_obj_we_want) {
865
+					/** @noinspection TypeUnsafeComparisonInspection */
866
+					if ($potentially_obj_we_want == $object_to_remove_or_index_into_array) {
867
+						$index_in_cache = $index;
868
+					}
869
+				}
870
+			} else {
871
+				$index_in_cache = $object_to_remove_or_index_into_array;
872
+			}
873
+			//supposedly we've found it. But it could just be that the client code
874
+			//provided a bad index/object
875
+			if (isset($this->_model_relations[ $relationName ][ $index_in_cache ])) {
876
+				$obj_removed = $this->_model_relations[ $relationName ][ $index_in_cache ];
877
+				unset($this->_model_relations[ $relationName ][ $index_in_cache ]);
878
+			} else {
879
+				//that thing was never cached anyways.
880
+				$obj_removed = null;
881
+			}
882
+		}
883
+		return $obj_removed;
884
+	}
885
+
886
+
887
+	/**
888
+	 * update_cache_after_object_save
889
+	 * Allows a cached item to have it's cache ID (within the array of cached items) reset using the new ID it has
890
+	 * obtained after being saved to the db
891
+	 *
892
+	 * @param string        $relationName       - the type of object that is cached
893
+	 * @param EE_Base_Class $newly_saved_object - the newly saved object to be re-cached
894
+	 * @param string        $current_cache_id   - the ID that was used when originally caching the object
895
+	 * @return boolean TRUE on success, FALSE on fail
896
+	 * @throws ReflectionException
897
+	 * @throws InvalidArgumentException
898
+	 * @throws InvalidInterfaceException
899
+	 * @throws InvalidDataTypeException
900
+	 * @throws EE_Error
901
+	 */
902
+	public function update_cache_after_object_save(
903
+		$relationName,
904
+		EE_Base_Class $newly_saved_object,
905
+		$current_cache_id = ''
906
+	) {
907
+		// verify that incoming object is of the correct type
908
+		$obj_class = 'EE_' . $relationName;
909
+		if ($newly_saved_object instanceof $obj_class) {
910
+			/* @type EE_Base_Class $newly_saved_object */
911
+			// now get the type of relation
912
+			$relationship_to_model = $this->get_model()->related_settings_for($relationName);
913
+			// if this is a 1:1 relationship
914
+			if ($relationship_to_model instanceof EE_Belongs_To_Relation) {
915
+				// then just replace the cached object with the newly saved object
916
+				$this->_model_relations[ $relationName ] = $newly_saved_object;
917
+				return true;
918
+				// or if it's some kind of sordid feral polyamorous relationship...
919
+			}
920
+			if (is_array($this->_model_relations[ $relationName ])
921
+					  && isset($this->_model_relations[ $relationName ][ $current_cache_id ])
922
+			) {
923
+				// then remove the current cached item
924
+				unset($this->_model_relations[ $relationName ][ $current_cache_id ]);
925
+				// and cache the newly saved object using it's new ID
926
+				$this->_model_relations[ $relationName ][ $newly_saved_object->ID() ] = $newly_saved_object;
927
+				return true;
928
+			}
929
+		}
930
+		return false;
931
+	}
932
+
933
+
934
+	/**
935
+	 * Fetches a single EE_Base_Class on that relation. (If the relation is of type
936
+	 * BelongsTo, it will only ever have 1 object. However, other relations could have an array of objects)
937
+	 *
938
+	 * @param string $relationName
939
+	 * @return EE_Base_Class
940
+	 */
941
+	public function get_one_from_cache($relationName)
942
+	{
943
+		$cached_array_or_object = isset($this->_model_relations[ $relationName ])
944
+			? $this->_model_relations[ $relationName ]
945
+			: null;
946
+		if (is_array($cached_array_or_object)) {
947
+			return array_shift($cached_array_or_object);
948
+		}
949
+		return $cached_array_or_object;
950
+	}
951
+
952
+
953
+	/**
954
+	 * Fetches a single EE_Base_Class on that relation. (If the relation is of type
955
+	 * BelongsTo, it will only ever have 1 object. However, other relations could have an array of objects)
956
+	 *
957
+	 * @param string $relationName
958
+	 * @throws ReflectionException
959
+	 * @throws InvalidArgumentException
960
+	 * @throws InvalidInterfaceException
961
+	 * @throws InvalidDataTypeException
962
+	 * @throws EE_Error
963
+	 * @return EE_Base_Class[] NOT necessarily indexed by primary keys
964
+	 */
965
+	public function get_all_from_cache($relationName)
966
+	{
967
+		$objects = isset($this->_model_relations[ $relationName ]) ? $this->_model_relations[ $relationName ] : array();
968
+		// if the result is not an array, but exists, make it an array
969
+		$objects = is_array($objects) ? $objects : array($objects);
970
+		//bugfix for https://events.codebasehq.com/projects/event-espresso/tickets/7143
971
+		//basically, if this model object was stored in the session, and these cached model objects
972
+		//already have IDs, let's make sure they're in their model's entity mapper
973
+		//otherwise we will have duplicates next time we call
974
+		// EE_Registry::instance()->load_model( $relationName )->get_one_by_ID( $result->ID() );
975
+		$model = EE_Registry::instance()->load_model($relationName);
976
+		foreach ($objects as $model_object) {
977
+			if ($model instanceof EEM_Base && $model_object instanceof EE_Base_Class) {
978
+				//ensure its in the map if it has an ID; otherwise it will be added to the map when its saved
979
+				if ($model_object->ID()) {
980
+					$model->add_to_entity_map($model_object);
981
+				}
982
+			} else {
983
+				throw new EE_Error(
984
+					sprintf(
985
+						esc_html__(
986
+							'Error retrieving related model objects. Either $1%s is not a model or $2%s is not a model object',
987
+							'event_espresso'
988
+						),
989
+						$relationName,
990
+						gettype($model_object)
991
+					)
992
+				);
993
+			}
994
+		}
995
+		return $objects;
996
+	}
997
+
998
+
999
+	/**
1000
+	 * Returns the next x number of EE_Base_Class objects in sequence from this object as found in the database
1001
+	 * matching the given query conditions.
1002
+	 *
1003
+	 * @param null  $field_to_order_by  What field is being used as the reference point.
1004
+	 * @param int   $limit              How many objects to return.
1005
+	 * @param array $query_params       Any additional conditions on the query.
1006
+	 * @param null  $columns_to_select  If left null, then an array of EE_Base_Class objects is returned, otherwise
1007
+	 *                                  you can indicate just the columns you want returned
1008
+	 * @return array|EE_Base_Class[]
1009
+	 * @throws ReflectionException
1010
+	 * @throws InvalidArgumentException
1011
+	 * @throws InvalidInterfaceException
1012
+	 * @throws InvalidDataTypeException
1013
+	 * @throws EE_Error
1014
+	 */
1015
+	public function next_x($field_to_order_by = null, $limit = 1, $query_params = array(), $columns_to_select = null)
1016
+	{
1017
+		$model         = $this->get_model();
1018
+		$field         = empty($field_to_order_by) && $model->has_primary_key_field()
1019
+			? $model->get_primary_key_field()->get_name()
1020
+			: $field_to_order_by;
1021
+		$current_value = ! empty($field) ? $this->get($field) : null;
1022
+		if (empty($field) || empty($current_value)) {
1023
+			return array();
1024
+		}
1025
+		return $model->next_x($current_value, $field, $limit, $query_params, $columns_to_select);
1026
+	}
1027
+
1028
+
1029
+	/**
1030
+	 * Returns the previous x number of EE_Base_Class objects in sequence from this object as found in the database
1031
+	 * matching the given query conditions.
1032
+	 *
1033
+	 * @param null  $field_to_order_by  What field is being used as the reference point.
1034
+	 * @param int   $limit              How many objects to return.
1035
+	 * @param array $query_params       Any additional conditions on the query.
1036
+	 * @param null  $columns_to_select  If left null, then an array of EE_Base_Class objects is returned, otherwise
1037
+	 *                                  you can indicate just the columns you want returned
1038
+	 * @return array|EE_Base_Class[]
1039
+	 * @throws ReflectionException
1040
+	 * @throws InvalidArgumentException
1041
+	 * @throws InvalidInterfaceException
1042
+	 * @throws InvalidDataTypeException
1043
+	 * @throws EE_Error
1044
+	 */
1045
+	public function previous_x(
1046
+		$field_to_order_by = null,
1047
+		$limit = 1,
1048
+		$query_params = array(),
1049
+		$columns_to_select = null
1050
+	) {
1051
+		$model         = $this->get_model();
1052
+		$field         = empty($field_to_order_by) && $model->has_primary_key_field()
1053
+			? $model->get_primary_key_field()->get_name()
1054
+			: $field_to_order_by;
1055
+		$current_value = ! empty($field) ? $this->get($field) : null;
1056
+		if (empty($field) || empty($current_value)) {
1057
+			return array();
1058
+		}
1059
+		return $model->previous_x($current_value, $field, $limit, $query_params, $columns_to_select);
1060
+	}
1061
+
1062
+
1063
+	/**
1064
+	 * Returns the next EE_Base_Class object in sequence from this object as found in the database
1065
+	 * matching the given query conditions.
1066
+	 *
1067
+	 * @param null  $field_to_order_by  What field is being used as the reference point.
1068
+	 * @param array $query_params       Any additional conditions on the query.
1069
+	 * @param null  $columns_to_select  If left null, then an array of EE_Base_Class objects is returned, otherwise
1070
+	 *                                  you can indicate just the columns you want returned
1071
+	 * @return array|EE_Base_Class
1072
+	 * @throws ReflectionException
1073
+	 * @throws InvalidArgumentException
1074
+	 * @throws InvalidInterfaceException
1075
+	 * @throws InvalidDataTypeException
1076
+	 * @throws EE_Error
1077
+	 */
1078
+	public function next($field_to_order_by = null, $query_params = array(), $columns_to_select = null)
1079
+	{
1080
+		$model         = $this->get_model();
1081
+		$field         = empty($field_to_order_by) && $model->has_primary_key_field()
1082
+			? $model->get_primary_key_field()->get_name()
1083
+			: $field_to_order_by;
1084
+		$current_value = ! empty($field) ? $this->get($field) : null;
1085
+		if (empty($field) || empty($current_value)) {
1086
+			return array();
1087
+		}
1088
+		return $model->next($current_value, $field, $query_params, $columns_to_select);
1089
+	}
1090
+
1091
+
1092
+	/**
1093
+	 * Returns the previous EE_Base_Class object in sequence from this object as found in the database
1094
+	 * matching the given query conditions.
1095
+	 *
1096
+	 * @param null  $field_to_order_by  What field is being used as the reference point.
1097
+	 * @param array $query_params       Any additional conditions on the query.
1098
+	 * @param null  $columns_to_select  If left null, then an EE_Base_Class object is returned, otherwise
1099
+	 *                                  you can indicate just the column you want returned
1100
+	 * @return array|EE_Base_Class
1101
+	 * @throws ReflectionException
1102
+	 * @throws InvalidArgumentException
1103
+	 * @throws InvalidInterfaceException
1104
+	 * @throws InvalidDataTypeException
1105
+	 * @throws EE_Error
1106
+	 */
1107
+	public function previous($field_to_order_by = null, $query_params = array(), $columns_to_select = null)
1108
+	{
1109
+		$model         = $this->get_model();
1110
+		$field         = empty($field_to_order_by) && $model->has_primary_key_field()
1111
+			? $model->get_primary_key_field()->get_name()
1112
+			: $field_to_order_by;
1113
+		$current_value = ! empty($field) ? $this->get($field) : null;
1114
+		if (empty($field) || empty($current_value)) {
1115
+			return array();
1116
+		}
1117
+		return $model->previous($current_value, $field, $query_params, $columns_to_select);
1118
+	}
1119
+
1120
+
1121
+	/**
1122
+	 * Overrides parent because parent expects old models.
1123
+	 * This also doesn't do any validation, and won't work for serialized arrays
1124
+	 *
1125
+	 * @param string $field_name
1126
+	 * @param mixed  $field_value_from_db
1127
+	 * @throws ReflectionException
1128
+	 * @throws InvalidArgumentException
1129
+	 * @throws InvalidInterfaceException
1130
+	 * @throws InvalidDataTypeException
1131
+	 * @throws EE_Error
1132
+	 */
1133
+	public function set_from_db($field_name, $field_value_from_db)
1134
+	{
1135
+		$field_obj = $this->get_model()->field_settings_for($field_name);
1136
+		if ($field_obj instanceof EE_Model_Field_Base) {
1137
+			//you would think the DB has no NULLs for non-null label fields right? wrong!
1138
+			//eg, a CPT model object could have an entry in the posts table, but no
1139
+			//entry in the meta table. Meaning that all its columns in the meta table
1140
+			//are null! yikes! so when we find one like that, use defaults for its meta columns
1141
+			if ($field_value_from_db === null) {
1142
+				if ($field_obj->is_nullable()) {
1143
+					//if the field allows nulls, then let it be null
1144
+					$field_value = null;
1145
+				} else {
1146
+					$field_value = $field_obj->get_default_value();
1147
+				}
1148
+			} else {
1149
+				$field_value = $field_obj->prepare_for_set_from_db($field_value_from_db);
1150
+			}
1151
+			$this->_fields[ $field_name ] = $field_value;
1152
+			$this->_clear_cached_property($field_name);
1153
+		}
1154
+	}
1155
+
1156
+
1157
+	/**
1158
+	 * verifies that the specified field is of the correct type
1159
+	 *
1160
+	 * @param string $field_name
1161
+	 * @param string $extra_cache_ref This allows the user to specify an extra cache ref for the given property
1162
+	 *                                (in cases where the same property may be used for different outputs
1163
+	 *                                - i.e. datetime, money etc.)
1164
+	 * @return mixed
1165
+	 * @throws ReflectionException
1166
+	 * @throws InvalidArgumentException
1167
+	 * @throws InvalidInterfaceException
1168
+	 * @throws InvalidDataTypeException
1169
+	 * @throws EE_Error
1170
+	 */
1171
+	public function get($field_name, $extra_cache_ref = null)
1172
+	{
1173
+		return $this->_get_cached_property($field_name, false, $extra_cache_ref);
1174
+	}
1175
+
1176
+
1177
+	/**
1178
+	 * This method simply returns the RAW unprocessed value for the given property in this class
1179
+	 *
1180
+	 * @param  string $field_name A valid fieldname
1181
+	 * @return mixed              Whatever the raw value stored on the property is.
1182
+	 * @throws ReflectionException
1183
+	 * @throws InvalidArgumentException
1184
+	 * @throws InvalidInterfaceException
1185
+	 * @throws InvalidDataTypeException
1186
+	 * @throws EE_Error if fieldSettings is misconfigured or the field doesn't exist.
1187
+	 */
1188
+	public function get_raw($field_name)
1189
+	{
1190
+		$field_settings = $this->get_model()->field_settings_for($field_name);
1191
+		return $field_settings instanceof EE_Datetime_Field && $this->_fields[ $field_name ] instanceof DateTime
1192
+			? $this->_fields[ $field_name ]->format('U')
1193
+			: $this->_fields[ $field_name ];
1194
+	}
1195
+
1196
+
1197
+	/**
1198
+	 * This is used to return the internal DateTime object used for a field that is a
1199
+	 * EE_Datetime_Field.
1200
+	 *
1201
+	 * @param string $field_name               The field name retrieving the DateTime object.
1202
+	 * @return mixed null | false | DateTime  If the requested field is NOT a EE_Datetime_Field then
1203
+	 * @throws EE_Error an error is set and false returned.  If the field IS an
1204
+	 *                                         EE_Datetime_Field and but the field value is null, then
1205
+	 *                                         just null is returned (because that indicates that likely
1206
+	 *                                         this field is nullable).
1207
+	 * @throws InvalidArgumentException
1208
+	 * @throws InvalidDataTypeException
1209
+	 * @throws InvalidInterfaceException
1210
+	 * @throws ReflectionException
1211
+	 */
1212
+	public function get_DateTime_object($field_name)
1213
+	{
1214
+		$field_settings = $this->get_model()->field_settings_for($field_name);
1215
+		if (! $field_settings instanceof EE_Datetime_Field) {
1216
+			EE_Error::add_error(
1217
+				sprintf(
1218
+					esc_html__(
1219
+						'The field %s is not an EE_Datetime_Field field.  There is no DateTime object stored on this field type.',
1220
+						'event_espresso'
1221
+					),
1222
+					$field_name
1223
+				),
1224
+				__FILE__,
1225
+				__FUNCTION__,
1226
+				__LINE__
1227
+			);
1228
+			return false;
1229
+		}
1230
+		return isset($this->_fields[$field_name]) && $this->_fields[$field_name] instanceof DateTime
1231
+			? clone $this->_fields[$field_name]
1232
+			: null;
1233
+	}
1234
+
1235
+
1236
+	/**
1237
+	 * To be used in template to immediately echo out the value, and format it for output.
1238
+	 * Eg, should call stripslashes and whatnot before echoing
1239
+	 *
1240
+	 * @param string $field_name      the name of the field as it appears in the DB
1241
+	 * @param string $extra_cache_ref This allows the user to specify an extra cache ref for the given property
1242
+	 *                                (in cases where the same property may be used for different outputs
1243
+	 *                                - i.e. datetime, money etc.)
1244
+	 * @return void
1245
+	 * @throws ReflectionException
1246
+	 * @throws InvalidArgumentException
1247
+	 * @throws InvalidInterfaceException
1248
+	 * @throws InvalidDataTypeException
1249
+	 * @throws EE_Error
1250
+	 */
1251
+	public function e($field_name, $extra_cache_ref = null)
1252
+	{
1253
+		echo $this->get_pretty($field_name, $extra_cache_ref);
1254
+	}
1255
+
1256
+
1257
+	/**
1258
+	 * Exactly like e(), echoes out the field, but sets its schema to 'form_input', so that it
1259
+	 * can be easily used as the value of form input.
1260
+	 *
1261
+	 * @param string $field_name
1262
+	 * @return void
1263
+	 * @throws ReflectionException
1264
+	 * @throws InvalidArgumentException
1265
+	 * @throws InvalidInterfaceException
1266
+	 * @throws InvalidDataTypeException
1267
+	 * @throws EE_Error
1268
+	 */
1269
+	public function f($field_name)
1270
+	{
1271
+		$this->e($field_name, 'form_input');
1272
+	}
1273
+
1274
+
1275
+	/**
1276
+	 * Same as `f()` but just returns the value instead of echoing it
1277
+	 *
1278
+	 * @param string $field_name
1279
+	 * @return string
1280
+	 * @throws ReflectionException
1281
+	 * @throws InvalidArgumentException
1282
+	 * @throws InvalidInterfaceException
1283
+	 * @throws InvalidDataTypeException
1284
+	 * @throws EE_Error
1285
+	 */
1286
+	public function get_f($field_name)
1287
+	{
1288
+		return (string) $this->get_pretty($field_name, 'form_input');
1289
+	}
1290
+
1291
+
1292
+	/**
1293
+	 * Gets a pretty view of the field's value. $extra_cache_ref can specify different formats for this.
1294
+	 * The $extra_cache_ref will be passed to the model field's prepare_for_pretty_echoing, so consult the field's class
1295
+	 * to see what options are available.
1296
+	 *
1297
+	 * @param string $field_name
1298
+	 * @param string $extra_cache_ref This allows the user to specify an extra cache ref for the given property
1299
+	 *                                (in cases where the same property may be used for different outputs
1300
+	 *                                - i.e. datetime, money etc.)
1301
+	 * @return mixed
1302
+	 * @throws ReflectionException
1303
+	 * @throws InvalidArgumentException
1304
+	 * @throws InvalidInterfaceException
1305
+	 * @throws InvalidDataTypeException
1306
+	 * @throws EE_Error
1307
+	 */
1308
+	public function get_pretty($field_name, $extra_cache_ref = null)
1309
+	{
1310
+		return $this->_get_cached_property($field_name, true, $extra_cache_ref);
1311
+	}
1312
+
1313
+
1314
+	/**
1315
+	 * This simply returns the datetime for the given field name
1316
+	 * Note: this protected function is called by the wrapper get_date or get_time or get_datetime functions
1317
+	 * (and the equivalent e_date, e_time, e_datetime).
1318
+	 *
1319
+	 * @access   protected
1320
+	 * @param string   $field_name   Field on the instantiated EE_Base_Class child object
1321
+	 * @param string   $dt_frmt      valid datetime format used for date
1322
+	 *                               (if '' then we just use the default on the field,
1323
+	 *                               if NULL we use the last-used format)
1324
+	 * @param string   $tm_frmt      Same as above except this is for time format
1325
+	 * @param string   $date_or_time if NULL then both are returned, otherwise "D" = only date and "T" = only time.
1326
+	 * @param  boolean $echo         Whether the dtt is echoing using pretty echoing or just returned using vanilla get
1327
+	 * @return string|bool|EE_Error string on success, FALSE on fail, or EE_Error Exception is thrown
1328
+	 *                               if field is not a valid dtt field, or void if echoing
1329
+	 * @throws ReflectionException
1330
+	 * @throws InvalidArgumentException
1331
+	 * @throws InvalidInterfaceException
1332
+	 * @throws InvalidDataTypeException
1333
+	 * @throws EE_Error
1334
+	 */
1335
+	protected function _get_datetime($field_name, $dt_frmt = '', $tm_frmt = '', $date_or_time = '', $echo = false)
1336
+	{
1337
+		// clear cached property
1338
+		$this->_clear_cached_property($field_name);
1339
+		//reset format properties because they are used in get()
1340
+		$this->_dt_frmt = $dt_frmt !== '' ? $dt_frmt : $this->_dt_frmt;
1341
+		$this->_tm_frmt = $tm_frmt !== '' ? $tm_frmt : $this->_tm_frmt;
1342
+		if ($echo) {
1343
+			$this->e($field_name, $date_or_time);
1344
+			return '';
1345
+		}
1346
+		return $this->get($field_name, $date_or_time);
1347
+	}
1348
+
1349
+
1350
+	/**
1351
+	 * below are wrapper functions for the various datetime outputs that can be obtained for JUST returning the date
1352
+	 * portion of a datetime value. (note the only difference between get_ and e_ is one returns the value and the
1353
+	 * other echoes the pretty value for dtt)
1354
+	 *
1355
+	 * @param  string $field_name name of model object datetime field holding the value
1356
+	 * @param  string $format     format for the date returned (if NULL we use default in dt_frmt property)
1357
+	 * @return string            datetime value formatted
1358
+	 * @throws ReflectionException
1359
+	 * @throws InvalidArgumentException
1360
+	 * @throws InvalidInterfaceException
1361
+	 * @throws InvalidDataTypeException
1362
+	 * @throws EE_Error
1363
+	 */
1364
+	public function get_date($field_name, $format = '')
1365
+	{
1366
+		return $this->_get_datetime($field_name, $format, null, 'D');
1367
+	}
1368
+
1369
+
1370
+	/**
1371
+	 * @param        $field_name
1372
+	 * @param string $format
1373
+	 * @throws ReflectionException
1374
+	 * @throws InvalidArgumentException
1375
+	 * @throws InvalidInterfaceException
1376
+	 * @throws InvalidDataTypeException
1377
+	 * @throws EE_Error
1378
+	 */
1379
+	public function e_date($field_name, $format = '')
1380
+	{
1381
+		$this->_get_datetime($field_name, $format, null, 'D', true);
1382
+	}
1383
+
1384
+
1385
+	/**
1386
+	 * below are wrapper functions for the various datetime outputs that can be obtained for JUST returning the time
1387
+	 * portion of a datetime value. (note the only difference between get_ and e_ is one returns the value and the
1388
+	 * other echoes the pretty value for dtt)
1389
+	 *
1390
+	 * @param  string $field_name name of model object datetime field holding the value
1391
+	 * @param  string $format     format for the time returned ( if NULL we use default in tm_frmt property)
1392
+	 * @return string             datetime value formatted
1393
+	 * @throws ReflectionException
1394
+	 * @throws InvalidArgumentException
1395
+	 * @throws InvalidInterfaceException
1396
+	 * @throws InvalidDataTypeException
1397
+	 * @throws EE_Error
1398
+	 */
1399
+	public function get_time($field_name, $format = '')
1400
+	{
1401
+		return $this->_get_datetime($field_name, null, $format, 'T');
1402
+	}
1403
+
1404
+
1405
+	/**
1406
+	 * @param        $field_name
1407
+	 * @param string $format
1408
+	 * @throws ReflectionException
1409
+	 * @throws InvalidArgumentException
1410
+	 * @throws InvalidInterfaceException
1411
+	 * @throws InvalidDataTypeException
1412
+	 * @throws EE_Error
1413
+	 */
1414
+	public function e_time($field_name, $format = '')
1415
+	{
1416
+		$this->_get_datetime($field_name, null, $format, 'T', true);
1417
+	}
1418
+
1419
+
1420
+	/**
1421
+	 * below are wrapper functions for the various datetime outputs that can be obtained for returning the date AND
1422
+	 * time portion of a datetime value. (note the only difference between get_ and e_ is one returns the value and the
1423
+	 * other echoes the pretty value for dtt)
1424
+	 *
1425
+	 * @param  string $field_name name of model object datetime field holding the value
1426
+	 * @param  string $dt_frmt    format for the date returned (if NULL we use default in dt_frmt property)
1427
+	 * @param  string $tm_frmt    format for the time returned (if NULL we use default in tm_frmt property)
1428
+	 * @return string             datetime value formatted
1429
+	 * @throws ReflectionException
1430
+	 * @throws InvalidArgumentException
1431
+	 * @throws InvalidInterfaceException
1432
+	 * @throws InvalidDataTypeException
1433
+	 * @throws EE_Error
1434
+	 */
1435
+	public function get_datetime($field_name, $dt_frmt = '', $tm_frmt = '')
1436
+	{
1437
+		return $this->_get_datetime($field_name, $dt_frmt, $tm_frmt);
1438
+	}
1439
+
1440
+
1441
+	/**
1442
+	 * @param string $field_name
1443
+	 * @param string $dt_frmt
1444
+	 * @param string $tm_frmt
1445
+	 * @throws ReflectionException
1446
+	 * @throws InvalidArgumentException
1447
+	 * @throws InvalidInterfaceException
1448
+	 * @throws InvalidDataTypeException
1449
+	 * @throws EE_Error
1450
+	 */
1451
+	public function e_datetime($field_name, $dt_frmt = '', $tm_frmt = '')
1452
+	{
1453
+		$this->_get_datetime($field_name, $dt_frmt, $tm_frmt, null, true);
1454
+	}
1455
+
1456
+
1457
+	/**
1458
+	 * Get the i8ln value for a date using the WordPress @see date_i18n function.
1459
+	 *
1460
+	 * @param string $field_name The EE_Datetime_Field reference for the date being retrieved.
1461
+	 * @param string $format     PHP valid date/time string format.  If none is provided then the internal set format
1462
+	 *                           on the object will be used.
1463
+	 * @return string Date and time string in set locale or false if no field exists for the given
1464
+	 * @throws ReflectionException
1465
+	 * @throws InvalidArgumentException
1466
+	 * @throws InvalidInterfaceException
1467
+	 * @throws InvalidDataTypeException
1468
+	 * @throws EE_Error
1469
+	 *                           field name.
1470
+	 */
1471
+	public function get_i18n_datetime($field_name, $format = '')
1472
+	{
1473
+		$format = empty($format) ? $this->_dt_frmt . ' ' . $this->_tm_frmt : $format;
1474
+		return date_i18n(
1475
+			$format,
1476
+			EEH_DTT_Helper::get_timestamp_with_offset(
1477
+				$this->get_raw($field_name),
1478
+				$this->_timezone
1479
+			)
1480
+		);
1481
+	}
1482
+
1483
+
1484
+	/**
1485
+	 * This method validates whether the given field name is a valid field on the model object as well as it is of a
1486
+	 * type EE_Datetime_Field.  On success there will be returned the field settings.  On fail an EE_Error exception is
1487
+	 * thrown.
1488
+	 *
1489
+	 * @param  string $field_name The field name being checked
1490
+	 * @throws ReflectionException
1491
+	 * @throws InvalidArgumentException
1492
+	 * @throws InvalidInterfaceException
1493
+	 * @throws InvalidDataTypeException
1494
+	 * @throws EE_Error
1495
+	 * @return EE_Datetime_Field
1496
+	 */
1497
+	protected function _get_dtt_field_settings($field_name)
1498
+	{
1499
+		$field = $this->get_model()->field_settings_for($field_name);
1500
+		//check if field is dtt
1501
+		if ($field instanceof EE_Datetime_Field) {
1502
+			return $field;
1503
+		}
1504
+		throw new EE_Error(
1505
+			sprintf(
1506
+				esc_html__(
1507
+					'The field name "%s" has been requested for the EE_Base_Class datetime functions and it is not a valid EE_Datetime_Field.  Please check the spelling of the field and make sure it has been setup as a EE_Datetime_Field in the %s model constructor',
1508
+					'event_espresso'
1509
+				),
1510
+				$field_name,
1511
+				self::_get_model_classname(get_class($this))
1512
+			)
1513
+		);
1514
+	}
1515
+
1516
+
1517
+
1518
+
1519
+	/**
1520
+	 * NOTE ABOUT BELOW:
1521
+	 * These convenience date and time setters are for setting date and time independently.  In other words you might
1522
+	 * want to change the time on a datetime_field but leave the date the same (or vice versa). IF on the other hand
1523
+	 * you want to set both date and time at the same time, you can just use the models default set($fieldname,$value)
1524
+	 * method and make sure you send the entire datetime value for setting.
1525
+	 */
1526
+	/**
1527
+	 * sets the time on a datetime property
1528
+	 *
1529
+	 * @access protected
1530
+	 * @param string|Datetime $time      a valid time string for php datetime functions (or DateTime object)
1531
+	 * @param string          $fieldname the name of the field the time is being set on (must match a EE_Datetime_Field)
1532
+	 * @throws ReflectionException
1533
+	 * @throws InvalidArgumentException
1534
+	 * @throws InvalidInterfaceException
1535
+	 * @throws InvalidDataTypeException
1536
+	 * @throws EE_Error
1537
+	 */
1538
+	protected function _set_time_for($time, $fieldname)
1539
+	{
1540
+		$this->_set_date_time('T', $time, $fieldname);
1541
+	}
1542
+
1543
+
1544
+	/**
1545
+	 * sets the date on a datetime property
1546
+	 *
1547
+	 * @access protected
1548
+	 * @param string|DateTime $date      a valid date string for php datetime functions ( or DateTime object)
1549
+	 * @param string          $fieldname the name of the field the date is being set on (must match a EE_Datetime_Field)
1550
+	 * @throws ReflectionException
1551
+	 * @throws InvalidArgumentException
1552
+	 * @throws InvalidInterfaceException
1553
+	 * @throws InvalidDataTypeException
1554
+	 * @throws EE_Error
1555
+	 */
1556
+	protected function _set_date_for($date, $fieldname)
1557
+	{
1558
+		$this->_set_date_time('D', $date, $fieldname);
1559
+	}
1560
+
1561
+
1562
+	/**
1563
+	 * This takes care of setting a date or time independently on a given model object property. This method also
1564
+	 * verifies that the given fieldname matches a model object property and is for a EE_Datetime_Field field
1565
+	 *
1566
+	 * @access protected
1567
+	 * @param string          $what           "T" for time, 'B' for both, 'D' for Date.
1568
+	 * @param string|DateTime $datetime_value A valid Date or Time string (or DateTime object)
1569
+	 * @param string          $fieldname      the name of the field the date OR time is being set on (must match a
1570
+	 *                                        EE_Datetime_Field property)
1571
+	 * @throws ReflectionException
1572
+	 * @throws InvalidArgumentException
1573
+	 * @throws InvalidInterfaceException
1574
+	 * @throws InvalidDataTypeException
1575
+	 * @throws EE_Error
1576
+	 */
1577
+	protected function _set_date_time($what = 'T', $datetime_value, $fieldname)
1578
+	{
1579
+		$field = $this->_get_dtt_field_settings($fieldname);
1580
+		$field->set_timezone($this->_timezone);
1581
+		$field->set_date_format($this->_dt_frmt);
1582
+		$field->set_time_format($this->_tm_frmt);
1583
+		switch ($what) {
1584
+			case 'T' :
1585
+				$this->_fields[ $fieldname ] = $field->prepare_for_set_with_new_time(
1586
+					$datetime_value,
1587
+					$this->_fields[ $fieldname ]
1588
+				);
1589
+				break;
1590
+			case 'D' :
1591
+				$this->_fields[ $fieldname ] = $field->prepare_for_set_with_new_date(
1592
+					$datetime_value,
1593
+					$this->_fields[ $fieldname ]
1594
+				);
1595
+				break;
1596
+			case 'B' :
1597
+				$this->_fields[ $fieldname ] = $field->prepare_for_set($datetime_value);
1598
+				break;
1599
+		}
1600
+		$this->_clear_cached_property($fieldname);
1601
+	}
1602
+
1603
+
1604
+	/**
1605
+	 * This will return a timestamp for the website timezone but ONLY when the current website timezone is different
1606
+	 * than the timezone set for the website. NOTE, this currently only works well with methods that return values.  If
1607
+	 * you use it with methods that echo values the $_timestamp property may not get reset to its original value and
1608
+	 * that could lead to some unexpected results!
1609
+	 *
1610
+	 * @access public
1611
+	 * @param string $field_name               This is the name of the field on the object that contains the date/time
1612
+	 *                                         value being returned.
1613
+	 * @param string $callback                 must match a valid method in this class (defaults to get_datetime)
1614
+	 * @param mixed (array|string) $args       This is the arguments that will be passed to the callback.
1615
+	 * @param string $prepend                  You can include something to prepend on the timestamp
1616
+	 * @param string $append                   You can include something to append on the timestamp
1617
+	 * @throws ReflectionException
1618
+	 * @throws InvalidArgumentException
1619
+	 * @throws InvalidInterfaceException
1620
+	 * @throws InvalidDataTypeException
1621
+	 * @throws EE_Error
1622
+	 * @return string timestamp
1623
+	 */
1624
+	public function display_in_my_timezone(
1625
+		$field_name,
1626
+		$callback = 'get_datetime',
1627
+		$args = null,
1628
+		$prepend = '',
1629
+		$append = ''
1630
+	) {
1631
+		$timezone = EEH_DTT_Helper::get_timezone();
1632
+		if ($timezone === $this->_timezone) {
1633
+			return '';
1634
+		}
1635
+		$original_timezone = $this->_timezone;
1636
+		$this->set_timezone($timezone);
1637
+		$fn   = (array) $field_name;
1638
+		$args = array_merge($fn, (array) $args);
1639
+		if (! method_exists($this, $callback)) {
1640
+			throw new EE_Error(
1641
+				sprintf(
1642
+					esc_html__(
1643
+						'The method named "%s" given as the callback param in "display_in_my_timezone" does not exist.  Please check your spelling',
1644
+						'event_espresso'
1645
+					),
1646
+					$callback
1647
+				)
1648
+			);
1649
+		}
1650
+		$args   = (array) $args;
1651
+		$return = $prepend . call_user_func_array(array($this, $callback), $args) . $append;
1652
+		$this->set_timezone($original_timezone);
1653
+		return $return;
1654
+	}
1655
+
1656
+
1657
+	/**
1658
+	 * Deletes this model object.
1659
+	 * This calls the `EE_Base_Class::_delete` method.  Child classes wishing to change default behaviour should
1660
+	 * override
1661
+	 * `EE_Base_Class::_delete` NOT this class.
1662
+	 *
1663
+	 * @return boolean | int
1664
+	 * @throws ReflectionException
1665
+	 * @throws InvalidArgumentException
1666
+	 * @throws InvalidInterfaceException
1667
+	 * @throws InvalidDataTypeException
1668
+	 * @throws EE_Error
1669
+	 */
1670
+	public function delete()
1671
+	{
1672
+		/**
1673
+		 * Called just before the `EE_Base_Class::_delete` method call.
1674
+		 * Note:
1675
+		 * `EE_Base_Class::_delete` might be overridden by child classes so any client code hooking into these actions
1676
+		 * should be aware that `_delete` may not always result in a permanent delete.
1677
+		 * For example, `EE_Soft_Delete_Base_Class::_delete`
1678
+		 * soft deletes (trash) the object and does not permanently delete it.
1679
+		 *
1680
+		 * @param EE_Base_Class $model_object about to be 'deleted'
1681
+		 */
1682
+		do_action('AHEE__EE_Base_Class__delete__before', $this);
1683
+		$result = $this->_delete();
1684
+		/**
1685
+		 * Called just after the `EE_Base_Class::_delete` method call.
1686
+		 * Note:
1687
+		 * `EE_Base_Class::_delete` might be overridden by child classes so any client code hooking into these actions
1688
+		 * should be aware that `_delete` may not always result in a permanent delete.
1689
+		 * For example `EE_Soft_Base_Class::_delete`
1690
+		 * soft deletes (trash) the object and does not permanently delete it.
1691
+		 *
1692
+		 * @param EE_Base_Class $model_object that was just 'deleted'
1693
+		 * @param boolean       $result
1694
+		 */
1695
+		do_action('AHEE__EE_Base_Class__delete__end', $this, $result);
1696
+		return $result;
1697
+	}
1698
+
1699
+
1700
+	/**
1701
+	 * Calls the specific delete method for the instantiated class.
1702
+	 * This method is called by the public `EE_Base_Class::delete` method.  Any child classes desiring to override
1703
+	 * default functionality for "delete" (which is to call `permanently_delete`) should override this method NOT
1704
+	 * `EE_Base_Class::delete`
1705
+	 *
1706
+	 * @return bool|int
1707
+	 * @throws ReflectionException
1708
+	 * @throws InvalidArgumentException
1709
+	 * @throws InvalidInterfaceException
1710
+	 * @throws InvalidDataTypeException
1711
+	 * @throws EE_Error
1712
+	 */
1713
+	protected function _delete()
1714
+	{
1715
+		return $this->delete_permanently();
1716
+	}
1717
+
1718
+
1719
+	/**
1720
+	 * Deletes this model object permanently from db
1721
+	 * (but keep in mind related models may block the delete and return an error)
1722
+	 *
1723
+	 * @return bool | int
1724
+	 * @throws ReflectionException
1725
+	 * @throws InvalidArgumentException
1726
+	 * @throws InvalidInterfaceException
1727
+	 * @throws InvalidDataTypeException
1728
+	 * @throws EE_Error
1729
+	 */
1730
+	public function delete_permanently()
1731
+	{
1732
+		/**
1733
+		 * Called just before HARD deleting a model object
1734
+		 *
1735
+		 * @param EE_Base_Class $model_object about to be 'deleted'
1736
+		 */
1737
+		do_action('AHEE__EE_Base_Class__delete_permanently__before', $this);
1738
+		$model  = $this->get_model();
1739
+		$result = $model->delete_permanently_by_ID($this->ID());
1740
+		$this->refresh_cache_of_related_objects();
1741
+		/**
1742
+		 * Called just after HARD deleting a model object
1743
+		 *
1744
+		 * @param EE_Base_Class $model_object that was just 'deleted'
1745
+		 * @param boolean       $result
1746
+		 */
1747
+		do_action('AHEE__EE_Base_Class__delete_permanently__end', $this, $result);
1748
+		return $result;
1749
+	}
1750
+
1751
+
1752
+	/**
1753
+	 * When this model object is deleted, it may still be cached on related model objects. This clears the cache of
1754
+	 * related model objects
1755
+	 *
1756
+	 * @throws ReflectionException
1757
+	 * @throws InvalidArgumentException
1758
+	 * @throws InvalidInterfaceException
1759
+	 * @throws InvalidDataTypeException
1760
+	 * @throws EE_Error
1761
+	 */
1762
+	public function refresh_cache_of_related_objects()
1763
+	{
1764
+		$model = $this->get_model();
1765
+		foreach ($model->relation_settings() as $relation_name => $relation_obj) {
1766
+			if (! empty($this->_model_relations[ $relation_name ])) {
1767
+				$related_objects = $this->_model_relations[ $relation_name ];
1768
+				if ($relation_obj instanceof EE_Belongs_To_Relation) {
1769
+					//this relation only stores a single model object, not an array
1770
+					//but let's make it consistent
1771
+					$related_objects = array($related_objects);
1772
+				}
1773
+				foreach ($related_objects as $related_object) {
1774
+					//only refresh their cache if they're in memory
1775
+					if ($related_object instanceof EE_Base_Class) {
1776
+						$related_object->clear_cache(
1777
+							$model->get_this_model_name(),
1778
+							$this
1779
+						);
1780
+					}
1781
+				}
1782
+			}
1783
+		}
1784
+	}
1785
+
1786
+
1787
+	/**
1788
+	 *        Saves this object to the database. An array may be supplied to set some values on this
1789
+	 * object just before saving.
1790
+	 *
1791
+	 * @access public
1792
+	 * @param array $set_cols_n_values keys are field names, values are their new values,
1793
+	 *                                 if provided during the save() method (often client code will change the fields'
1794
+	 *                                 values before calling save)
1795
+	 * @throws InvalidArgumentException
1796
+	 * @throws InvalidInterfaceException
1797
+	 * @throws InvalidDataTypeException
1798
+	 * @throws EE_Error
1799
+	 * @return int , 1 on a successful update, the ID of the new entry on insert; 0 on failure or if the model object
1800
+	 *                                 isn't allowed to persist (as determined by EE_Base_Class::allow_persist())
1801
+	 * @throws ReflectionException
1802
+	 * @throws ReflectionException
1803
+	 * @throws ReflectionException
1804
+	 */
1805
+	public function save($set_cols_n_values = array())
1806
+	{
1807
+		$model = $this->get_model();
1808
+		/**
1809
+		 * Filters the fields we're about to save on the model object
1810
+		 *
1811
+		 * @param array         $set_cols_n_values
1812
+		 * @param EE_Base_Class $model_object
1813
+		 */
1814
+		$set_cols_n_values = (array) apply_filters(
1815
+			'FHEE__EE_Base_Class__save__set_cols_n_values',
1816
+			$set_cols_n_values,
1817
+			$this
1818
+		);
1819
+		//set attributes as provided in $set_cols_n_values
1820
+		foreach ($set_cols_n_values as $column => $value) {
1821
+			$this->set($column, $value);
1822
+		}
1823
+		// no changes ? then don't do anything
1824
+		if (! $this->_has_changes && $this->ID() && $model->get_primary_key_field()->is_auto_increment()) {
1825
+			return 0;
1826
+		}
1827
+		/**
1828
+		 * Saving a model object.
1829
+		 * Before we perform a save, this action is fired.
1830
+		 *
1831
+		 * @param EE_Base_Class $model_object the model object about to be saved.
1832
+		 */
1833
+		do_action('AHEE__EE_Base_Class__save__begin', $this);
1834
+		if (! $this->allow_persist()) {
1835
+			return 0;
1836
+		}
1837
+		// now get current attribute values
1838
+		$save_cols_n_values = $this->_fields;
1839
+		// if the object already has an ID, update it. Otherwise, insert it
1840
+		// also: change the assumption about values passed to the model NOT being prepare dby the model object.
1841
+		// They have been
1842
+		$old_assumption_concerning_value_preparation = $model
1843
+			->get_assumption_concerning_values_already_prepared_by_model_object();
1844
+		$model->assume_values_already_prepared_by_model_object(true);
1845
+		//does this model have an autoincrement PK?
1846
+		if ($model->has_primary_key_field()) {
1847
+			if ($model->get_primary_key_field()->is_auto_increment()) {
1848
+				//ok check if it's set, if so: update; if not, insert
1849
+				if (! empty($save_cols_n_values[ $model->primary_key_name() ])) {
1850
+					$results = $model->update_by_ID($save_cols_n_values, $this->ID());
1851
+				} else {
1852
+					unset($save_cols_n_values[ $model->primary_key_name() ]);
1853
+					$results = $model->insert($save_cols_n_values);
1854
+					if ($results) {
1855
+						//if successful, set the primary key
1856
+						//but don't use the normal SET method, because it will check if
1857
+						//an item with the same ID exists in the mapper & db, then
1858
+						//will find it in the db (because we just added it) and THAT object
1859
+						//will get added to the mapper before we can add this one!
1860
+						//but if we just avoid using the SET method, all that headache can be avoided
1861
+						$pk_field_name                   = $model->primary_key_name();
1862
+						$this->_fields[ $pk_field_name ] = $results;
1863
+						$this->_clear_cached_property($pk_field_name);
1864
+						$model->add_to_entity_map($this);
1865
+						$this->_update_cached_related_model_objs_fks();
1866
+					}
1867
+				}
1868
+			} else {//PK is NOT auto-increment
1869
+				//so check if one like it already exists in the db
1870
+				if ($model->exists_by_ID($this->ID())) {
1871
+					if (WP_DEBUG && ! $this->in_entity_map()) {
1872
+						throw new EE_Error(
1873
+							sprintf(
1874
+								esc_html__(
1875
+									'Using a model object %1$s that is NOT in the entity map, can lead to unexpected errors. You should either: %4$s 1. Put it in the entity mapper by calling %2$s %4$s 2. Discard this model object and use what is in the entity mapper %4$s 3. Fetch from the database using %3$s',
1876
+									'event_espresso'
1877
+								),
1878
+								get_class($this),
1879
+								get_class($model) . '::instance()->add_to_entity_map()',
1880
+								get_class($model) . '::instance()->get_one_by_ID()',
1881
+								'<br />'
1882
+							)
1883
+						);
1884
+					}
1885
+					$results = $model->update_by_ID($save_cols_n_values, $this->ID());
1886
+				} else {
1887
+					$results = $model->insert($save_cols_n_values);
1888
+					$this->_update_cached_related_model_objs_fks();
1889
+				}
1890
+			}
1891
+		} else {//there is NO primary key
1892
+			$already_in_db = false;
1893
+			foreach ($model->unique_indexes() as $index) {
1894
+				$uniqueness_where_params = array_intersect_key($save_cols_n_values, $index->fields());
1895
+				if ($model->exists(array($uniqueness_where_params))) {
1896
+					$already_in_db = true;
1897
+				}
1898
+			}
1899
+			if ($already_in_db) {
1900
+				$combined_pk_fields_n_values = array_intersect_key($save_cols_n_values,
1901
+					$model->get_combined_primary_key_fields());
1902
+				$results                     = $model->update(
1903
+					$save_cols_n_values,
1904
+					$combined_pk_fields_n_values
1905
+				);
1906
+			} else {
1907
+				$results = $model->insert($save_cols_n_values);
1908
+			}
1909
+		}
1910
+		//restore the old assumption about values being prepared by the model object
1911
+		$model->assume_values_already_prepared_by_model_object(
1912
+				$old_assumption_concerning_value_preparation
1913
+			);
1914
+		/**
1915
+		 * After saving the model object this action is called
1916
+		 *
1917
+		 * @param EE_Base_Class $model_object which was just saved
1918
+		 * @param boolean|int   $results      if it were updated, TRUE or FALSE; if it were newly inserted
1919
+		 *                                    the new ID (or 0 if an error occurred and it wasn't updated)
1920
+		 */
1921
+		do_action('AHEE__EE_Base_Class__save__end', $this, $results);
1922
+		$this->_has_changes = false;
1923
+		return $results;
1924
+	}
1925
+
1926
+
1927
+	/**
1928
+	 * Updates the foreign key on related models objects pointing to this to have this model object's ID
1929
+	 * as their foreign key.  If the cached related model objects already exist in the db, saves them (so that the DB
1930
+	 * is consistent) Especially useful in case we JUST added this model object ot the database and we want to let its
1931
+	 * cached relations with foreign keys to it know about that change. Eg: we've created a transaction but haven't
1932
+	 * saved it to the db. We also create a registration and don't save it to the DB, but we DO cache it on the
1933
+	 * transaction. Now, when we save the transaction, the registration's TXN_ID will be automatically updated, whether
1934
+	 * or not they exist in the DB (if they do, their DB records will be automatically updated)
1935
+	 *
1936
+	 * @return void
1937
+	 * @throws ReflectionException
1938
+	 * @throws InvalidArgumentException
1939
+	 * @throws InvalidInterfaceException
1940
+	 * @throws InvalidDataTypeException
1941
+	 * @throws EE_Error
1942
+	 */
1943
+	protected function _update_cached_related_model_objs_fks()
1944
+	{
1945
+		$model = $this->get_model();
1946
+		foreach ($model->relation_settings() as $relation_name => $relation_obj) {
1947
+			if ($relation_obj instanceof EE_Has_Many_Relation) {
1948
+				foreach ($this->get_all_from_cache($relation_name) as $related_model_obj_in_cache) {
1949
+					$fk_to_this = $related_model_obj_in_cache->get_model()->get_foreign_key_to(
1950
+						$model->get_this_model_name()
1951
+					);
1952
+					$related_model_obj_in_cache->set($fk_to_this->get_name(), $this->ID());
1953
+					if ($related_model_obj_in_cache->ID()) {
1954
+						$related_model_obj_in_cache->save();
1955
+					}
1956
+				}
1957
+			}
1958
+		}
1959
+	}
1960
+
1961
+
1962
+	/**
1963
+	 * Saves this model object and its NEW cached relations to the database.
1964
+	 * (Meaning, for now, IT DOES NOT WORK if the cached items already exist in the DB.
1965
+	 * In order for that to work, we would need to mark model objects as dirty/clean...
1966
+	 * because otherwise, there's a potential for infinite looping of saving
1967
+	 * Saves the cached related model objects, and ensures the relation between them
1968
+	 * and this object and properly setup
1969
+	 *
1970
+	 * @return int ID of new model object on save; 0 on failure+
1971
+	 * @throws ReflectionException
1972
+	 * @throws InvalidArgumentException
1973
+	 * @throws InvalidInterfaceException
1974
+	 * @throws InvalidDataTypeException
1975
+	 * @throws EE_Error
1976
+	 */
1977
+	public function save_new_cached_related_model_objs()
1978
+	{
1979
+		//make sure this has been saved
1980
+		if (! $this->ID()) {
1981
+			$id = $this->save();
1982
+		} else {
1983
+			$id = $this->ID();
1984
+		}
1985
+		//now save all the NEW cached model objects  (ie they don't exist in the DB)
1986
+		foreach ($this->get_model()->relation_settings() as $relationName => $relationObj) {
1987
+			if ($this->_model_relations[ $relationName ]) {
1988
+				//is this a relation where we should expect just ONE related object (ie, EE_Belongs_To_relation)
1989
+				//or MANY related objects (ie, EE_HABTM_Relation or EE_Has_Many_Relation)?
1990
+				/* @var $related_model_obj EE_Base_Class */
1991
+				if ($relationObj instanceof EE_Belongs_To_Relation) {
1992
+					//add a relation to that relation type (which saves the appropriate thing in the process)
1993
+					//but ONLY if it DOES NOT exist in the DB
1994
+					$related_model_obj = $this->_model_relations[ $relationName ];
1995
+					//					if( ! $related_model_obj->ID()){
1996
+					$this->_add_relation_to($related_model_obj, $relationName);
1997
+					$related_model_obj->save_new_cached_related_model_objs();
1998
+					//					}
1999
+				} else {
2000
+					foreach ($this->_model_relations[ $relationName ] as $related_model_obj) {
2001
+						//add a relation to that relation type (which saves the appropriate thing in the process)
2002
+						//but ONLY if it DOES NOT exist in the DB
2003
+						//						if( ! $related_model_obj->ID()){
2004
+						$this->_add_relation_to($related_model_obj, $relationName);
2005
+						$related_model_obj->save_new_cached_related_model_objs();
2006
+						//						}
2007
+					}
2008
+				}
2009
+			}
2010
+		}
2011
+		return $id;
2012
+	}
2013
+
2014
+
2015
+	/**
2016
+	 * for getting a model while instantiated.
2017
+	 *
2018
+	 * @return EEM_Base | EEM_CPT_Base
2019
+	 * @throws ReflectionException
2020
+	 * @throws InvalidArgumentException
2021
+	 * @throws InvalidInterfaceException
2022
+	 * @throws InvalidDataTypeException
2023
+	 * @throws EE_Error
2024
+	 */
2025
+	public function get_model()
2026
+	{
2027
+		if (! $this->_model) {
2028
+			$modelName    = self::_get_model_classname(get_class($this));
2029
+			$this->_model = self::_get_model_instance_with_name($modelName, $this->_timezone);
2030
+		} else {
2031
+			$this->_model->set_timezone($this->_timezone);
2032
+		}
2033
+		return $this->_model;
2034
+	}
2035
+
2036
+
2037
+	/**
2038
+	 * @param $props_n_values
2039
+	 * @param $classname
2040
+	 * @return mixed bool|EE_Base_Class|EEM_CPT_Base
2041
+	 * @throws ReflectionException
2042
+	 * @throws InvalidArgumentException
2043
+	 * @throws InvalidInterfaceException
2044
+	 * @throws InvalidDataTypeException
2045
+	 * @throws EE_Error
2046
+	 */
2047
+	protected static function _get_object_from_entity_mapper($props_n_values, $classname)
2048
+	{
2049
+		//TODO: will not work for Term_Relationships because they have no PK!
2050
+		$primary_id_ref = self::_get_primary_key_name($classname);
2051
+		if (
2052
+			array_key_exists($primary_id_ref, $props_n_values)
2053
+			&& ! empty($props_n_values[ $primary_id_ref ])
2054
+		) {
2055
+			$id = $props_n_values[ $primary_id_ref ];
2056
+			return self::_get_model($classname)->get_from_entity_map($id);
2057
+		}
2058
+		return false;
2059
+	}
2060
+
2061
+
2062
+	/**
2063
+	 * This is called by child static "new_instance" method and we'll check to see if there is an existing db entry for
2064
+	 * the primary key (if present in incoming values). If there is a key in the incoming array that matches the
2065
+	 * primary key for the model AND it is not null, then we check the db. If there's a an object we return it.  If not
2066
+	 * we return false.
2067
+	 *
2068
+	 * @param  array  $props_n_values   incoming array of properties and their values
2069
+	 * @param  string $classname        the classname of the child class
2070
+	 * @param null    $timezone
2071
+	 * @param array   $date_formats     incoming date_formats in an array where the first value is the
2072
+	 *                                  date_format and the second value is the time format
2073
+	 * @return mixed (EE_Base_Class|bool)
2074
+	 * @throws InvalidArgumentException
2075
+	 * @throws InvalidInterfaceException
2076
+	 * @throws InvalidDataTypeException
2077
+	 * @throws EE_Error
2078
+	 * @throws ReflectionException
2079
+	 * @throws ReflectionException
2080
+	 * @throws ReflectionException
2081
+	 */
2082
+	protected static function _check_for_object($props_n_values, $classname, $timezone = null, $date_formats = array())
2083
+	{
2084
+		$existing = null;
2085
+		$model    = self::_get_model($classname, $timezone);
2086
+		if ($model->has_primary_key_field()) {
2087
+			$primary_id_ref = self::_get_primary_key_name($classname);
2088
+			if (array_key_exists($primary_id_ref, $props_n_values)
2089
+				&& ! empty($props_n_values[ $primary_id_ref ])
2090
+			) {
2091
+				$existing = $model->get_one_by_ID(
2092
+					$props_n_values[ $primary_id_ref ]
2093
+				);
2094
+			}
2095
+		} elseif ($model->has_all_combined_primary_key_fields($props_n_values)) {
2096
+			//no primary key on this model, but there's still a matching item in the DB
2097
+			$existing = self::_get_model($classname, $timezone)->get_one_by_ID(
2098
+				self::_get_model($classname, $timezone)
2099
+					->get_index_primary_key_string($props_n_values)
2100
+			);
2101
+		}
2102
+		if ($existing) {
2103
+			//set date formats if present before setting values
2104
+			if (! empty($date_formats) && is_array($date_formats)) {
2105
+				$existing->set_date_format($date_formats[0]);
2106
+				$existing->set_time_format($date_formats[1]);
2107
+			} else {
2108
+				//set default formats for date and time
2109
+				$existing->set_date_format(get_option('date_format'));
2110
+				$existing->set_time_format(get_option('time_format'));
2111
+			}
2112
+			foreach ($props_n_values as $property => $field_value) {
2113
+				$existing->set($property, $field_value);
2114
+			}
2115
+			return $existing;
2116
+		}
2117
+		return false;
2118
+	}
2119
+
2120
+
2121
+	/**
2122
+	 * Gets the EEM_*_Model for this class
2123
+	 *
2124
+	 * @access public now, as this is more convenient
2125
+	 * @param      $classname
2126
+	 * @param null $timezone
2127
+	 * @throws ReflectionException
2128
+	 * @throws InvalidArgumentException
2129
+	 * @throws InvalidInterfaceException
2130
+	 * @throws InvalidDataTypeException
2131
+	 * @throws EE_Error
2132
+	 * @return EEM_Base
2133
+	 */
2134
+	protected static function _get_model($classname, $timezone = null)
2135
+	{
2136
+		//find model for this class
2137
+		if (! $classname) {
2138
+			throw new EE_Error(
2139
+				sprintf(
2140
+					esc_html__(
2141
+						'What were you thinking calling _get_model(%s)?? You need to specify the class name',
2142
+						'event_espresso'
2143
+					),
2144
+					$classname
2145
+				)
2146
+			);
2147
+		}
2148
+		$modelName = self::_get_model_classname($classname);
2149
+		return self::_get_model_instance_with_name($modelName, $timezone);
2150
+	}
2151
+
2152
+
2153
+	/**
2154
+	 * Gets the model instance (eg instance of EEM_Attendee) given its classname (eg EE_Attendee)
2155
+	 *
2156
+	 * @param string $model_classname
2157
+	 * @param null   $timezone
2158
+	 * @return EEM_Base
2159
+	 * @throws ReflectionException
2160
+	 * @throws InvalidArgumentException
2161
+	 * @throws InvalidInterfaceException
2162
+	 * @throws InvalidDataTypeException
2163
+	 * @throws EE_Error
2164
+	 */
2165
+	protected static function _get_model_instance_with_name($model_classname, $timezone = null)
2166
+	{
2167
+		$model_classname = str_replace('EEM_', '', $model_classname);
2168
+		$model           = EE_Registry::instance()->load_model($model_classname);
2169
+		$model->set_timezone($timezone);
2170
+		return $model;
2171
+	}
2172
+
2173
+
2174
+	/**
2175
+	 * If a model name is provided (eg Registration), gets the model classname for that model.
2176
+	 * Also works if a model class's classname is provided (eg EE_Registration).
2177
+	 *
2178
+	 * @param null $model_name
2179
+	 * @return string like EEM_Attendee
2180
+	 */
2181
+	private static function _get_model_classname($model_name = null)
2182
+	{
2183
+		if (strpos($model_name, 'EE_') === 0) {
2184
+			$model_classname = str_replace('EE_', 'EEM_', $model_name);
2185
+		} else {
2186
+			$model_classname = 'EEM_' . $model_name;
2187
+		}
2188
+		return $model_classname;
2189
+	}
2190
+
2191
+
2192
+	/**
2193
+	 * returns the name of the primary key attribute
2194
+	 *
2195
+	 * @param null $classname
2196
+	 * @throws ReflectionException
2197
+	 * @throws InvalidArgumentException
2198
+	 * @throws InvalidInterfaceException
2199
+	 * @throws InvalidDataTypeException
2200
+	 * @throws EE_Error
2201
+	 * @return string
2202
+	 */
2203
+	protected static function _get_primary_key_name($classname = null)
2204
+	{
2205
+		if (! $classname) {
2206
+			throw new EE_Error(
2207
+				sprintf(
2208
+					esc_html__('What were you thinking calling _get_primary_key_name(%s)', 'event_espresso'),
2209
+					$classname
2210
+				)
2211
+			);
2212
+		}
2213
+		return self::_get_model($classname)->get_primary_key_field()->get_name();
2214
+	}
2215
+
2216
+
2217
+	/**
2218
+	 * Gets the value of the primary key.
2219
+	 * If the object hasn't yet been saved, it should be whatever the model field's default was
2220
+	 * (eg, if this were the EE_Event class, look at the primary key field on EEM_Event and see what its default value
2221
+	 * is. Usually defaults for integer primary keys are 0; string primary keys are usually NULL).
2222
+	 *
2223
+	 * @return mixed, if the primary key is of type INT it'll be an int. Otherwise it could be a string
2224
+	 * @throws ReflectionException
2225
+	 * @throws InvalidArgumentException
2226
+	 * @throws InvalidInterfaceException
2227
+	 * @throws InvalidDataTypeException
2228
+	 * @throws EE_Error
2229
+	 */
2230
+	public function ID()
2231
+	{
2232
+		$model = $this->get_model();
2233
+		//now that we know the name of the variable, use a variable variable to get its value and return its
2234
+		if ($model->has_primary_key_field()) {
2235
+			return $this->_fields[ $model->primary_key_name() ];
2236
+		}
2237
+		return $model->get_index_primary_key_string($this->_fields);
2238
+	}
2239
+
2240
+
2241
+	/**
2242
+	 * Adds a relationship to the specified EE_Base_Class object, given the relationship's name. Eg, if the current
2243
+	 * model is related to a group of events, the $relationName should be 'Event', and should be a key in the EE
2244
+	 * Model's $_model_relations array. If this model object doesn't exist in the DB, just caches the related thing
2245
+	 *
2246
+	 * @param mixed  $otherObjectModelObjectOrID       EE_Base_Class or the ID of the other object
2247
+	 * @param string $relationName                     eg 'Events','Question',etc.
2248
+	 *                                                 an attendee to a group, you also want to specify which role they
2249
+	 *                                                 will have in that group. So you would use this parameter to
2250
+	 *                                                 specify array('role-column-name'=>'role-id')
2251
+	 * @param array  $extra_join_model_fields_n_values You can optionally include an array of key=>value pairs that
2252
+	 *                                                 allow you to further constrict the relation to being added.
2253
+	 *                                                 However, keep in mind that the columns (keys) given must match a
2254
+	 *                                                 column on the JOIN table and currently only the HABTM models
2255
+	 *                                                 accept these additional conditions.  Also remember that if an
2256
+	 *                                                 exact match isn't found for these extra cols/val pairs, then a
2257
+	 *                                                 NEW row is created in the join table.
2258
+	 * @param null   $cache_id
2259
+	 * @throws ReflectionException
2260
+	 * @throws InvalidArgumentException
2261
+	 * @throws InvalidInterfaceException
2262
+	 * @throws InvalidDataTypeException
2263
+	 * @throws EE_Error
2264
+	 * @return EE_Base_Class the object the relation was added to
2265
+	 */
2266
+	public function _add_relation_to(
2267
+		$otherObjectModelObjectOrID,
2268
+		$relationName,
2269
+		$extra_join_model_fields_n_values = array(),
2270
+		$cache_id = null
2271
+	) {
2272
+		$model = $this->get_model();
2273
+		//if this thing exists in the DB, save the relation to the DB
2274
+		if ($this->ID()) {
2275
+			$otherObject = $model->add_relationship_to(
2276
+				$this,
2277
+				$otherObjectModelObjectOrID,
2278
+				$relationName,
2279
+				$extra_join_model_fields_n_values
2280
+			);
2281
+			//clear cache so future get_many_related and get_first_related() return new results.
2282
+			$this->clear_cache($relationName, $otherObject, true);
2283
+			if ($otherObject instanceof EE_Base_Class) {
2284
+				$otherObject->clear_cache($model->get_this_model_name(), $this);
2285
+			}
2286
+		} else {
2287
+			//this thing doesn't exist in the DB,  so just cache it
2288
+			if (! $otherObjectModelObjectOrID instanceof EE_Base_Class) {
2289
+				throw new EE_Error(
2290
+					sprintf(
2291
+						esc_html__(
2292
+							'Before a model object is saved to the database, calls to _add_relation_to must be passed an actual object, not just an ID. You provided %s as the model object to a %s',
2293
+							'event_espresso'
2294
+						),
2295
+						$otherObjectModelObjectOrID,
2296
+						get_class($this)
2297
+					)
2298
+				);
2299
+			}
2300
+			$otherObject = $otherObjectModelObjectOrID;
2301
+			$this->cache($relationName, $otherObjectModelObjectOrID, $cache_id);
2302
+		}
2303
+		if ($otherObject instanceof EE_Base_Class) {
2304
+			//fix the reciprocal relation too
2305
+			if ($otherObject->ID()) {
2306
+				//its saved so assumed relations exist in the DB, so we can just
2307
+				//clear the cache so future queries use the updated info in the DB
2308
+				$otherObject->clear_cache(
2309
+					$model->get_this_model_name(),
2310
+					null,
2311
+					true
2312
+				);
2313
+			} else {
2314
+				//it's not saved, so it caches relations like this
2315
+				$otherObject->cache($model->get_this_model_name(), $this);
2316
+			}
2317
+		}
2318
+		return $otherObject;
2319
+	}
2320
+
2321
+
2322
+	/**
2323
+	 * Removes a relationship to the specified EE_Base_Class object, given the relationships' name. Eg, if the current
2324
+	 * model is related to a group of events, the $relationName should be 'Events', and should be a key in the EE
2325
+	 * Model's $_model_relations array. If this model object doesn't exist in the DB, just removes the related thing
2326
+	 * from the cache
2327
+	 *
2328
+	 * @param mixed  $otherObjectModelObjectOrID
2329
+	 *                EE_Base_Class or the ID of the other object, OR an array key into the cache if this isn't saved
2330
+	 *                to the DB yet
2331
+	 * @param string $relationName
2332
+	 * @param array  $where_query
2333
+	 *                You can optionally include an array of key=>value pairs that allow you to further constrict the
2334
+	 *                relation to being added. However, keep in mind that the columns (keys) given must match a column
2335
+	 *                on the JOIN table and currently only the HABTM models accept these additional conditions. Also
2336
+	 *                remember that if an exact match isn't found for these extra cols/val pairs, then a NEW row is
2337
+	 *                created in the join table.
2338
+	 * @return EE_Base_Class the relation was removed from
2339
+	 * @throws ReflectionException
2340
+	 * @throws InvalidArgumentException
2341
+	 * @throws InvalidInterfaceException
2342
+	 * @throws InvalidDataTypeException
2343
+	 * @throws EE_Error
2344
+	 */
2345
+	public function _remove_relation_to($otherObjectModelObjectOrID, $relationName, $where_query = array())
2346
+	{
2347
+		if ($this->ID()) {
2348
+			//if this exists in the DB, save the relation change to the DB too
2349
+			$otherObject = $this->get_model()->remove_relationship_to(
2350
+				$this,
2351
+				$otherObjectModelObjectOrID,
2352
+				$relationName,
2353
+				$where_query
2354
+			);
2355
+			$this->clear_cache(
2356
+				$relationName,
2357
+				$otherObject
2358
+			);
2359
+		} else {
2360
+			//this doesn't exist in the DB, just remove it from the cache
2361
+			$otherObject = $this->clear_cache(
2362
+				$relationName,
2363
+				$otherObjectModelObjectOrID
2364
+			);
2365
+		}
2366
+		if ($otherObject instanceof EE_Base_Class) {
2367
+			$otherObject->clear_cache(
2368
+				$this->get_model()->get_this_model_name(),
2369
+				$this
2370
+			);
2371
+		}
2372
+		return $otherObject;
2373
+	}
2374
+
2375
+
2376
+	/**
2377
+	 * Removes ALL the related things for the $relationName.
2378
+	 *
2379
+	 * @param string $relationName
2380
+	 * @param array  $where_query_params like EEM_Base::get_all's $query_params[0] (where conditions)
2381
+	 * @return EE_Base_Class
2382
+	 * @throws ReflectionException
2383
+	 * @throws InvalidArgumentException
2384
+	 * @throws InvalidInterfaceException
2385
+	 * @throws InvalidDataTypeException
2386
+	 * @throws EE_Error
2387
+	 */
2388
+	public function _remove_relations($relationName, $where_query_params = array())
2389
+	{
2390
+		if ($this->ID()) {
2391
+			//if this exists in the DB, save the relation change to the DB too
2392
+			$otherObjects = $this->get_model()->remove_relations(
2393
+				$this,
2394
+				$relationName,
2395
+				$where_query_params
2396
+			);
2397
+			$this->clear_cache(
2398
+				$relationName,
2399
+				null,
2400
+				true
2401
+			);
2402
+		} else {
2403
+			//this doesn't exist in the DB, just remove it from the cache
2404
+			$otherObjects = $this->clear_cache(
2405
+				$relationName,
2406
+				null,
2407
+				true
2408
+			);
2409
+		}
2410
+		if (is_array($otherObjects)) {
2411
+			foreach ($otherObjects as $otherObject) {
2412
+				$otherObject->clear_cache(
2413
+					$this->get_model()->get_this_model_name(),
2414
+					$this
2415
+				);
2416
+			}
2417
+		}
2418
+		return $otherObjects;
2419
+	}
2420
+
2421
+
2422
+	/**
2423
+	 * Gets all the related model objects of the specified type. Eg, if the current class if
2424
+	 * EE_Event, you could call $this->get_many_related('Registration') to get an array of all the
2425
+	 * EE_Registration objects which related to this event. Note: by default, we remove the "default query params"
2426
+	 * because we want to get even deleted items etc.
2427
+	 *
2428
+	 * @param string $relationName key in the model's _model_relations array
2429
+	 * @param array  $query_params like EEM_Base::get_all
2430
+	 * @return EE_Base_Class[]     Results not necessarily indexed by IDs, because some results might not have primary
2431
+	 *                             keys or might not be saved yet. Consider using EEM_Base::get_IDs() on these
2432
+	 *                             results if you want IDs
2433
+	 * @throws ReflectionException
2434
+	 * @throws InvalidArgumentException
2435
+	 * @throws InvalidInterfaceException
2436
+	 * @throws InvalidDataTypeException
2437
+	 * @throws EE_Error
2438
+	 */
2439
+	public function get_many_related($relationName, $query_params = array())
2440
+	{
2441
+		if ($this->ID()) {
2442
+			//this exists in the DB, so get the related things from either the cache or the DB
2443
+			//if there are query parameters, forget about caching the related model objects.
2444
+			if ($query_params) {
2445
+				$related_model_objects = $this->get_model()->get_all_related(
2446
+					$this,
2447
+					$relationName,
2448
+					$query_params
2449
+				);
2450
+			} else {
2451
+				//did we already cache the result of this query?
2452
+				$cached_results = $this->get_all_from_cache($relationName);
2453
+				if (! $cached_results) {
2454
+					$related_model_objects = $this->get_model()->get_all_related(
2455
+						$this,
2456
+						$relationName,
2457
+						$query_params
2458
+					);
2459
+					//if no query parameters were passed, then we got all the related model objects
2460
+					//for that relation. We can cache them then.
2461
+					foreach ($related_model_objects as $related_model_object) {
2462
+						$this->cache($relationName, $related_model_object);
2463
+					}
2464
+				} else {
2465
+					$related_model_objects = $cached_results;
2466
+				}
2467
+			}
2468
+		} else {
2469
+			//this doesn't exist in the DB, so just get the related things from the cache
2470
+			$related_model_objects = $this->get_all_from_cache($relationName);
2471
+		}
2472
+		return $related_model_objects;
2473
+	}
2474
+
2475
+
2476
+	/**
2477
+	 * Instead of getting the related model objects, simply counts them. Ignores default_where_conditions by default,
2478
+	 * unless otherwise specified in the $query_params
2479
+	 *
2480
+	 * @param string $relation_name  model_name like 'Event', or 'Registration'
2481
+	 * @param array  $query_params   like EEM_Base::get_all's
2482
+	 * @param string $field_to_count name of field to count by. By default, uses primary key
2483
+	 * @param bool   $distinct       if we want to only count the distinct values for the column then you can trigger
2484
+	 *                               that by the setting $distinct to TRUE;
2485
+	 * @return int
2486
+	 * @throws ReflectionException
2487
+	 * @throws InvalidArgumentException
2488
+	 * @throws InvalidInterfaceException
2489
+	 * @throws InvalidDataTypeException
2490
+	 * @throws EE_Error
2491
+	 */
2492
+	public function count_related($relation_name, $query_params = array(), $field_to_count = null, $distinct = false)
2493
+	{
2494
+		return $this->get_model()->count_related(
2495
+			$this,
2496
+			$relation_name,
2497
+			$query_params,
2498
+			$field_to_count,
2499
+			$distinct
2500
+		);
2501
+	}
2502
+
2503
+
2504
+	/**
2505
+	 * Instead of getting the related model objects, simply sums up the values of the specified field.
2506
+	 * Note: ignores default_where_conditions by default, unless otherwise specified in the $query_params
2507
+	 *
2508
+	 * @param string $relation_name model_name like 'Event', or 'Registration'
2509
+	 * @param array  $query_params  like EEM_Base::get_all's
2510
+	 * @param string $field_to_sum  name of field to count by.
2511
+	 *                              By default, uses primary key
2512
+	 *                              (which doesn't make much sense, so you should probably change it)
2513
+	 * @return int
2514
+	 * @throws ReflectionException
2515
+	 * @throws InvalidArgumentException
2516
+	 * @throws InvalidInterfaceException
2517
+	 * @throws InvalidDataTypeException
2518
+	 * @throws EE_Error
2519
+	 */
2520
+	public function sum_related($relation_name, $query_params = array(), $field_to_sum = null)
2521
+	{
2522
+		return $this->get_model()->sum_related(
2523
+			$this,
2524
+			$relation_name,
2525
+			$query_params,
2526
+			$field_to_sum
2527
+		);
2528
+	}
2529
+
2530
+
2531
+	/**
2532
+	 * Gets the first (ie, one) related model object of the specified type.
2533
+	 *
2534
+	 * @param string $relationName key in the model's _model_relations array
2535
+	 * @param array  $query_params like EEM_Base::get_all
2536
+	 * @return EE_Base_Class (not an array, a single object)
2537
+	 * @throws ReflectionException
2538
+	 * @throws InvalidArgumentException
2539
+	 * @throws InvalidInterfaceException
2540
+	 * @throws InvalidDataTypeException
2541
+	 * @throws EE_Error
2542
+	 */
2543
+	public function get_first_related($relationName, $query_params = array())
2544
+	{
2545
+		$model = $this->get_model();
2546
+		if ($this->ID()) {//this exists in the DB, get from the cache OR the DB
2547
+			//if they've provided some query parameters, don't bother trying to cache the result
2548
+			//also make sure we're not caching the result of get_first_related
2549
+			//on a relation which should have an array of objects (because the cache might have an array of objects)
2550
+			if ($query_params
2551
+				|| ! $model->related_settings_for($relationName)
2552
+					 instanceof
2553
+					 EE_Belongs_To_Relation
2554
+			) {
2555
+				$related_model_object = $model->get_first_related(
2556
+					$this,
2557
+					$relationName,
2558
+					$query_params
2559
+				);
2560
+			} else {
2561
+				//first, check if we've already cached the result of this query
2562
+				$cached_result = $this->get_one_from_cache($relationName);
2563
+				if (! $cached_result) {
2564
+					$related_model_object = $model->get_first_related(
2565
+						$this,
2566
+						$relationName,
2567
+						$query_params
2568
+					);
2569
+					$this->cache($relationName, $related_model_object);
2570
+				} else {
2571
+					$related_model_object = $cached_result;
2572
+				}
2573
+			}
2574
+		} else {
2575
+			$related_model_object = null;
2576
+			// this doesn't exist in the Db,
2577
+			// but maybe the relation is of type belongs to, and so the related thing might
2578
+			if ($model->related_settings_for($relationName) instanceof EE_Belongs_To_Relation) {
2579
+				$related_model_object = $model->get_first_related(
2580
+					$this,
2581
+					$relationName,
2582
+					$query_params
2583
+				);
2584
+			}
2585
+			// this doesn't exist in the DB and apparently the thing it belongs to doesn't either,
2586
+			// just get what's cached on this object
2587
+			if (! $related_model_object) {
2588
+				$related_model_object = $this->get_one_from_cache($relationName);
2589
+			}
2590
+		}
2591
+		return $related_model_object;
2592
+	}
2593
+
2594
+
2595
+	/**
2596
+	 * Does a delete on all related objects of type $relationName and removes
2597
+	 * the current model object's relation to them. If they can't be deleted (because
2598
+	 * of blocking related model objects) does nothing. If the related model objects are
2599
+	 * soft-deletable, they will be soft-deleted regardless of related blocking model objects.
2600
+	 * If this model object doesn't exist yet in the DB, just removes its related things
2601
+	 *
2602
+	 * @param string $relationName
2603
+	 * @param array  $query_params like EEM_Base::get_all's
2604
+	 * @return int how many deleted
2605
+	 * @throws ReflectionException
2606
+	 * @throws InvalidArgumentException
2607
+	 * @throws InvalidInterfaceException
2608
+	 * @throws InvalidDataTypeException
2609
+	 * @throws EE_Error
2610
+	 */
2611
+	public function delete_related($relationName, $query_params = array())
2612
+	{
2613
+		if ($this->ID()) {
2614
+			$count = $this->get_model()->delete_related(
2615
+				$this,
2616
+				$relationName,
2617
+				$query_params
2618
+			);
2619
+		} else {
2620
+			$count = count($this->get_all_from_cache($relationName));
2621
+			$this->clear_cache($relationName, null, true);
2622
+		}
2623
+		return $count;
2624
+	}
2625
+
2626
+
2627
+	/**
2628
+	 * Does a hard delete (ie, removes the DB row) on all related objects of type $relationName and removes
2629
+	 * the current model object's relation to them. If they can't be deleted (because
2630
+	 * of blocking related model objects) just does a soft delete on it instead, if possible.
2631
+	 * If the related thing isn't a soft-deletable model object, this function is identical
2632
+	 * to delete_related(). If this model object doesn't exist in the DB, just remove its related things
2633
+	 *
2634
+	 * @param string $relationName
2635
+	 * @param array  $query_params like EEM_Base::get_all's
2636
+	 * @return int how many deleted (including those soft deleted)
2637
+	 * @throws ReflectionException
2638
+	 * @throws InvalidArgumentException
2639
+	 * @throws InvalidInterfaceException
2640
+	 * @throws InvalidDataTypeException
2641
+	 * @throws EE_Error
2642
+	 */
2643
+	public function delete_related_permanently($relationName, $query_params = array())
2644
+	{
2645
+		if ($this->ID()) {
2646
+			$count = $this->get_model()->delete_related_permanently(
2647
+				$this,
2648
+				$relationName,
2649
+				$query_params
2650
+			);
2651
+		} else {
2652
+			$count = count($this->get_all_from_cache($relationName));
2653
+		}
2654
+		$this->clear_cache($relationName, null, true);
2655
+		return $count;
2656
+	}
2657
+
2658
+
2659
+	/**
2660
+	 * is_set
2661
+	 * Just a simple utility function children can use for checking if property exists
2662
+	 *
2663
+	 * @access  public
2664
+	 * @param  string $field_name property to check
2665
+	 * @return bool                              TRUE if existing,FALSE if not.
2666
+	 */
2667
+	public function is_set($field_name)
2668
+	{
2669
+		return isset($this->_fields[ $field_name ]);
2670
+	}
2671
+
2672
+
2673
+	/**
2674
+	 * Just a simple utility function children can use for checking if property (or properties) exists and throwing an
2675
+	 * EE_Error exception if they don't
2676
+	 *
2677
+	 * @param  mixed (string|array) $properties properties to check
2678
+	 * @throws EE_Error
2679
+	 * @return bool                              TRUE if existing, throw EE_Error if not.
2680
+	 */
2681
+	protected function _property_exists($properties)
2682
+	{
2683
+		foreach ((array) $properties as $property_name) {
2684
+			//first make sure this property exists
2685
+			if (! $this->_fields[ $property_name ]) {
2686
+				throw new EE_Error(
2687
+					sprintf(
2688
+						esc_html__(
2689
+							'Trying to retrieve a non-existent property (%s).  Double check the spelling please',
2690
+							'event_espresso'
2691
+						),
2692
+						$property_name
2693
+					)
2694
+				);
2695
+			}
2696
+		}
2697
+		return true;
2698
+	}
2699
+
2700
+
2701
+	/**
2702
+	 * This simply returns an array of model fields for this object
2703
+	 *
2704
+	 * @return array
2705
+	 * @throws ReflectionException
2706
+	 * @throws InvalidArgumentException
2707
+	 * @throws InvalidInterfaceException
2708
+	 * @throws InvalidDataTypeException
2709
+	 * @throws EE_Error
2710
+	 */
2711
+	public function model_field_array()
2712
+	{
2713
+		$fields     = $this->get_model()->field_settings(false);
2714
+		$properties = array();
2715
+		//remove prepended underscore
2716
+		foreach ($fields as $field_name => $settings) {
2717
+			$properties[ $field_name ] = $this->get($field_name);
2718
+		}
2719
+		return $properties;
2720
+	}
2721
+
2722
+
2723
+	/**
2724
+	 * Very handy general function to allow for plugins to extend any child of EE_Base_Class.
2725
+	 * If a method is called on a child of EE_Base_Class that doesn't exist, this function is called
2726
+	 * (http://www.garfieldtech.com/blog/php-magic-call) and passed the method's name and arguments.
2727
+	 * Instead of requiring a plugin to extend the EE_Base_Class
2728
+	 * (which works fine is there's only 1 plugin, but when will that happen?)
2729
+	 * they can add a hook onto 'filters_hook_espresso__{className}__{methodName}'
2730
+	 * (eg, filters_hook_espresso__EE_Answer__my_great_function)
2731
+	 * and accepts 2 arguments: the object on which the function was called,
2732
+	 * and an array of the original arguments passed to the function.
2733
+	 * Whatever their callback function returns will be returned by this function.
2734
+	 * Example: in functions.php (or in a plugin):
2735
+	 *      add_filter('FHEE__EE_Answer__my_callback','my_callback',10,3);
2736
+	 *      function my_callback($previousReturnValue,EE_Base_Class $object,$argsArray){
2737
+	 *          $returnString= "you called my_callback! and passed args:".implode(",",$argsArray);
2738
+	 *          return $previousReturnValue.$returnString;
2739
+	 *      }
2740
+	 * require('EE_Answer.class.php');
2741
+	 * $answer= EE_Answer::new_instance(array('REG_ID' => 2,'QST_ID' => 3,'ANS_value' => The answer is 42'));
2742
+	 * echo $answer->my_callback('monkeys',100);
2743
+	 * //will output "you called my_callback! and passed args:monkeys,100"
2744
+	 *
2745
+	 * @param string $methodName name of method which was called on a child of EE_Base_Class, but which
2746
+	 * @param array  $args       array of original arguments passed to the function
2747
+	 * @throws EE_Error
2748
+	 * @return mixed whatever the plugin which calls add_filter decides
2749
+	 */
2750
+	public function __call($methodName, $args)
2751
+	{
2752
+		$className = get_class($this);
2753
+		$tagName   = "FHEE__{$className}__{$methodName}";
2754
+		if (! has_filter($tagName)) {
2755
+			throw new EE_Error(
2756
+				sprintf(
2757
+					esc_html__(
2758
+						"Method %s on class %s does not exist! You can create one with the following code in functions.php or in a plugin: add_filter('%s','my_callback',10,3);function my_callback(\$previousReturnValue,EE_Base_Class \$object, \$argsArray){/*function body*/return \$whatever;}",
2759
+						'event_espresso'
2760
+					),
2761
+					$methodName,
2762
+					$className,
2763
+					$tagName
2764
+				)
2765
+			);
2766
+		}
2767
+		return apply_filters($tagName, null, $this, $args);
2768
+	}
2769
+
2770
+
2771
+	/**
2772
+	 * Similar to insert_post_meta, adds a record in the Extra_Meta model's table with the given key and value.
2773
+	 * A $previous_value can be specified in case there are many meta rows with the same key
2774
+	 *
2775
+	 * @param string $meta_key
2776
+	 * @param mixed  $meta_value
2777
+	 * @param mixed  $previous_value
2778
+	 * @return bool|int # of records updated (or BOOLEAN if we actually ended up inserting the extra meta row)
2779
+	 *                  NOTE: if the values haven't changed, returns 0
2780
+	 * @throws InvalidArgumentException
2781
+	 * @throws InvalidInterfaceException
2782
+	 * @throws InvalidDataTypeException
2783
+	 * @throws EE_Error
2784
+	 * @throws ReflectionException
2785
+	 */
2786
+	public function update_extra_meta($meta_key, $meta_value, $previous_value = null)
2787
+	{
2788
+		$query_params = array(
2789
+			array(
2790
+				'EXM_key'  => $meta_key,
2791
+				'OBJ_ID'   => $this->ID(),
2792
+				'EXM_type' => $this->get_model()->get_this_model_name(),
2793
+			),
2794
+		);
2795
+		if ($previous_value !== null) {
2796
+			$query_params[0]['EXM_value'] = $meta_value;
2797
+		}
2798
+		$existing_rows_like_that = EEM_Extra_Meta::instance()->get_all($query_params);
2799
+		if (! $existing_rows_like_that) {
2800
+			return $this->add_extra_meta($meta_key, $meta_value);
2801
+		}
2802
+		foreach ($existing_rows_like_that as $existing_row) {
2803
+			$existing_row->save(array('EXM_value' => $meta_value));
2804
+		}
2805
+		return count($existing_rows_like_that);
2806
+	}
2807
+
2808
+
2809
+	/**
2810
+	 * Adds a new extra meta record. If $unique is set to TRUE, we'll first double-check
2811
+	 * no other extra meta for this model object have the same key. Returns TRUE if the
2812
+	 * extra meta row was entered, false if not
2813
+	 *
2814
+	 * @param string  $meta_key
2815
+	 * @param mixed   $meta_value
2816
+	 * @param boolean $unique
2817
+	 * @return boolean
2818
+	 * @throws InvalidArgumentException
2819
+	 * @throws InvalidInterfaceException
2820
+	 * @throws InvalidDataTypeException
2821
+	 * @throws EE_Error
2822
+	 * @throws ReflectionException
2823
+	 * @throws ReflectionException
2824
+	 */
2825
+	public function add_extra_meta($meta_key, $meta_value, $unique = false)
2826
+	{
2827
+		if ($unique) {
2828
+			$existing_extra_meta = EEM_Extra_Meta::instance()->get_one(
2829
+				array(
2830
+					array(
2831
+						'EXM_key'  => $meta_key,
2832
+						'OBJ_ID'   => $this->ID(),
2833
+						'EXM_type' => $this->get_model()->get_this_model_name(),
2834
+					),
2835
+				)
2836
+			);
2837
+			if ($existing_extra_meta) {
2838
+				return false;
2839
+			}
2840
+		}
2841
+		$new_extra_meta = EE_Extra_Meta::new_instance(
2842
+			array(
2843
+				'EXM_key'   => $meta_key,
2844
+				'EXM_value' => $meta_value,
2845
+				'OBJ_ID'    => $this->ID(),
2846
+				'EXM_type'  => $this->get_model()->get_this_model_name(),
2847
+			)
2848
+		);
2849
+		$new_extra_meta->save();
2850
+		return true;
2851
+	}
2852
+
2853
+
2854
+	/**
2855
+	 * Deletes all the extra meta rows for this record as specified by key. If $meta_value
2856
+	 * is specified, only deletes extra meta records with that value.
2857
+	 *
2858
+	 * @param string $meta_key
2859
+	 * @param mixed  $meta_value
2860
+	 * @return int number of extra meta rows deleted
2861
+	 * @throws InvalidArgumentException
2862
+	 * @throws InvalidInterfaceException
2863
+	 * @throws InvalidDataTypeException
2864
+	 * @throws EE_Error
2865
+	 * @throws ReflectionException
2866
+	 */
2867
+	public function delete_extra_meta($meta_key, $meta_value = null)
2868
+	{
2869
+		$query_params = array(
2870
+			array(
2871
+				'EXM_key'  => $meta_key,
2872
+				'OBJ_ID'   => $this->ID(),
2873
+				'EXM_type' => $this->get_model()->get_this_model_name(),
2874
+			),
2875
+		);
2876
+		if ($meta_value !== null) {
2877
+			$query_params[0]['EXM_value'] = $meta_value;
2878
+		}
2879
+		return EEM_Extra_Meta::instance()->delete($query_params);
2880
+	}
2881
+
2882
+
2883
+	/**
2884
+	 * Gets the extra meta with the given meta key. If you specify "single" we just return 1, otherwise
2885
+	 * an array of everything found. Requires that this model actually have a relation of type EE_Has_Many_Any_Relation.
2886
+	 * You can specify $default is case you haven't found the extra meta
2887
+	 *
2888
+	 * @param string  $meta_key
2889
+	 * @param boolean $single
2890
+	 * @param mixed   $default if we don't find anything, what should we return?
2891
+	 * @return mixed single value if $single; array if ! $single
2892
+	 * @throws ReflectionException
2893
+	 * @throws InvalidArgumentException
2894
+	 * @throws InvalidInterfaceException
2895
+	 * @throws InvalidDataTypeException
2896
+	 * @throws EE_Error
2897
+	 */
2898
+	public function get_extra_meta($meta_key, $single = false, $default = null)
2899
+	{
2900
+		if ($single) {
2901
+			$result = $this->get_first_related(
2902
+				'Extra_Meta',
2903
+				array(array('EXM_key' => $meta_key))
2904
+			);
2905
+			if ($result instanceof EE_Extra_Meta) {
2906
+				return $result->value();
2907
+			}
2908
+		} else {
2909
+			$results = $this->get_many_related(
2910
+				'Extra_Meta',
2911
+				array(array('EXM_key' => $meta_key))
2912
+			);
2913
+			if ($results) {
2914
+				$values = array();
2915
+				foreach ($results as $result) {
2916
+					if ($result instanceof EE_Extra_Meta) {
2917
+						$values[ $result->ID() ] = $result->value();
2918
+					}
2919
+				}
2920
+				return $values;
2921
+			}
2922
+		}
2923
+		//if nothing discovered yet return default.
2924
+		return apply_filters(
2925
+			'FHEE__EE_Base_Class__get_extra_meta__default_value',
2926
+			$default,
2927
+			$meta_key,
2928
+			$single,
2929
+			$this
2930
+		);
2931
+	}
2932
+
2933
+
2934
+	/**
2935
+	 * Returns a simple array of all the extra meta associated with this model object.
2936
+	 * If $one_of_each_key is true (Default), it will be an array of simple key-value pairs, keys being the
2937
+	 * extra meta's key, and teh value being its value. However, if there are duplicate extra meta rows with
2938
+	 * the same key, only one will be used. (eg array('foo'=>'bar','monkey'=>123))
2939
+	 * If $one_of_each_key is false, it will return an array with the top-level keys being
2940
+	 * the extra meta keys, but their values are also arrays, which have the extra-meta's ID as their sub-key, and
2941
+	 * finally the extra meta's value as each sub-value. (eg
2942
+	 * array('foo'=>array(1=>'bar',2=>'bill'),'monkey'=>array(3=>123)))
2943
+	 *
2944
+	 * @param boolean $one_of_each_key
2945
+	 * @return array
2946
+	 * @throws ReflectionException
2947
+	 * @throws InvalidArgumentException
2948
+	 * @throws InvalidInterfaceException
2949
+	 * @throws InvalidDataTypeException
2950
+	 * @throws EE_Error
2951
+	 */
2952
+	public function all_extra_meta_array($one_of_each_key = true)
2953
+	{
2954
+		$return_array = array();
2955
+		if ($one_of_each_key) {
2956
+			$extra_meta_objs = $this->get_many_related(
2957
+				'Extra_Meta',
2958
+				array('group_by' => 'EXM_key')
2959
+			);
2960
+			foreach ($extra_meta_objs as $extra_meta_obj) {
2961
+				if ($extra_meta_obj instanceof EE_Extra_Meta) {
2962
+					$return_array[ $extra_meta_obj->key() ] = $extra_meta_obj->value();
2963
+				}
2964
+			}
2965
+		} else {
2966
+			$extra_meta_objs = $this->get_many_related('Extra_Meta');
2967
+			foreach ($extra_meta_objs as $extra_meta_obj) {
2968
+				if ($extra_meta_obj instanceof EE_Extra_Meta) {
2969
+					if (! isset($return_array[ $extra_meta_obj->key() ])) {
2970
+						$return_array[ $extra_meta_obj->key() ] = array();
2971
+					}
2972
+					$return_array[ $extra_meta_obj->key() ][ $extra_meta_obj->ID() ] = $extra_meta_obj->value();
2973
+				}
2974
+			}
2975
+		}
2976
+		return $return_array;
2977
+	}
2978
+
2979
+
2980
+	/**
2981
+	 * Gets a pretty nice displayable nice for this model object. Often overridden
2982
+	 *
2983
+	 * @return string
2984
+	 * @throws ReflectionException
2985
+	 * @throws InvalidArgumentException
2986
+	 * @throws InvalidInterfaceException
2987
+	 * @throws InvalidDataTypeException
2988
+	 * @throws EE_Error
2989
+	 */
2990
+	public function name()
2991
+	{
2992
+		//find a field that's not a text field
2993
+		$field_we_can_use = $this->get_model()->get_a_field_of_type('EE_Text_Field_Base');
2994
+		if ($field_we_can_use) {
2995
+			return $this->get($field_we_can_use->get_name());
2996
+		}
2997
+		$first_few_properties = $this->model_field_array();
2998
+		$first_few_properties = array_slice($first_few_properties, 0, 3);
2999
+		$name_parts           = array();
3000
+		foreach ($first_few_properties as $name => $value) {
3001
+			$name_parts[] = "$name:$value";
3002
+		}
3003
+		return implode(',', $name_parts);
3004
+	}
3005
+
3006
+
3007
+	/**
3008
+	 * in_entity_map
3009
+	 * Checks if this model object has been proven to already be in the entity map
3010
+	 *
3011
+	 * @return boolean
3012
+	 * @throws ReflectionException
3013
+	 * @throws InvalidArgumentException
3014
+	 * @throws InvalidInterfaceException
3015
+	 * @throws InvalidDataTypeException
3016
+	 * @throws EE_Error
3017
+	 */
3018
+	public function in_entity_map()
3019
+	{
3020
+		// well, if we looked, did we find it in the entity map?
3021
+		return $this->ID() && $this->get_model()->get_from_entity_map($this->ID()) === $this;
3022
+	}
3023
+
3024
+
3025
+	/**
3026
+	 * refresh_from_db
3027
+	 * Makes sure the fields and values on this model object are in-sync with what's in the database.
3028
+	 *
3029
+	 * @throws ReflectionException
3030
+	 * @throws InvalidArgumentException
3031
+	 * @throws InvalidInterfaceException
3032
+	 * @throws InvalidDataTypeException
3033
+	 * @throws EE_Error if this model object isn't in the entity mapper (because then you should
3034
+	 * just use what's in the entity mapper and refresh it) and WP_DEBUG is TRUE
3035
+	 */
3036
+	public function refresh_from_db()
3037
+	{
3038
+		if ($this->ID() && $this->in_entity_map()) {
3039
+			$this->get_model()->refresh_entity_map_from_db($this->ID());
3040
+		} else {
3041
+			//if it doesn't have ID, you shouldn't be asking to refresh it from teh database (because its not in the database)
3042
+			//if it has an ID but it's not in the map, and you're asking me to refresh it
3043
+			//that's kinda dangerous. You should just use what's in the entity map, or add this to the entity map if there's
3044
+			//absolutely nothing in it for this ID
3045
+			if (WP_DEBUG) {
3046
+				throw new EE_Error(
3047
+					sprintf(
3048
+						esc_html__('Trying to refresh a model object with ID "%1$s" that\'s not in the entity map? First off: you should put it in the entity map by calling %2$s. Second off, if you want what\'s in the database right now, you should just call %3$s yourself and discard this model object.',
3049
+							'event_espresso'),
3050
+						$this->ID(),
3051
+						get_class($this->get_model()) . '::instance()->add_to_entity_map()',
3052
+						get_class($this->get_model()) . '::instance()->refresh_entity_map()'
3053
+					)
3054
+				);
3055
+			}
3056
+		}
3057
+	}
3058
+
3059
+
3060
+	/**
3061
+	 * Because some other plugins, like Advanced Cron Manager, expect all objects to have this method
3062
+	 * (probably a bad assumption they have made, oh well)
3063
+	 *
3064
+	 * @return string
3065
+	 */
3066
+	public function __toString()
3067
+	{
3068
+		try {
3069
+			return sprintf('%s (%s)', $this->name(), $this->ID());
3070
+		} catch (Exception $e) {
3071
+			EE_Error::add_error($e->getMessage(), __FILE__, __FUNCTION__, __LINE__);
3072
+			return '';
3073
+		}
3074
+	}
3075
+
3076
+
3077
+	/**
3078
+	 * Clear related model objects if they're already in the DB, because otherwise when we
3079
+	 * UN-serialize this model object we'll need to be careful to add them to the entity map.
3080
+	 * This means if we have made changes to those related model objects, and want to unserialize
3081
+	 * the this model object on a subsequent request, changes to those related model objects will be lost.
3082
+	 * Instead, those related model objects should be directly serialized and stored.
3083
+	 * Eg, the following won't work:
3084
+	 * $reg = EEM_Registration::instance()->get_one_by_ID( 123 );
3085
+	 * $att = $reg->attendee();
3086
+	 * $att->set( 'ATT_fname', 'Dirk' );
3087
+	 * update_option( 'my_option', serialize( $reg ) );
3088
+	 * //END REQUEST
3089
+	 * //START NEXT REQUEST
3090
+	 * $reg = get_option( 'my_option' );
3091
+	 * $reg->attendee()->save();
3092
+	 * And would need to be replace with:
3093
+	 * $reg = EEM_Registration::instance()->get_one_by_ID( 123 );
3094
+	 * $att = $reg->attendee();
3095
+	 * $att->set( 'ATT_fname', 'Dirk' );
3096
+	 * update_option( 'my_option', serialize( $reg ) );
3097
+	 * //END REQUEST
3098
+	 * //START NEXT REQUEST
3099
+	 * $att = get_option( 'my_option' );
3100
+	 * $att->save();
3101
+	 *
3102
+	 * @return array
3103
+	 * @throws ReflectionException
3104
+	 * @throws InvalidArgumentException
3105
+	 * @throws InvalidInterfaceException
3106
+	 * @throws InvalidDataTypeException
3107
+	 * @throws EE_Error
3108
+	 */
3109
+	public function __sleep()
3110
+	{
3111
+		$model = $this->get_model();
3112
+		foreach ($model->relation_settings() as $relation_name => $relation_obj) {
3113
+			if ($relation_obj instanceof EE_Belongs_To_Relation) {
3114
+				$classname = 'EE_' . $model->get_this_model_name();
3115
+				if (
3116
+					$this->get_one_from_cache($relation_name) instanceof $classname
3117
+					&& $this->get_one_from_cache($relation_name)->ID()
3118
+				) {
3119
+					$this->clear_cache(
3120
+						$relation_name,
3121
+						$this->get_one_from_cache($relation_name)->ID()
3122
+					);
3123
+				}
3124
+			}
3125
+		}
3126
+		$this->_props_n_values_provided_in_constructor = array();
3127
+		$properties_to_serialize                       = get_object_vars($this);
3128
+		//don't serialize the model. It's big and that risks recursion
3129
+		unset($properties_to_serialize['_model']);
3130
+		return array_keys($properties_to_serialize);
3131
+	}
3132
+
3133
+
3134
+	/**
3135
+	 * restore _props_n_values_provided_in_constructor
3136
+	 * PLZ NOTE: this will reset the array to whatever fields values were present prior to serialization,
3137
+	 * and therefore should NOT be used to determine if state change has occurred since initial construction.
3138
+	 * At best, you would only be able to detect if state change has occurred during THIS request.
3139
+	 */
3140
+	public function __wakeup()
3141
+	{
3142
+		$this->_props_n_values_provided_in_constructor = $this->_fields;
3143
+	}
3144
+
3145
+
3146
+	/**
3147
+	 * Usage of this magic method is to ensure any internally cached references to object instances that must remain
3148
+	 * distinct with the clone host instance are also cloned.
3149
+	 */
3150
+	public function __clone()
3151
+	{
3152
+		//handle DateTimes (this is handled in here because there's no one specific child class that uses datetimes).
3153
+		foreach ($this->_fields as $field => $value) {
3154
+			if ($value instanceof DateTime) {
3155
+				$this->_fields[$field] = clone $value;
3156
+			}
3157
+		}
3158
+	}
3159 3159
 }
3160 3160
 
3161 3161
 
Please login to merge, or discard this patch.
Spacing   +116 added lines, -116 removed lines patch added patch discarded remove patch
@@ -148,7 +148,7 @@  discard block
 block discarded – undo
148 148
         $fieldValues = is_array($fieldValues) ? $fieldValues : array($fieldValues);
149 149
         // verify client code has not passed any invalid field names
150 150
         foreach ($fieldValues as $field_name => $field_value) {
151
-            if (! isset($model_fields[ $field_name ])) {
151
+            if ( ! isset($model_fields[$field_name])) {
152 152
                 throw new EE_Error(
153 153
                     sprintf(
154 154
                         esc_html__(
@@ -163,7 +163,7 @@  discard block
 block discarded – undo
163 163
             }
164 164
         }
165 165
         $this->_timezone = EEH_DTT_Helper::get_valid_timezone_string($timezone);
166
-        if (! empty($date_formats) && is_array($date_formats)) {
166
+        if ( ! empty($date_formats) && is_array($date_formats)) {
167 167
             list($this->_dt_frmt, $this->_tm_frmt) = $date_formats;
168 168
         } else {
169 169
             //set default formats for date and time
@@ -176,7 +176,7 @@  discard block
 block discarded – undo
176 176
             foreach ($model_fields as $fieldName => $field) {
177 177
                 $this->set_from_db(
178 178
                     $fieldName,
179
-                    isset($fieldValues[ $fieldName ]) ? $fieldValues[ $fieldName ] : null
179
+                    isset($fieldValues[$fieldName]) ? $fieldValues[$fieldName] : null
180 180
                 );
181 181
             }
182 182
         } else {
@@ -185,22 +185,22 @@  discard block
 block discarded – undo
185 185
             foreach ($model_fields as $fieldName => $field) {
186 186
                 $this->set(
187 187
                     $fieldName,
188
-                    isset($fieldValues[ $fieldName ]) ? $fieldValues[ $fieldName ] : null, true
188
+                    isset($fieldValues[$fieldName]) ? $fieldValues[$fieldName] : null, true
189 189
                 );
190 190
             }
191 191
         }
192 192
         //remember what values were passed to this constructor
193 193
         $this->_props_n_values_provided_in_constructor = $fieldValues;
194 194
         //remember in entity mapper
195
-        if (! $bydb && $model->has_primary_key_field() && $this->ID()) {
195
+        if ( ! $bydb && $model->has_primary_key_field() && $this->ID()) {
196 196
             $model->add_to_entity_map($this);
197 197
         }
198 198
         //setup all the relations
199 199
         foreach ($model->relation_settings() as $relation_name => $relation_obj) {
200 200
             if ($relation_obj instanceof EE_Belongs_To_Relation) {
201
-                $this->_model_relations[ $relation_name ] = null;
201
+                $this->_model_relations[$relation_name] = null;
202 202
             } else {
203
-                $this->_model_relations[ $relation_name ] = array();
203
+                $this->_model_relations[$relation_name] = array();
204 204
             }
205 205
         }
206 206
         /**
@@ -251,10 +251,10 @@  discard block
 block discarded – undo
251 251
      */
252 252
     public function get_original($field_name)
253 253
     {
254
-        if (isset($this->_props_n_values_provided_in_constructor[ $field_name ])
254
+        if (isset($this->_props_n_values_provided_in_constructor[$field_name])
255 255
             && $field_settings = $this->get_model()->field_settings_for($field_name)
256 256
         ) {
257
-            return $field_settings->prepare_for_get($this->_props_n_values_provided_in_constructor[ $field_name ]);
257
+            return $field_settings->prepare_for_get($this->_props_n_values_provided_in_constructor[$field_name]);
258 258
         }
259 259
         return null;
260 260
     }
@@ -291,7 +291,7 @@  discard block
 block discarded – undo
291 291
         // then don't do anything
292 292
         if (
293 293
             ! $use_default
294
-            && $this->_fields[ $field_name ] === $field_value
294
+            && $this->_fields[$field_name] === $field_value
295 295
             && $this->ID()
296 296
         ) {
297 297
             return;
@@ -309,7 +309,7 @@  discard block
 block discarded – undo
309 309
             $holder_of_value = $field_obj->prepare_for_set($field_value);
310 310
             //should the value be null?
311 311
             if (($field_value === null || $holder_of_value === null || $holder_of_value === '') && $use_default) {
312
-                $this->_fields[ $field_name ] = $field_obj->get_default_value();
312
+                $this->_fields[$field_name] = $field_obj->get_default_value();
313 313
                 /**
314 314
                  * To save having to refactor all the models, if a default value is used for a
315 315
                  * EE_Datetime_Field, and that value is not null nor is it a DateTime
@@ -320,15 +320,15 @@  discard block
 block discarded – undo
320 320
                  */
321 321
                 if (
322 322
                     $field_obj instanceof EE_Datetime_Field
323
-                    && $this->_fields[ $field_name ] !== null
324
-                    && ! $this->_fields[ $field_name ] instanceof DateTime
323
+                    && $this->_fields[$field_name] !== null
324
+                    && ! $this->_fields[$field_name] instanceof DateTime
325 325
                 ) {
326
-                    empty($this->_fields[ $field_name ])
326
+                    empty($this->_fields[$field_name])
327 327
                         ? $this->set($field_name, time())
328
-                        : $this->set($field_name, $this->_fields[ $field_name ]);
328
+                        : $this->set($field_name, $this->_fields[$field_name]);
329 329
                 }
330 330
             } else {
331
-                $this->_fields[ $field_name ] = $holder_of_value;
331
+                $this->_fields[$field_name] = $holder_of_value;
332 332
             }
333 333
             //if we're not in the constructor...
334 334
             //now check if what we set was a primary key
@@ -345,7 +345,7 @@  discard block
 block discarded – undo
345 345
                 $fields_on_model = self::_get_model(get_class($this))->field_settings();
346 346
                 $obj_in_db       = self::_get_model(get_class($this))->get_one_by_ID($field_value);
347 347
                 foreach ($fields_on_model as $field_obj) {
348
-                    if (! array_key_exists($field_obj->get_name(), $this->_props_n_values_provided_in_constructor)
348
+                    if ( ! array_key_exists($field_obj->get_name(), $this->_props_n_values_provided_in_constructor)
349 349
                         && $field_obj->get_name() !== $field_name
350 350
                     ) {
351 351
                         $this->set($field_obj->get_name(), $obj_in_db->get($field_obj->get_name()));
@@ -390,8 +390,8 @@  discard block
 block discarded – undo
390 390
      */
391 391
     public function getCustomSelect($alias)
392 392
     {
393
-        return isset($this->custom_selection_results[ $alias ])
394
-            ? $this->custom_selection_results[ $alias ]
393
+        return isset($this->custom_selection_results[$alias])
394
+            ? $this->custom_selection_results[$alias]
395 395
             : null;
396 396
     }
397 397
 
@@ -478,8 +478,8 @@  discard block
 block discarded – undo
478 478
         foreach ($model_fields as $field_name => $field_obj) {
479 479
             if ($field_obj instanceof EE_Datetime_Field) {
480 480
                 $field_obj->set_timezone($this->_timezone);
481
-                if (isset($this->_fields[ $field_name ]) && $this->_fields[ $field_name ] instanceof DateTime) {
482
-                    $this->_fields[ $field_name ]->setTimezone(new DateTimeZone($this->_timezone));
481
+                if (isset($this->_fields[$field_name]) && $this->_fields[$field_name] instanceof DateTime) {
482
+                    $this->_fields[$field_name]->setTimezone(new DateTimeZone($this->_timezone));
483 483
                 }
484 484
             }
485 485
         }
@@ -537,7 +537,7 @@  discard block
 block discarded – undo
537 537
      */
538 538
     public function get_format($full = true)
539 539
     {
540
-        return $full ? $this->_dt_frmt . ' ' . $this->_tm_frmt : array($this->_dt_frmt, $this->_tm_frmt);
540
+        return $full ? $this->_dt_frmt.' '.$this->_tm_frmt : array($this->_dt_frmt, $this->_tm_frmt);
541 541
     }
542 542
 
543 543
 
@@ -563,11 +563,11 @@  discard block
 block discarded – undo
563 563
     public function cache($relationName = '', $object_to_cache = null, $cache_id = null)
564 564
     {
565 565
         // its entirely possible that there IS no related object yet in which case there is nothing to cache.
566
-        if (! $object_to_cache instanceof EE_Base_Class) {
566
+        if ( ! $object_to_cache instanceof EE_Base_Class) {
567 567
             return false;
568 568
         }
569 569
         // also get "how" the object is related, or throw an error
570
-        if (! $relationship_to_model = $this->get_model()->related_settings_for($relationName)) {
570
+        if ( ! $relationship_to_model = $this->get_model()->related_settings_for($relationName)) {
571 571
             throw new EE_Error(
572 572
                 sprintf(
573 573
                     esc_html__('There is no relationship to %s on a %s. Cannot cache it', 'event_espresso'),
@@ -581,38 +581,38 @@  discard block
 block discarded – undo
581 581
             // if it's a "belongs to" relationship, then there's only one related model object
582 582
             // eg, if this is a registration, there's only 1 attendee for it
583 583
             // so for these model objects just set it to be cached
584
-            $this->_model_relations[ $relationName ] = $object_to_cache;
584
+            $this->_model_relations[$relationName] = $object_to_cache;
585 585
             $return                                  = true;
586 586
         } else {
587 587
             // otherwise, this is the "many" side of a one to many relationship,
588 588
             // so we'll add the object to the array of related objects for that type.
589 589
             // eg: if this is an event, there are many registrations for that event,
590 590
             // so we cache the registrations in an array
591
-            if (! is_array($this->_model_relations[ $relationName ])) {
591
+            if ( ! is_array($this->_model_relations[$relationName])) {
592 592
                 // if for some reason, the cached item is a model object,
593 593
                 // then stick that in the array, otherwise start with an empty array
594
-                $this->_model_relations[ $relationName ] = $this->_model_relations[ $relationName ]
594
+                $this->_model_relations[$relationName] = $this->_model_relations[$relationName]
595 595
                                                            instanceof
596 596
                                                            EE_Base_Class
597
-                    ? array($this->_model_relations[ $relationName ]) : array();
597
+                    ? array($this->_model_relations[$relationName]) : array();
598 598
             }
599 599
             // first check for a cache_id which is normally empty
600
-            if (! empty($cache_id)) {
600
+            if ( ! empty($cache_id)) {
601 601
                 // if the cache_id exists, then it means we are purposely trying to cache this
602 602
                 // with a known key that can then be used to retrieve the object later on
603
-                $this->_model_relations[ $relationName ][ $cache_id ] = $object_to_cache;
603
+                $this->_model_relations[$relationName][$cache_id] = $object_to_cache;
604 604
                 $return                                               = $cache_id;
605 605
             } elseif ($object_to_cache->ID()) {
606 606
                 // OR the cached object originally came from the db, so let's just use it's PK for an ID
607
-                $this->_model_relations[ $relationName ][ $object_to_cache->ID() ] = $object_to_cache;
607
+                $this->_model_relations[$relationName][$object_to_cache->ID()] = $object_to_cache;
608 608
                 $return                                                            = $object_to_cache->ID();
609 609
             } else {
610 610
                 // OR it's a new object with no ID, so just throw it in the array with an auto-incremented ID
611
-                $this->_model_relations[ $relationName ][] = $object_to_cache;
611
+                $this->_model_relations[$relationName][] = $object_to_cache;
612 612
                 // move the internal pointer to the end of the array
613
-                end($this->_model_relations[ $relationName ]);
613
+                end($this->_model_relations[$relationName]);
614 614
                 // and grab the key so that we can return it
615
-                $return = key($this->_model_relations[ $relationName ]);
615
+                $return = key($this->_model_relations[$relationName]);
616 616
             }
617 617
         }
618 618
         return $return;
@@ -638,7 +638,7 @@  discard block
 block discarded – undo
638 638
         //first make sure this property exists
639 639
         $this->get_model()->field_settings_for($fieldname);
640 640
         $cache_type                                            = empty($cache_type) ? 'standard' : $cache_type;
641
-        $this->_cached_properties[ $fieldname ][ $cache_type ] = $value;
641
+        $this->_cached_properties[$fieldname][$cache_type] = $value;
642 642
     }
643 643
 
644 644
 
@@ -667,9 +667,9 @@  discard block
 block discarded – undo
667 667
         $model = $this->get_model();
668 668
         $model->field_settings_for($fieldname);
669 669
         $cache_type = $pretty ? 'pretty' : 'standard';
670
-        $cache_type .= ! empty($extra_cache_ref) ? '_' . $extra_cache_ref : '';
671
-        if (isset($this->_cached_properties[ $fieldname ][ $cache_type ])) {
672
-            return $this->_cached_properties[ $fieldname ][ $cache_type ];
670
+        $cache_type .= ! empty($extra_cache_ref) ? '_'.$extra_cache_ref : '';
671
+        if (isset($this->_cached_properties[$fieldname][$cache_type])) {
672
+            return $this->_cached_properties[$fieldname][$cache_type];
673 673
         }
674 674
         $value = $this->_get_fresh_property($fieldname, $pretty, $extra_cache_ref);
675 675
         $this->_set_cached_property($fieldname, $value, $cache_type);
@@ -697,12 +697,12 @@  discard block
 block discarded – undo
697 697
         if ($field_obj instanceof EE_Datetime_Field) {
698 698
             $this->_prepare_datetime_field($field_obj, $pretty, $extra_cache_ref);
699 699
         }
700
-        if (! isset($this->_fields[ $fieldname ])) {
701
-            $this->_fields[ $fieldname ] = null;
700
+        if ( ! isset($this->_fields[$fieldname])) {
701
+            $this->_fields[$fieldname] = null;
702 702
         }
703 703
         $value = $pretty
704
-            ? $field_obj->prepare_for_pretty_echoing($this->_fields[ $fieldname ], $extra_cache_ref)
705
-            : $field_obj->prepare_for_get($this->_fields[ $fieldname ]);
704
+            ? $field_obj->prepare_for_pretty_echoing($this->_fields[$fieldname], $extra_cache_ref)
705
+            : $field_obj->prepare_for_get($this->_fields[$fieldname]);
706 706
         return $value;
707 707
     }
708 708
 
@@ -760,8 +760,8 @@  discard block
 block discarded – undo
760 760
      */
761 761
     protected function _clear_cached_property($property_name)
762 762
     {
763
-        if (isset($this->_cached_properties[ $property_name ])) {
764
-            unset($this->_cached_properties[ $property_name ]);
763
+        if (isset($this->_cached_properties[$property_name])) {
764
+            unset($this->_cached_properties[$property_name]);
765 765
         }
766 766
     }
767 767
 
@@ -813,7 +813,7 @@  discard block
 block discarded – undo
813 813
     {
814 814
         $relationship_to_model = $this->get_model()->related_settings_for($relationName);
815 815
         $index_in_cache        = '';
816
-        if (! $relationship_to_model) {
816
+        if ( ! $relationship_to_model) {
817 817
             throw new EE_Error(
818 818
                 sprintf(
819 819
                     esc_html__('There is no relationship to %s on a %s. Cannot clear that cache', 'event_espresso'),
@@ -824,21 +824,21 @@  discard block
 block discarded – undo
824 824
         }
825 825
         if ($clear_all) {
826 826
             $obj_removed                             = true;
827
-            $this->_model_relations[ $relationName ] = null;
827
+            $this->_model_relations[$relationName] = null;
828 828
         } elseif ($relationship_to_model instanceof EE_Belongs_To_Relation) {
829
-            $obj_removed                             = $this->_model_relations[ $relationName ];
830
-            $this->_model_relations[ $relationName ] = null;
829
+            $obj_removed                             = $this->_model_relations[$relationName];
830
+            $this->_model_relations[$relationName] = null;
831 831
         } else {
832 832
             if ($object_to_remove_or_index_into_array instanceof EE_Base_Class
833 833
                 && $object_to_remove_or_index_into_array->ID()
834 834
             ) {
835 835
                 $index_in_cache = $object_to_remove_or_index_into_array->ID();
836
-                if (is_array($this->_model_relations[ $relationName ])
837
-                    && ! isset($this->_model_relations[ $relationName ][ $index_in_cache ])
836
+                if (is_array($this->_model_relations[$relationName])
837
+                    && ! isset($this->_model_relations[$relationName][$index_in_cache])
838 838
                 ) {
839 839
                     $index_found_at = null;
840 840
                     //find this object in the array even though it has a different key
841
-                    foreach ($this->_model_relations[ $relationName ] as $index => $obj) {
841
+                    foreach ($this->_model_relations[$relationName] as $index => $obj) {
842 842
                         /** @noinspection TypeUnsafeComparisonInspection */
843 843
                         if (
844 844
                             $obj instanceof EE_Base_Class
@@ -872,9 +872,9 @@  discard block
 block discarded – undo
872 872
             }
873 873
             //supposedly we've found it. But it could just be that the client code
874 874
             //provided a bad index/object
875
-            if (isset($this->_model_relations[ $relationName ][ $index_in_cache ])) {
876
-                $obj_removed = $this->_model_relations[ $relationName ][ $index_in_cache ];
877
-                unset($this->_model_relations[ $relationName ][ $index_in_cache ]);
875
+            if (isset($this->_model_relations[$relationName][$index_in_cache])) {
876
+                $obj_removed = $this->_model_relations[$relationName][$index_in_cache];
877
+                unset($this->_model_relations[$relationName][$index_in_cache]);
878 878
             } else {
879 879
                 //that thing was never cached anyways.
880 880
                 $obj_removed = null;
@@ -905,7 +905,7 @@  discard block
 block discarded – undo
905 905
         $current_cache_id = ''
906 906
     ) {
907 907
         // verify that incoming object is of the correct type
908
-        $obj_class = 'EE_' . $relationName;
908
+        $obj_class = 'EE_'.$relationName;
909 909
         if ($newly_saved_object instanceof $obj_class) {
910 910
             /* @type EE_Base_Class $newly_saved_object */
911 911
             // now get the type of relation
@@ -913,17 +913,17 @@  discard block
 block discarded – undo
913 913
             // if this is a 1:1 relationship
914 914
             if ($relationship_to_model instanceof EE_Belongs_To_Relation) {
915 915
                 // then just replace the cached object with the newly saved object
916
-                $this->_model_relations[ $relationName ] = $newly_saved_object;
916
+                $this->_model_relations[$relationName] = $newly_saved_object;
917 917
                 return true;
918 918
                 // or if it's some kind of sordid feral polyamorous relationship...
919 919
             }
920
-            if (is_array($this->_model_relations[ $relationName ])
921
-                      && isset($this->_model_relations[ $relationName ][ $current_cache_id ])
920
+            if (is_array($this->_model_relations[$relationName])
921
+                      && isset($this->_model_relations[$relationName][$current_cache_id])
922 922
             ) {
923 923
                 // then remove the current cached item
924
-                unset($this->_model_relations[ $relationName ][ $current_cache_id ]);
924
+                unset($this->_model_relations[$relationName][$current_cache_id]);
925 925
                 // and cache the newly saved object using it's new ID
926
-                $this->_model_relations[ $relationName ][ $newly_saved_object->ID() ] = $newly_saved_object;
926
+                $this->_model_relations[$relationName][$newly_saved_object->ID()] = $newly_saved_object;
927 927
                 return true;
928 928
             }
929 929
         }
@@ -940,8 +940,8 @@  discard block
 block discarded – undo
940 940
      */
941 941
     public function get_one_from_cache($relationName)
942 942
     {
943
-        $cached_array_or_object = isset($this->_model_relations[ $relationName ])
944
-            ? $this->_model_relations[ $relationName ]
943
+        $cached_array_or_object = isset($this->_model_relations[$relationName])
944
+            ? $this->_model_relations[$relationName]
945 945
             : null;
946 946
         if (is_array($cached_array_or_object)) {
947 947
             return array_shift($cached_array_or_object);
@@ -964,7 +964,7 @@  discard block
 block discarded – undo
964 964
      */
965 965
     public function get_all_from_cache($relationName)
966 966
     {
967
-        $objects = isset($this->_model_relations[ $relationName ]) ? $this->_model_relations[ $relationName ] : array();
967
+        $objects = isset($this->_model_relations[$relationName]) ? $this->_model_relations[$relationName] : array();
968 968
         // if the result is not an array, but exists, make it an array
969 969
         $objects = is_array($objects) ? $objects : array($objects);
970 970
         //bugfix for https://events.codebasehq.com/projects/event-espresso/tickets/7143
@@ -1148,7 +1148,7 @@  discard block
 block discarded – undo
1148 1148
             } else {
1149 1149
                 $field_value = $field_obj->prepare_for_set_from_db($field_value_from_db);
1150 1150
             }
1151
-            $this->_fields[ $field_name ] = $field_value;
1151
+            $this->_fields[$field_name] = $field_value;
1152 1152
             $this->_clear_cached_property($field_name);
1153 1153
         }
1154 1154
     }
@@ -1188,9 +1188,9 @@  discard block
 block discarded – undo
1188 1188
     public function get_raw($field_name)
1189 1189
     {
1190 1190
         $field_settings = $this->get_model()->field_settings_for($field_name);
1191
-        return $field_settings instanceof EE_Datetime_Field && $this->_fields[ $field_name ] instanceof DateTime
1192
-            ? $this->_fields[ $field_name ]->format('U')
1193
-            : $this->_fields[ $field_name ];
1191
+        return $field_settings instanceof EE_Datetime_Field && $this->_fields[$field_name] instanceof DateTime
1192
+            ? $this->_fields[$field_name]->format('U')
1193
+            : $this->_fields[$field_name];
1194 1194
     }
1195 1195
 
1196 1196
 
@@ -1212,7 +1212,7 @@  discard block
 block discarded – undo
1212 1212
     public function get_DateTime_object($field_name)
1213 1213
     {
1214 1214
         $field_settings = $this->get_model()->field_settings_for($field_name);
1215
-        if (! $field_settings instanceof EE_Datetime_Field) {
1215
+        if ( ! $field_settings instanceof EE_Datetime_Field) {
1216 1216
             EE_Error::add_error(
1217 1217
                 sprintf(
1218 1218
                     esc_html__(
@@ -1470,7 +1470,7 @@  discard block
 block discarded – undo
1470 1470
      */
1471 1471
     public function get_i18n_datetime($field_name, $format = '')
1472 1472
     {
1473
-        $format = empty($format) ? $this->_dt_frmt . ' ' . $this->_tm_frmt : $format;
1473
+        $format = empty($format) ? $this->_dt_frmt.' '.$this->_tm_frmt : $format;
1474 1474
         return date_i18n(
1475 1475
             $format,
1476 1476
             EEH_DTT_Helper::get_timestamp_with_offset(
@@ -1582,19 +1582,19 @@  discard block
 block discarded – undo
1582 1582
         $field->set_time_format($this->_tm_frmt);
1583 1583
         switch ($what) {
1584 1584
             case 'T' :
1585
-                $this->_fields[ $fieldname ] = $field->prepare_for_set_with_new_time(
1585
+                $this->_fields[$fieldname] = $field->prepare_for_set_with_new_time(
1586 1586
                     $datetime_value,
1587
-                    $this->_fields[ $fieldname ]
1587
+                    $this->_fields[$fieldname]
1588 1588
                 );
1589 1589
                 break;
1590 1590
             case 'D' :
1591
-                $this->_fields[ $fieldname ] = $field->prepare_for_set_with_new_date(
1591
+                $this->_fields[$fieldname] = $field->prepare_for_set_with_new_date(
1592 1592
                     $datetime_value,
1593
-                    $this->_fields[ $fieldname ]
1593
+                    $this->_fields[$fieldname]
1594 1594
                 );
1595 1595
                 break;
1596 1596
             case 'B' :
1597
-                $this->_fields[ $fieldname ] = $field->prepare_for_set($datetime_value);
1597
+                $this->_fields[$fieldname] = $field->prepare_for_set($datetime_value);
1598 1598
                 break;
1599 1599
         }
1600 1600
         $this->_clear_cached_property($fieldname);
@@ -1636,7 +1636,7 @@  discard block
 block discarded – undo
1636 1636
         $this->set_timezone($timezone);
1637 1637
         $fn   = (array) $field_name;
1638 1638
         $args = array_merge($fn, (array) $args);
1639
-        if (! method_exists($this, $callback)) {
1639
+        if ( ! method_exists($this, $callback)) {
1640 1640
             throw new EE_Error(
1641 1641
                 sprintf(
1642 1642
                     esc_html__(
@@ -1648,7 +1648,7 @@  discard block
 block discarded – undo
1648 1648
             );
1649 1649
         }
1650 1650
         $args   = (array) $args;
1651
-        $return = $prepend . call_user_func_array(array($this, $callback), $args) . $append;
1651
+        $return = $prepend.call_user_func_array(array($this, $callback), $args).$append;
1652 1652
         $this->set_timezone($original_timezone);
1653 1653
         return $return;
1654 1654
     }
@@ -1763,8 +1763,8 @@  discard block
 block discarded – undo
1763 1763
     {
1764 1764
         $model = $this->get_model();
1765 1765
         foreach ($model->relation_settings() as $relation_name => $relation_obj) {
1766
-            if (! empty($this->_model_relations[ $relation_name ])) {
1767
-                $related_objects = $this->_model_relations[ $relation_name ];
1766
+            if ( ! empty($this->_model_relations[$relation_name])) {
1767
+                $related_objects = $this->_model_relations[$relation_name];
1768 1768
                 if ($relation_obj instanceof EE_Belongs_To_Relation) {
1769 1769
                     //this relation only stores a single model object, not an array
1770 1770
                     //but let's make it consistent
@@ -1821,7 +1821,7 @@  discard block
 block discarded – undo
1821 1821
             $this->set($column, $value);
1822 1822
         }
1823 1823
         // no changes ? then don't do anything
1824
-        if (! $this->_has_changes && $this->ID() && $model->get_primary_key_field()->is_auto_increment()) {
1824
+        if ( ! $this->_has_changes && $this->ID() && $model->get_primary_key_field()->is_auto_increment()) {
1825 1825
             return 0;
1826 1826
         }
1827 1827
         /**
@@ -1831,7 +1831,7 @@  discard block
 block discarded – undo
1831 1831
          * @param EE_Base_Class $model_object the model object about to be saved.
1832 1832
          */
1833 1833
         do_action('AHEE__EE_Base_Class__save__begin', $this);
1834
-        if (! $this->allow_persist()) {
1834
+        if ( ! $this->allow_persist()) {
1835 1835
             return 0;
1836 1836
         }
1837 1837
         // now get current attribute values
@@ -1846,10 +1846,10 @@  discard block
 block discarded – undo
1846 1846
         if ($model->has_primary_key_field()) {
1847 1847
             if ($model->get_primary_key_field()->is_auto_increment()) {
1848 1848
                 //ok check if it's set, if so: update; if not, insert
1849
-                if (! empty($save_cols_n_values[ $model->primary_key_name() ])) {
1849
+                if ( ! empty($save_cols_n_values[$model->primary_key_name()])) {
1850 1850
                     $results = $model->update_by_ID($save_cols_n_values, $this->ID());
1851 1851
                 } else {
1852
-                    unset($save_cols_n_values[ $model->primary_key_name() ]);
1852
+                    unset($save_cols_n_values[$model->primary_key_name()]);
1853 1853
                     $results = $model->insert($save_cols_n_values);
1854 1854
                     if ($results) {
1855 1855
                         //if successful, set the primary key
@@ -1859,7 +1859,7 @@  discard block
 block discarded – undo
1859 1859
                         //will get added to the mapper before we can add this one!
1860 1860
                         //but if we just avoid using the SET method, all that headache can be avoided
1861 1861
                         $pk_field_name                   = $model->primary_key_name();
1862
-                        $this->_fields[ $pk_field_name ] = $results;
1862
+                        $this->_fields[$pk_field_name] = $results;
1863 1863
                         $this->_clear_cached_property($pk_field_name);
1864 1864
                         $model->add_to_entity_map($this);
1865 1865
                         $this->_update_cached_related_model_objs_fks();
@@ -1876,8 +1876,8 @@  discard block
 block discarded – undo
1876 1876
                                     'event_espresso'
1877 1877
                                 ),
1878 1878
                                 get_class($this),
1879
-                                get_class($model) . '::instance()->add_to_entity_map()',
1880
-                                get_class($model) . '::instance()->get_one_by_ID()',
1879
+                                get_class($model).'::instance()->add_to_entity_map()',
1880
+                                get_class($model).'::instance()->get_one_by_ID()',
1881 1881
                                 '<br />'
1882 1882
                             )
1883 1883
                         );
@@ -1977,27 +1977,27 @@  discard block
 block discarded – undo
1977 1977
     public function save_new_cached_related_model_objs()
1978 1978
     {
1979 1979
         //make sure this has been saved
1980
-        if (! $this->ID()) {
1980
+        if ( ! $this->ID()) {
1981 1981
             $id = $this->save();
1982 1982
         } else {
1983 1983
             $id = $this->ID();
1984 1984
         }
1985 1985
         //now save all the NEW cached model objects  (ie they don't exist in the DB)
1986 1986
         foreach ($this->get_model()->relation_settings() as $relationName => $relationObj) {
1987
-            if ($this->_model_relations[ $relationName ]) {
1987
+            if ($this->_model_relations[$relationName]) {
1988 1988
                 //is this a relation where we should expect just ONE related object (ie, EE_Belongs_To_relation)
1989 1989
                 //or MANY related objects (ie, EE_HABTM_Relation or EE_Has_Many_Relation)?
1990 1990
                 /* @var $related_model_obj EE_Base_Class */
1991 1991
                 if ($relationObj instanceof EE_Belongs_To_Relation) {
1992 1992
                     //add a relation to that relation type (which saves the appropriate thing in the process)
1993 1993
                     //but ONLY if it DOES NOT exist in the DB
1994
-                    $related_model_obj = $this->_model_relations[ $relationName ];
1994
+                    $related_model_obj = $this->_model_relations[$relationName];
1995 1995
                     //					if( ! $related_model_obj->ID()){
1996 1996
                     $this->_add_relation_to($related_model_obj, $relationName);
1997 1997
                     $related_model_obj->save_new_cached_related_model_objs();
1998 1998
                     //					}
1999 1999
                 } else {
2000
-                    foreach ($this->_model_relations[ $relationName ] as $related_model_obj) {
2000
+                    foreach ($this->_model_relations[$relationName] as $related_model_obj) {
2001 2001
                         //add a relation to that relation type (which saves the appropriate thing in the process)
2002 2002
                         //but ONLY if it DOES NOT exist in the DB
2003 2003
                         //						if( ! $related_model_obj->ID()){
@@ -2024,7 +2024,7 @@  discard block
 block discarded – undo
2024 2024
      */
2025 2025
     public function get_model()
2026 2026
     {
2027
-        if (! $this->_model) {
2027
+        if ( ! $this->_model) {
2028 2028
             $modelName    = self::_get_model_classname(get_class($this));
2029 2029
             $this->_model = self::_get_model_instance_with_name($modelName, $this->_timezone);
2030 2030
         } else {
@@ -2050,9 +2050,9 @@  discard block
 block discarded – undo
2050 2050
         $primary_id_ref = self::_get_primary_key_name($classname);
2051 2051
         if (
2052 2052
             array_key_exists($primary_id_ref, $props_n_values)
2053
-            && ! empty($props_n_values[ $primary_id_ref ])
2053
+            && ! empty($props_n_values[$primary_id_ref])
2054 2054
         ) {
2055
-            $id = $props_n_values[ $primary_id_ref ];
2055
+            $id = $props_n_values[$primary_id_ref];
2056 2056
             return self::_get_model($classname)->get_from_entity_map($id);
2057 2057
         }
2058 2058
         return false;
@@ -2086,10 +2086,10 @@  discard block
 block discarded – undo
2086 2086
         if ($model->has_primary_key_field()) {
2087 2087
             $primary_id_ref = self::_get_primary_key_name($classname);
2088 2088
             if (array_key_exists($primary_id_ref, $props_n_values)
2089
-                && ! empty($props_n_values[ $primary_id_ref ])
2089
+                && ! empty($props_n_values[$primary_id_ref])
2090 2090
             ) {
2091 2091
                 $existing = $model->get_one_by_ID(
2092
-                    $props_n_values[ $primary_id_ref ]
2092
+                    $props_n_values[$primary_id_ref]
2093 2093
                 );
2094 2094
             }
2095 2095
         } elseif ($model->has_all_combined_primary_key_fields($props_n_values)) {
@@ -2101,7 +2101,7 @@  discard block
 block discarded – undo
2101 2101
         }
2102 2102
         if ($existing) {
2103 2103
             //set date formats if present before setting values
2104
-            if (! empty($date_formats) && is_array($date_formats)) {
2104
+            if ( ! empty($date_formats) && is_array($date_formats)) {
2105 2105
                 $existing->set_date_format($date_formats[0]);
2106 2106
                 $existing->set_time_format($date_formats[1]);
2107 2107
             } else {
@@ -2134,7 +2134,7 @@  discard block
 block discarded – undo
2134 2134
     protected static function _get_model($classname, $timezone = null)
2135 2135
     {
2136 2136
         //find model for this class
2137
-        if (! $classname) {
2137
+        if ( ! $classname) {
2138 2138
             throw new EE_Error(
2139 2139
                 sprintf(
2140 2140
                     esc_html__(
@@ -2183,7 +2183,7 @@  discard block
 block discarded – undo
2183 2183
         if (strpos($model_name, 'EE_') === 0) {
2184 2184
             $model_classname = str_replace('EE_', 'EEM_', $model_name);
2185 2185
         } else {
2186
-            $model_classname = 'EEM_' . $model_name;
2186
+            $model_classname = 'EEM_'.$model_name;
2187 2187
         }
2188 2188
         return $model_classname;
2189 2189
     }
@@ -2202,7 +2202,7 @@  discard block
 block discarded – undo
2202 2202
      */
2203 2203
     protected static function _get_primary_key_name($classname = null)
2204 2204
     {
2205
-        if (! $classname) {
2205
+        if ( ! $classname) {
2206 2206
             throw new EE_Error(
2207 2207
                 sprintf(
2208 2208
                     esc_html__('What were you thinking calling _get_primary_key_name(%s)', 'event_espresso'),
@@ -2232,7 +2232,7 @@  discard block
 block discarded – undo
2232 2232
         $model = $this->get_model();
2233 2233
         //now that we know the name of the variable, use a variable variable to get its value and return its
2234 2234
         if ($model->has_primary_key_field()) {
2235
-            return $this->_fields[ $model->primary_key_name() ];
2235
+            return $this->_fields[$model->primary_key_name()];
2236 2236
         }
2237 2237
         return $model->get_index_primary_key_string($this->_fields);
2238 2238
     }
@@ -2285,7 +2285,7 @@  discard block
 block discarded – undo
2285 2285
             }
2286 2286
         } else {
2287 2287
             //this thing doesn't exist in the DB,  so just cache it
2288
-            if (! $otherObjectModelObjectOrID instanceof EE_Base_Class) {
2288
+            if ( ! $otherObjectModelObjectOrID instanceof EE_Base_Class) {
2289 2289
                 throw new EE_Error(
2290 2290
                     sprintf(
2291 2291
                         esc_html__(
@@ -2450,7 +2450,7 @@  discard block
 block discarded – undo
2450 2450
             } else {
2451 2451
                 //did we already cache the result of this query?
2452 2452
                 $cached_results = $this->get_all_from_cache($relationName);
2453
-                if (! $cached_results) {
2453
+                if ( ! $cached_results) {
2454 2454
                     $related_model_objects = $this->get_model()->get_all_related(
2455 2455
                         $this,
2456 2456
                         $relationName,
@@ -2560,7 +2560,7 @@  discard block
 block discarded – undo
2560 2560
             } else {
2561 2561
                 //first, check if we've already cached the result of this query
2562 2562
                 $cached_result = $this->get_one_from_cache($relationName);
2563
-                if (! $cached_result) {
2563
+                if ( ! $cached_result) {
2564 2564
                     $related_model_object = $model->get_first_related(
2565 2565
                         $this,
2566 2566
                         $relationName,
@@ -2584,7 +2584,7 @@  discard block
 block discarded – undo
2584 2584
             }
2585 2585
             // this doesn't exist in the DB and apparently the thing it belongs to doesn't either,
2586 2586
             // just get what's cached on this object
2587
-            if (! $related_model_object) {
2587
+            if ( ! $related_model_object) {
2588 2588
                 $related_model_object = $this->get_one_from_cache($relationName);
2589 2589
             }
2590 2590
         }
@@ -2666,7 +2666,7 @@  discard block
 block discarded – undo
2666 2666
      */
2667 2667
     public function is_set($field_name)
2668 2668
     {
2669
-        return isset($this->_fields[ $field_name ]);
2669
+        return isset($this->_fields[$field_name]);
2670 2670
     }
2671 2671
 
2672 2672
 
@@ -2682,7 +2682,7 @@  discard block
 block discarded – undo
2682 2682
     {
2683 2683
         foreach ((array) $properties as $property_name) {
2684 2684
             //first make sure this property exists
2685
-            if (! $this->_fields[ $property_name ]) {
2685
+            if ( ! $this->_fields[$property_name]) {
2686 2686
                 throw new EE_Error(
2687 2687
                     sprintf(
2688 2688
                         esc_html__(
@@ -2714,7 +2714,7 @@  discard block
 block discarded – undo
2714 2714
         $properties = array();
2715 2715
         //remove prepended underscore
2716 2716
         foreach ($fields as $field_name => $settings) {
2717
-            $properties[ $field_name ] = $this->get($field_name);
2717
+            $properties[$field_name] = $this->get($field_name);
2718 2718
         }
2719 2719
         return $properties;
2720 2720
     }
@@ -2751,7 +2751,7 @@  discard block
 block discarded – undo
2751 2751
     {
2752 2752
         $className = get_class($this);
2753 2753
         $tagName   = "FHEE__{$className}__{$methodName}";
2754
-        if (! has_filter($tagName)) {
2754
+        if ( ! has_filter($tagName)) {
2755 2755
             throw new EE_Error(
2756 2756
                 sprintf(
2757 2757
                     esc_html__(
@@ -2796,7 +2796,7 @@  discard block
 block discarded – undo
2796 2796
             $query_params[0]['EXM_value'] = $meta_value;
2797 2797
         }
2798 2798
         $existing_rows_like_that = EEM_Extra_Meta::instance()->get_all($query_params);
2799
-        if (! $existing_rows_like_that) {
2799
+        if ( ! $existing_rows_like_that) {
2800 2800
             return $this->add_extra_meta($meta_key, $meta_value);
2801 2801
         }
2802 2802
         foreach ($existing_rows_like_that as $existing_row) {
@@ -2914,7 +2914,7 @@  discard block
 block discarded – undo
2914 2914
                 $values = array();
2915 2915
                 foreach ($results as $result) {
2916 2916
                     if ($result instanceof EE_Extra_Meta) {
2917
-                        $values[ $result->ID() ] = $result->value();
2917
+                        $values[$result->ID()] = $result->value();
2918 2918
                     }
2919 2919
                 }
2920 2920
                 return $values;
@@ -2959,17 +2959,17 @@  discard block
 block discarded – undo
2959 2959
             );
2960 2960
             foreach ($extra_meta_objs as $extra_meta_obj) {
2961 2961
                 if ($extra_meta_obj instanceof EE_Extra_Meta) {
2962
-                    $return_array[ $extra_meta_obj->key() ] = $extra_meta_obj->value();
2962
+                    $return_array[$extra_meta_obj->key()] = $extra_meta_obj->value();
2963 2963
                 }
2964 2964
             }
2965 2965
         } else {
2966 2966
             $extra_meta_objs = $this->get_many_related('Extra_Meta');
2967 2967
             foreach ($extra_meta_objs as $extra_meta_obj) {
2968 2968
                 if ($extra_meta_obj instanceof EE_Extra_Meta) {
2969
-                    if (! isset($return_array[ $extra_meta_obj->key() ])) {
2970
-                        $return_array[ $extra_meta_obj->key() ] = array();
2969
+                    if ( ! isset($return_array[$extra_meta_obj->key()])) {
2970
+                        $return_array[$extra_meta_obj->key()] = array();
2971 2971
                     }
2972
-                    $return_array[ $extra_meta_obj->key() ][ $extra_meta_obj->ID() ] = $extra_meta_obj->value();
2972
+                    $return_array[$extra_meta_obj->key()][$extra_meta_obj->ID()] = $extra_meta_obj->value();
2973 2973
                 }
2974 2974
             }
2975 2975
         }
@@ -3048,8 +3048,8 @@  discard block
 block discarded – undo
3048 3048
                         esc_html__('Trying to refresh a model object with ID "%1$s" that\'s not in the entity map? First off: you should put it in the entity map by calling %2$s. Second off, if you want what\'s in the database right now, you should just call %3$s yourself and discard this model object.',
3049 3049
                             'event_espresso'),
3050 3050
                         $this->ID(),
3051
-                        get_class($this->get_model()) . '::instance()->add_to_entity_map()',
3052
-                        get_class($this->get_model()) . '::instance()->refresh_entity_map()'
3051
+                        get_class($this->get_model()).'::instance()->add_to_entity_map()',
3052
+                        get_class($this->get_model()).'::instance()->refresh_entity_map()'
3053 3053
                     )
3054 3054
                 );
3055 3055
             }
@@ -3111,7 +3111,7 @@  discard block
 block discarded – undo
3111 3111
         $model = $this->get_model();
3112 3112
         foreach ($model->relation_settings() as $relation_name => $relation_obj) {
3113 3113
             if ($relation_obj instanceof EE_Belongs_To_Relation) {
3114
-                $classname = 'EE_' . $model->get_this_model_name();
3114
+                $classname = 'EE_'.$model->get_this_model_name();
3115 3115
                 if (
3116 3116
                     $this->get_one_from_cache($relation_name) instanceof $classname
3117 3117
                     && $this->get_one_from_cache($relation_name)->ID()
Please login to merge, or discard this patch.
modules/single_page_checkout/EED_Single_Page_Checkout.module.php 2 patches
Spacing   +26 added lines, -26 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'] = EED_Single_Page_Checkout::getRegistrationExpirationNotice();
236 236
     }
@@ -251,7 +251,7 @@  discard block
 block discarded – undo
251 251
             return;
252 252
         }
253 253
         // filter list of reg_steps
254
-        $reg_steps_to_load = (array)apply_filters(
254
+        $reg_steps_to_load = (array) apply_filters(
255 255
             'AHEE__SPCO__load_reg_steps__reg_steps_to_load',
256 256
             EED_Single_Page_Checkout::get_reg_steps()
257 257
         );
@@ -303,25 +303,25 @@  discard block
 block discarded – undo
303 303
         if (empty($reg_steps)) {
304 304
             $reg_steps = array(
305 305
                 10  => array(
306
-                    'file_path'  => SPCO_REG_STEPS_PATH . 'attendee_information',
306
+                    'file_path'  => SPCO_REG_STEPS_PATH.'attendee_information',
307 307
                     'class_name' => 'EE_SPCO_Reg_Step_Attendee_Information',
308 308
                     'slug'       => 'attendee_information',
309 309
                     'has_hooks'  => false,
310 310
                 ),
311 311
                 20  => array(
312
-                    'file_path'  => SPCO_REG_STEPS_PATH . 'registration_confirmation',
312
+                    'file_path'  => SPCO_REG_STEPS_PATH.'registration_confirmation',
313 313
                     'class_name' => 'EE_SPCO_Reg_Step_Registration_Confirmation',
314 314
                     'slug'       => 'registration_confirmation',
315 315
                     'has_hooks'  => false,
316 316
                 ),
317 317
                 30  => array(
318
-                    'file_path'  => SPCO_REG_STEPS_PATH . 'payment_options',
318
+                    'file_path'  => SPCO_REG_STEPS_PATH.'payment_options',
319 319
                     'class_name' => 'EE_SPCO_Reg_Step_Payment_Options',
320 320
                     'slug'       => 'payment_options',
321 321
                     'has_hooks'  => true,
322 322
                 ),
323 323
                 999 => array(
324
-                    'file_path'  => SPCO_REG_STEPS_PATH . 'finalize_registration',
324
+                    'file_path'  => SPCO_REG_STEPS_PATH.'finalize_registration',
325 325
                     'class_name' => 'EE_SPCO_Reg_Step_Finalize_Registration',
326 326
                     'slug'       => 'finalize_registration',
327 327
                     'has_hooks'  => false,
@@ -505,7 +505,7 @@  discard block
 block discarded – undo
505 505
             // DEBUG LOG
506 506
             //$this->checkout->log( __CLASS__, __FUNCTION__, __LINE__ );
507 507
             // get reg form
508
-            if( ! $this->_check_form_submission()) {
508
+            if ( ! $this->_check_form_submission()) {
509 509
                 EED_Single_Page_Checkout::$_initialized = true;
510 510
                 return;
511 511
             }
@@ -546,7 +546,7 @@  discard block
 block discarded – undo
546 546
         );
547 547
         // is session still valid ?
548 548
         if ($clear_session_requested
549
-            || ( EE_Registry::instance()->SSN->expired()
549
+            || (EE_Registry::instance()->SSN->expired()
550 550
               && EE_Registry::instance()->REQ->get('e_reg_url_link', '') === ''
551 551
             )
552 552
         ) {
@@ -555,7 +555,7 @@  discard block
 block discarded – undo
555 555
             // EE_Registry::instance()->SSN->reset_cart();
556 556
             // EE_Registry::instance()->SSN->reset_checkout();
557 557
             // EE_Registry::instance()->SSN->reset_transaction();
558
-            if (! $clear_session_requested) {
558
+            if ( ! $clear_session_requested) {
559 559
                 EE_Error::add_attention(
560 560
                     EE_Registry::$i18n_js_strings['registration_expiration_notice'],
561 561
                     __FILE__, __FUNCTION__, __LINE__
@@ -1114,7 +1114,7 @@  discard block
 block discarded – undo
1114 1114
                     if ( ! $registration instanceof EE_Registration) {
1115 1115
                         throw new InvalidEntityException($registration, 'EE_Registration');
1116 1116
                     }
1117
-                    $registrations[ $registration->ID() ] = $registration;
1117
+                    $registrations[$registration->ID()] = $registration;
1118 1118
                 }
1119 1119
             }
1120 1120
             $registration_processor->fix_reg_final_price_rounding_issue($transaction);
@@ -1375,7 +1375,7 @@  discard block
 block discarded – undo
1375 1375
                         ) {
1376 1376
                             EE_Error::add_success(
1377 1377
                                 $this->checkout->current_step->success_message()
1378
-                                . '<br />' . $this->checkout->next_step->_instructions()
1378
+                                . '<br />'.$this->checkout->next_step->_instructions()
1379 1379
                             );
1380 1380
                         }
1381 1381
                         // pack it up, pack it in...
@@ -1519,7 +1519,7 @@  discard block
 block discarded – undo
1519 1519
         // load css
1520 1520
         wp_register_style(
1521 1521
             'single_page_checkout',
1522
-            SPCO_CSS_URL . 'single_page_checkout.css',
1522
+            SPCO_CSS_URL.'single_page_checkout.css',
1523 1523
             array('espresso_default'),
1524 1524
             EVENT_ESPRESSO_VERSION
1525 1525
         );
@@ -1527,21 +1527,21 @@  discard block
 block discarded – undo
1527 1527
         // load JS
1528 1528
         wp_register_script(
1529 1529
             'jquery_plugin',
1530
-            EE_THIRD_PARTY_URL . 'jquery	.plugin.min.js',
1530
+            EE_THIRD_PARTY_URL.'jquery	.plugin.min.js',
1531 1531
             array('jquery'),
1532 1532
             '1.0.1',
1533 1533
             true
1534 1534
         );
1535 1535
         wp_register_script(
1536 1536
             'jquery_countdown',
1537
-            EE_THIRD_PARTY_URL . 'jquery	.countdown.min.js',
1537
+            EE_THIRD_PARTY_URL.'jquery	.countdown.min.js',
1538 1538
             array('jquery_plugin'),
1539 1539
             '2.0.2',
1540 1540
             true
1541 1541
         );
1542 1542
         wp_register_script(
1543 1543
             'single_page_checkout',
1544
-            SPCO_JS_URL . 'single_page_checkout.js',
1544
+            SPCO_JS_URL.'single_page_checkout.js',
1545 1545
             array('espresso_core', 'underscore', 'ee_form_section_validation', 'jquery_countdown'),
1546 1546
             EVENT_ESPRESSO_VERSION,
1547 1547
             true
@@ -1564,7 +1564,7 @@  discard block
 block discarded – undo
1564 1564
          *      AHEE__EED_Single_Page_Checkout__enqueue_styles_and_scripts__attendee_information
1565 1565
          */
1566 1566
         do_action(
1567
-            'AHEE__EED_Single_Page_Checkout__enqueue_styles_and_scripts__' . $this->checkout->current_step->slug(),
1567
+            'AHEE__EED_Single_Page_Checkout__enqueue_styles_and_scripts__'.$this->checkout->current_step->slug(),
1568 1568
             $this
1569 1569
         );
1570 1570
     }
@@ -1618,7 +1618,7 @@  discard block
 block discarded – undo
1618 1618
                     'layout_strategy' =>
1619 1619
                         new EE_Template_Layout(
1620 1620
                             array(
1621
-                                'layout_template_file' => SPCO_TEMPLATES_PATH . 'registration_page_wrapper.template.php',
1621
+                                'layout_template_file' => SPCO_TEMPLATES_PATH.'registration_page_wrapper.template.php',
1622 1622
                                 'template_args'        => array(
1623 1623
                                     'empty_cart'              => $empty_cart,
1624 1624
                                     'revisit'                 => $this->checkout->revisit,
@@ -1692,7 +1692,7 @@  discard block
 block discarded – undo
1692 1692
         ) {
1693 1693
             add_filter(
1694 1694
                 'FHEE__EEH_Template__powered_by_event_espresso__url',
1695
-                function ($url) {
1695
+                function($url) {
1696 1696
                     return apply_filters('FHEE__EE_Front_Controller__registration_footer__url', $url);
1697 1697
                 }
1698 1698
             );
@@ -1871,7 +1871,7 @@  discard block
 block discarded – undo
1871 1871
             '</h4>',
1872 1872
             '<br />',
1873 1873
             '<p>',
1874
-            '<a href="' . get_post_type_archive_link('espresso_events') . '" title="',
1874
+            '<a href="'.get_post_type_archive_link('espresso_events').'" title="',
1875 1875
             '">',
1876 1876
             '</a>',
1877 1877
             '</p>'
Please login to merge, or discard this patch.
Indentation   +1844 added lines, -1844 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,1849 +20,1849 @@  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'] = EED_Single_Page_Checkout::getRegistrationExpirationNotice();
236
-    }
237
-
238
-
239
-
240
-    /**
241
-     * load_reg_steps
242
-     * loads and instantiates each reg step based on the EE_Registry::instance()->CFG->registration->reg_steps array
243
-     *
244
-     * @access    private
245
-     * @throws EE_Error
246
-     */
247
-    public static function load_reg_steps()
248
-    {
249
-        static $reg_steps_loaded = false;
250
-        if ($reg_steps_loaded) {
251
-            return;
252
-        }
253
-        // filter list of reg_steps
254
-        $reg_steps_to_load = (array)apply_filters(
255
-            'AHEE__SPCO__load_reg_steps__reg_steps_to_load',
256
-            EED_Single_Page_Checkout::get_reg_steps()
257
-        );
258
-        // sort by key (order)
259
-        ksort($reg_steps_to_load);
260
-        // loop through folders
261
-        foreach ($reg_steps_to_load as $order => $reg_step) {
262
-            // we need a
263
-            if (isset($reg_step['file_path'], $reg_step['class_name'], $reg_step['slug'])) {
264
-                // copy over to the reg_steps_array
265
-                EED_Single_Page_Checkout::$_reg_steps_array[$order] = $reg_step;
266
-                // register custom key route for each reg step
267
-                // ie: step=>"slug" - this is the entire reason we load the reg steps array now
268
-                EE_Config::register_route(
269
-                    $reg_step['slug'],
270
-                    'EED_Single_Page_Checkout',
271
-                    'run',
272
-                    'step'
273
-                );
274
-                // add AJAX or other hooks
275
-                if (isset($reg_step['has_hooks']) && $reg_step['has_hooks']) {
276
-                    // setup autoloaders if necessary
277
-                    if ( ! class_exists($reg_step['class_name'])) {
278
-                        EEH_Autoloader::register_autoloaders_for_each_file_in_folder(
279
-                            $reg_step['file_path'],
280
-                            true
281
-                        );
282
-                    }
283
-                    if (is_callable($reg_step['class_name'], 'set_hooks')) {
284
-                        call_user_func(array($reg_step['class_name'], 'set_hooks'));
285
-                    }
286
-                }
287
-            }
288
-        }
289
-        $reg_steps_loaded = true;
290
-    }
291
-
292
-
293
-
294
-    /**
295
-     *    get_reg_steps
296
-     *
297
-     * @access    public
298
-     * @return    array
299
-     */
300
-    public static function get_reg_steps()
301
-    {
302
-        $reg_steps = EE_Registry::instance()->CFG->registration->reg_steps;
303
-        if (empty($reg_steps)) {
304
-            $reg_steps = array(
305
-                10  => array(
306
-                    'file_path'  => SPCO_REG_STEPS_PATH . 'attendee_information',
307
-                    'class_name' => 'EE_SPCO_Reg_Step_Attendee_Information',
308
-                    'slug'       => 'attendee_information',
309
-                    'has_hooks'  => false,
310
-                ),
311
-                20  => array(
312
-                    'file_path'  => SPCO_REG_STEPS_PATH . 'registration_confirmation',
313
-                    'class_name' => 'EE_SPCO_Reg_Step_Registration_Confirmation',
314
-                    'slug'       => 'registration_confirmation',
315
-                    'has_hooks'  => false,
316
-                ),
317
-                30  => array(
318
-                    'file_path'  => SPCO_REG_STEPS_PATH . 'payment_options',
319
-                    'class_name' => 'EE_SPCO_Reg_Step_Payment_Options',
320
-                    'slug'       => 'payment_options',
321
-                    'has_hooks'  => true,
322
-                ),
323
-                999 => array(
324
-                    'file_path'  => SPCO_REG_STEPS_PATH . 'finalize_registration',
325
-                    'class_name' => 'EE_SPCO_Reg_Step_Finalize_Registration',
326
-                    'slug'       => 'finalize_registration',
327
-                    'has_hooks'  => false,
328
-                ),
329
-            );
330
-        }
331
-        return $reg_steps;
332
-    }
333
-
334
-
335
-
336
-    /**
337
-     *    registration_checkout_for_admin
338
-     *
339
-     * @access    public
340
-     * @return    string
341
-     * @throws EE_Error
342
-     */
343
-    public static function registration_checkout_for_admin()
344
-    {
345
-        EED_Single_Page_Checkout::load_request_handler();
346
-        EE_Registry::instance()->REQ->set('step', 'attendee_information');
347
-        EE_Registry::instance()->REQ->set('action', 'display_spco_reg_step');
348
-        EE_Registry::instance()->REQ->set('process_form_submission', false);
349
-        EED_Single_Page_Checkout::instance()->_initialize();
350
-        EED_Single_Page_Checkout::instance()->_display_spco_reg_form();
351
-        return EE_Registry::instance()->REQ->get_output();
352
-    }
353
-
354
-
355
-
356
-    /**
357
-     * process_registration_from_admin
358
-     *
359
-     * @access public
360
-     * @return \EE_Transaction
361
-     * @throws EE_Error
362
-     */
363
-    public static function process_registration_from_admin()
364
-    {
365
-        EED_Single_Page_Checkout::load_request_handler();
366
-        EE_Registry::instance()->REQ->set('step', 'attendee_information');
367
-        EE_Registry::instance()->REQ->set('action', 'process_reg_step');
368
-        EE_Registry::instance()->REQ->set('process_form_submission', true);
369
-        EED_Single_Page_Checkout::instance()->_initialize();
370
-        if (EED_Single_Page_Checkout::instance()->checkout->current_step->completed()) {
371
-            $final_reg_step = end(EED_Single_Page_Checkout::instance()->checkout->reg_steps);
372
-            if ($final_reg_step instanceof EE_SPCO_Reg_Step_Finalize_Registration) {
373
-                EED_Single_Page_Checkout::instance()->checkout->set_reg_step_initiated($final_reg_step);
374
-                if ($final_reg_step->process_reg_step()) {
375
-                    $final_reg_step->set_completed();
376
-                    EED_Single_Page_Checkout::instance()->checkout->update_txn_reg_steps_array();
377
-                    return EED_Single_Page_Checkout::instance()->checkout->transaction;
378
-                }
379
-            }
380
-        }
381
-        return null;
382
-    }
383
-
384
-
385
-
386
-    /**
387
-     *    run
388
-     *
389
-     * @access    public
390
-     * @param WP_Query $WP_Query
391
-     * @return    void
392
-     * @throws EE_Error
393
-     */
394
-    public function run($WP_Query)
395
-    {
396
-        if (
397
-            $WP_Query instanceof WP_Query
398
-            && $WP_Query->is_main_query()
399
-            && apply_filters('FHEE__EED_Single_Page_Checkout__run', true)
400
-            && $this->_is_reg_checkout()
401
-        ) {
402
-            $this->_initialize();
403
-        }
404
-    }
405
-
406
-
407
-
408
-    /**
409
-     * determines whether current url matches reg page url
410
-     *
411
-     * @return bool
412
-     */
413
-    protected function _is_reg_checkout()
414
-    {
415
-        // get current permalink for reg page without any extra query args
416
-        $reg_page_url = \get_permalink(EE_Config::instance()->core->reg_page_id);
417
-        // get request URI for current request, but without the scheme or host
418
-        $current_request_uri = \EEH_URL::filter_input_server_url('REQUEST_URI');
419
-        $current_request_uri = html_entity_decode($current_request_uri);
420
-        // get array of query args from the current request URI
421
-        $query_args = \EEH_URL::get_query_string($current_request_uri);
422
-        // grab page id if it is set
423
-        $page_id = isset($query_args['page_id']) ? absint($query_args['page_id']) : 0;
424
-        // and remove the page id from the query args (we will re-add it later)
425
-        unset($query_args['page_id']);
426
-        // now strip all query args from current request URI
427
-        $current_request_uri = remove_query_arg(array_keys($query_args), $current_request_uri);
428
-        // and re-add the page id if it was set
429
-        if ($page_id) {
430
-            $current_request_uri = add_query_arg('page_id', $page_id, $current_request_uri);
431
-        }
432
-        // remove slashes and ?
433
-        $current_request_uri = trim($current_request_uri, '?/');
434
-        // is current request URI part of the known full reg page URL ?
435
-        return ! empty($current_request_uri) && strpos($reg_page_url, $current_request_uri) !== false;
436
-    }
437
-
438
-
439
-
440
-    /**
441
-     * @param WP_Query $wp_query
442
-     * @return    void
443
-     * @throws EE_Error
444
-     */
445
-    public static function init($wp_query)
446
-    {
447
-        EED_Single_Page_Checkout::instance()->run($wp_query);
448
-    }
449
-
450
-
451
-
452
-    /**
453
-     *    _initialize - initial module setup
454
-     *
455
-     * @access    private
456
-     * @throws EE_Error
457
-     * @return    void
458
-     */
459
-    private function _initialize()
460
-    {
461
-        // ensure SPCO doesn't run twice
462
-        if (EED_Single_Page_Checkout::$_initialized) {
463
-            return;
464
-        }
465
-        try {
466
-            EED_Single_Page_Checkout::load_reg_steps();
467
-            $this->_verify_session();
468
-            // setup the EE_Checkout object
469
-            $this->checkout = $this->_initialize_checkout();
470
-            // filter checkout
471
-            $this->checkout = apply_filters('FHEE__EED_Single_Page_Checkout___initialize__checkout', $this->checkout);
472
-            // get the $_GET
473
-            $this->_get_request_vars();
474
-            if ($this->_block_bots()) {
475
-                return;
476
-            }
477
-            // filter continue_reg
478
-            $this->checkout->continue_reg = apply_filters(
479
-                'FHEE__EED_Single_Page_Checkout__init___continue_reg',
480
-                true,
481
-                $this->checkout
482
-            );
483
-            // load the reg steps array
484
-            if ( ! $this->_load_and_instantiate_reg_steps()) {
485
-                EED_Single_Page_Checkout::$_initialized = true;
486
-                return;
487
-            }
488
-            // set the current step
489
-            $this->checkout->set_current_step($this->checkout->step);
490
-            // and the next step
491
-            $this->checkout->set_next_step();
492
-            // verify that everything has been setup correctly
493
-            if ( ! ($this->_verify_transaction_and_get_registrations() && $this->_final_verifications())) {
494
-                EED_Single_Page_Checkout::$_initialized = true;
495
-                return;
496
-            }
497
-            // lock the transaction
498
-            $this->checkout->transaction->lock();
499
-            // make sure all of our cached objects are added to their respective model entity mappers
500
-            $this->checkout->refresh_all_entities();
501
-            // set amount owing
502
-            $this->checkout->amount_owing = $this->checkout->transaction->remaining();
503
-            // initialize each reg step, which gives them the chance to potentially alter the process
504
-            $this->_initialize_reg_steps();
505
-            // DEBUG LOG
506
-            //$this->checkout->log( __CLASS__, __FUNCTION__, __LINE__ );
507
-            // get reg form
508
-            if( ! $this->_check_form_submission()) {
509
-                EED_Single_Page_Checkout::$_initialized = true;
510
-                return;
511
-            }
512
-            // checkout the action!!!
513
-            $this->_process_form_action();
514
-            // add some style and make it dance
515
-            $this->add_styles_and_scripts();
516
-            // kk... SPCO has successfully run
517
-            EED_Single_Page_Checkout::$_initialized = true;
518
-            // set no cache headers and constants
519
-            EE_System::do_not_cache();
520
-            // add anchor
521
-            add_action('loop_start', array($this, 'set_checkout_anchor'), 1);
522
-            // remove transaction lock
523
-            add_action('shutdown', array($this, 'unlock_transaction'), 1);
524
-        } catch (Exception $e) {
525
-            EE_Error::add_error($e->getMessage(), __FILE__, __FUNCTION__, __LINE__);
526
-        }
527
-    }
528
-
529
-
530
-
531
-    /**
532
-     *    _verify_session
533
-     * checks that the session is valid and not expired
534
-     *
535
-     * @access    private
536
-     * @throws EE_Error
537
-     */
538
-    private function _verify_session()
539
-    {
540
-        if ( ! EE_Registry::instance()->SSN instanceof EE_Session) {
541
-            throw new EE_Error(__('The EE_Session class could not be loaded.', 'event_espresso'));
542
-        }
543
-        $clear_session_requested = filter_var(
544
-            EE_Registry::instance()->REQ->get('clear_session', false),
545
-            FILTER_VALIDATE_BOOLEAN
546
-        );
547
-        // is session still valid ?
548
-        if ($clear_session_requested
549
-            || ( EE_Registry::instance()->SSN->expired()
550
-              && EE_Registry::instance()->REQ->get('e_reg_url_link', '') === ''
551
-            )
552
-        ) {
553
-            $this->checkout = new EE_Checkout();
554
-            EE_Registry::instance()->SSN->clear_session(__CLASS__, __FUNCTION__);
555
-            // EE_Registry::instance()->SSN->reset_cart();
556
-            // EE_Registry::instance()->SSN->reset_checkout();
557
-            // EE_Registry::instance()->SSN->reset_transaction();
558
-            if (! $clear_session_requested) {
559
-                EE_Error::add_attention(
560
-                    EE_Registry::$i18n_js_strings['registration_expiration_notice'],
561
-                    __FILE__, __FUNCTION__, __LINE__
562
-                );
563
-            }
564
-            // EE_Registry::instance()->SSN->reset_expired();
565
-        }
566
-    }
567
-
568
-
569
-
570
-    /**
571
-     *    _initialize_checkout
572
-     * loads and instantiates EE_Checkout
573
-     *
574
-     * @access    private
575
-     * @throws EE_Error
576
-     * @return EE_Checkout
577
-     */
578
-    private function _initialize_checkout()
579
-    {
580
-        // look in session for existing checkout
581
-        /** @type EE_Checkout $checkout */
582
-        $checkout = EE_Registry::instance()->SSN->checkout();
583
-        // verify
584
-        if ( ! $checkout instanceof EE_Checkout) {
585
-            // instantiate EE_Checkout object for handling the properties of the current checkout process
586
-            $checkout = EE_Registry::instance()->load_file(
587
-                SPCO_INC_PATH,
588
-                'EE_Checkout',
589
-                'class', array(),
590
-                false
591
-            );
592
-        } else {
593
-            if ($checkout->current_step->is_final_step() && $checkout->exit_spco() === true) {
594
-                $this->unlock_transaction();
595
-                wp_safe_redirect($checkout->redirect_url);
596
-                exit();
597
-            }
598
-        }
599
-        $checkout = apply_filters('FHEE__EED_Single_Page_Checkout___initialize_checkout__checkout', $checkout);
600
-        // verify again
601
-        if ( ! $checkout instanceof EE_Checkout) {
602
-            throw new EE_Error(__('The EE_Checkout class could not be loaded.', 'event_espresso'));
603
-        }
604
-        // reset anything that needs a clean slate for each request
605
-        $checkout->reset_for_current_request();
606
-        return $checkout;
607
-    }
608
-
609
-
610
-
611
-    /**
612
-     *    _get_request_vars
613
-     *
614
-     * @access    private
615
-     * @return    void
616
-     * @throws EE_Error
617
-     */
618
-    private function _get_request_vars()
619
-    {
620
-        // load classes
621
-        EED_Single_Page_Checkout::load_request_handler();
622
-        //make sure this request is marked as belonging to EE
623
-        EE_Registry::instance()->REQ->set_espresso_page(true);
624
-        // which step is being requested ?
625
-        $this->checkout->step = EE_Registry::instance()->REQ->get('step', $this->_get_first_step());
626
-        // which step is being edited ?
627
-        $this->checkout->edit_step = EE_Registry::instance()->REQ->get('edit_step', '');
628
-        // and what we're doing on the current step
629
-        $this->checkout->action = EE_Registry::instance()->REQ->get('action', 'display_spco_reg_step');
630
-        // timestamp
631
-        $this->checkout->uts = EE_Registry::instance()->REQ->get('uts', 0);
632
-        // returning to edit ?
633
-        $this->checkout->reg_url_link = EE_Registry::instance()->REQ->get('e_reg_url_link', '');
634
-        // add reg url link to registration query params
635
-        if ($this->checkout->reg_url_link && strpos($this->checkout->reg_url_link, '1-') !== 0) {
636
-            $this->checkout->reg_cache_where_params[0]['REG_url_link'] = $this->checkout->reg_url_link;
637
-        }
638
-        // or some other kind of revisit ?
639
-        $this->checkout->revisit = filter_var(
640
-            EE_Registry::instance()->REQ->get('revisit', false),
641
-            FILTER_VALIDATE_BOOLEAN
642
-        );
643
-        // and whether or not to generate a reg form for this request
644
-        $this->checkout->generate_reg_form = filter_var(
645
-            EE_Registry::instance()->REQ->get('generate_reg_form', true),
646
-            FILTER_VALIDATE_BOOLEAN
647
-        );
648
-        // and whether or not to process a reg form submission for this request
649
-        $this->checkout->process_form_submission = filter_var(
650
-            EE_Registry::instance()->REQ->get(
651
-                'process_form_submission',
652
-                $this->checkout->action === 'process_reg_step'
653
-            ),
654
-            FILTER_VALIDATE_BOOLEAN
655
-        );
656
-        $this->checkout->process_form_submission = filter_var(
657
-            $this->checkout->action !== 'display_spco_reg_step'
658
-                ? $this->checkout->process_form_submission
659
-                : false,
660
-            FILTER_VALIDATE_BOOLEAN
661
-        );
662
-        // $this->_display_request_vars();
663
-    }
664
-
665
-
666
-
667
-    /**
668
-     *  _display_request_vars
669
-     *
670
-     * @access    protected
671
-     * @return    void
672
-     */
673
-    protected function _display_request_vars()
674
-    {
675
-        if ( ! WP_DEBUG) {
676
-            return;
677
-        }
678
-        EEH_Debug_Tools::printr($_REQUEST, '$_REQUEST', __FILE__, __LINE__);
679
-        EEH_Debug_Tools::printr($this->checkout->step, '$this->checkout->step', __FILE__, __LINE__);
680
-        EEH_Debug_Tools::printr($this->checkout->edit_step, '$this->checkout->edit_step', __FILE__, __LINE__);
681
-        EEH_Debug_Tools::printr($this->checkout->action, '$this->checkout->action', __FILE__, __LINE__);
682
-        EEH_Debug_Tools::printr($this->checkout->reg_url_link, '$this->checkout->reg_url_link', __FILE__, __LINE__);
683
-        EEH_Debug_Tools::printr($this->checkout->revisit, '$this->checkout->revisit', __FILE__, __LINE__);
684
-        EEH_Debug_Tools::printr($this->checkout->generate_reg_form, '$this->checkout->generate_reg_form', __FILE__, __LINE__);
685
-        EEH_Debug_Tools::printr($this->checkout->process_form_submission, '$this->checkout->process_form_submission', __FILE__, __LINE__);
686
-    }
687
-
688
-
689
-
690
-    /**
691
-     * _block_bots
692
-     * checks that the incoming request has either of the following set:
693
-     *  a uts (unix timestamp) which indicates that the request was redirected from the Ticket Selector
694
-     *  a REG URL Link, which indicates that the request is a return visit to SPCO for a valid TXN
695
-     * so if you're not coming from the Ticket Selector nor returning for a valid IP...
696
-     * then where you coming from man?
697
-     *
698
-     * @return boolean
699
-     */
700
-    private function _block_bots()
701
-    {
702
-        $invalid_checkout_access = EED_Invalid_Checkout_Access::getInvalidCheckoutAccess();
703
-        if ($invalid_checkout_access->checkoutAccessIsInvalid($this->checkout)) {
704
-            return true;
705
-        }
706
-        return false;
707
-    }
708
-
709
-
710
-
711
-    /**
712
-     *    _get_first_step
713
-     *  gets slug for first step in $_reg_steps_array
714
-     *
715
-     * @access    private
716
-     * @throws EE_Error
717
-     * @return    string
718
-     */
719
-    private function _get_first_step()
720
-    {
721
-        $first_step = reset(EED_Single_Page_Checkout::$_reg_steps_array);
722
-        return isset($first_step['slug']) ? $first_step['slug'] : 'attendee_information';
723
-    }
724
-
725
-
726
-
727
-    /**
728
-     *    _load_and_instantiate_reg_steps
729
-     *  instantiates each reg step based on the loaded reg_steps array
730
-     *
731
-     * @access    private
732
-     * @throws EE_Error
733
-     * @return    bool
734
-     */
735
-    private function _load_and_instantiate_reg_steps()
736
-    {
737
-        do_action('AHEE__Single_Page_Checkout___load_and_instantiate_reg_steps__start', $this->checkout);
738
-        // have reg_steps already been instantiated ?
739
-        if (
740
-            empty($this->checkout->reg_steps)
741
-            || apply_filters('FHEE__Single_Page_Checkout__load_reg_steps__reload_reg_steps', false, $this->checkout)
742
-        ) {
743
-            // if not, then loop through raw reg steps array
744
-            foreach (EED_Single_Page_Checkout::$_reg_steps_array as $order => $reg_step) {
745
-                if ( ! $this->_load_and_instantiate_reg_step($reg_step, $order)) {
746
-                    return false;
747
-                }
748
-            }
749
-            EE_Registry::instance()->CFG->registration->skip_reg_confirmation = true;
750
-            EE_Registry::instance()->CFG->registration->reg_confirmation_last = true;
751
-            // skip the registration_confirmation page ?
752
-            if (EE_Registry::instance()->CFG->registration->skip_reg_confirmation) {
753
-                // just remove it from the reg steps array
754
-                $this->checkout->remove_reg_step('registration_confirmation', false);
755
-            } else if (
756
-                isset($this->checkout->reg_steps['registration_confirmation'])
757
-                && EE_Registry::instance()->CFG->registration->reg_confirmation_last
758
-            ) {
759
-                // set the order to something big like 100
760
-                $this->checkout->set_reg_step_order('registration_confirmation', 100);
761
-            }
762
-            // filter the array for good luck
763
-            $this->checkout->reg_steps = apply_filters(
764
-                'FHEE__Single_Page_Checkout__load_reg_steps__reg_steps',
765
-                $this->checkout->reg_steps
766
-            );
767
-            // finally re-sort based on the reg step class order properties
768
-            $this->checkout->sort_reg_steps();
769
-        } else {
770
-            foreach ($this->checkout->reg_steps as $reg_step) {
771
-                // set all current step stati to FALSE
772
-                $reg_step->set_is_current_step(false);
773
-            }
774
-        }
775
-        if (empty($this->checkout->reg_steps)) {
776
-            EE_Error::add_error(
777
-                __('No Reg Steps were loaded..', 'event_espresso'),
778
-                __FILE__, __FUNCTION__, __LINE__
779
-            );
780
-            return false;
781
-        }
782
-        // make reg step details available to JS
783
-        $this->checkout->set_reg_step_JSON_info();
784
-        return true;
785
-    }
786
-
787
-
788
-
789
-    /**
790
-     *     _load_and_instantiate_reg_step
791
-     *
792
-     * @access    private
793
-     * @param array $reg_step
794
-     * @param int   $order
795
-     * @return bool
796
-     */
797
-    private function _load_and_instantiate_reg_step($reg_step = array(), $order = 0)
798
-    {
799
-        // we need a file_path, class_name, and slug to add a reg step
800
-        if (isset($reg_step['file_path'], $reg_step['class_name'], $reg_step['slug'])) {
801
-            // if editing a specific step, but this is NOT that step... (and it's not the 'finalize_registration' step)
802
-            if (
803
-                $this->checkout->reg_url_link
804
-                && $this->checkout->step !== $reg_step['slug']
805
-                && $reg_step['slug'] !== 'finalize_registration'
806
-                // normally at this point we would NOT load the reg step, but this filter can change that
807
-                && apply_filters(
808
-                    'FHEE__Single_Page_Checkout___load_and_instantiate_reg_step__bypass_reg_step',
809
-                    true,
810
-                    $reg_step,
811
-                    $this->checkout
812
-                )
813
-            ) {
814
-                return true;
815
-            }
816
-            // instantiate step class using file path and class name
817
-            $reg_step_obj = EE_Registry::instance()->load_file(
818
-                $reg_step['file_path'],
819
-                $reg_step['class_name'],
820
-                'class',
821
-                $this->checkout,
822
-                false
823
-            );
824
-            // did we gets the goods ?
825
-            if ($reg_step_obj instanceof EE_SPCO_Reg_Step) {
826
-                // set reg step order based on config
827
-                $reg_step_obj->set_order($order);
828
-                // add instantiated reg step object to the master reg steps array
829
-                $this->checkout->add_reg_step($reg_step_obj);
830
-            } else {
831
-                EE_Error::add_error(
832
-                    __('The current step could not be set.', 'event_espresso'),
833
-                    __FILE__, __FUNCTION__, __LINE__
834
-                );
835
-                return false;
836
-            }
837
-        } else {
838
-            if (WP_DEBUG) {
839
-                EE_Error::add_error(
840
-                    sprintf(
841
-                        __(
842
-                            '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',
843
-                            'event_espresso'
844
-                        ),
845
-                        isset($reg_step['file_path']) ? $reg_step['file_path'] : '',
846
-                        isset($reg_step['class_name']) ? $reg_step['class_name'] : '',
847
-                        isset($reg_step['slug']) ? $reg_step['slug'] : '',
848
-                        '<ul>',
849
-                        '<li>',
850
-                        '</li>',
851
-                        '</ul>'
852
-                    ),
853
-                    __FILE__, __FUNCTION__, __LINE__
854
-                );
855
-            }
856
-            return false;
857
-        }
858
-        return true;
859
-    }
860
-
861
-
862
-    /**
863
-     * _verify_transaction_and_get_registrations
864
-     *
865
-     * @access private
866
-     * @return bool
867
-     * @throws InvalidDataTypeException
868
-     * @throws InvalidEntityException
869
-     * @throws EE_Error
870
-     */
871
-    private function _verify_transaction_and_get_registrations()
872
-    {
873
-        // was there already a valid transaction in the checkout from the session ?
874
-        if ( ! $this->checkout->transaction instanceof EE_Transaction) {
875
-            // get transaction from db or session
876
-            $this->checkout->transaction = $this->checkout->reg_url_link && ! is_admin()
877
-                ? $this->_get_transaction_and_cart_for_previous_visit()
878
-                : $this->_get_cart_for_current_session_and_setup_new_transaction();
879
-            if ( ! $this->checkout->transaction instanceof EE_Transaction) {
880
-                EE_Error::add_error(
881
-                    __('Your Registration and Transaction information could not be retrieved from the db.',
882
-                        'event_espresso'),
883
-                    __FILE__, __FUNCTION__, __LINE__
884
-                );
885
-                $this->checkout->transaction = EE_Transaction::new_instance();
886
-                // add some style and make it dance
887
-                $this->add_styles_and_scripts();
888
-                EED_Single_Page_Checkout::$_initialized = true;
889
-                return false;
890
-            }
891
-            // and the registrations for the transaction
892
-            $this->_get_registrations($this->checkout->transaction);
893
-        }
894
-        return true;
895
-    }
896
-
897
-
898
-
899
-    /**
900
-     * _get_transaction_and_cart_for_previous_visit
901
-     *
902
-     * @access private
903
-     * @return mixed EE_Transaction|NULL
904
-     */
905
-    private function _get_transaction_and_cart_for_previous_visit()
906
-    {
907
-        /** @var $TXN_model EEM_Transaction */
908
-        $TXN_model = EE_Registry::instance()->load_model('Transaction');
909
-        // because the reg_url_link is present in the request,
910
-        // this is a return visit to SPCO, so we'll get the transaction data from the db
911
-        $transaction = $TXN_model->get_transaction_from_reg_url_link($this->checkout->reg_url_link);
912
-        // verify transaction
913
-        if ($transaction instanceof EE_Transaction) {
914
-            // and get the cart that was used for that transaction
915
-            $this->checkout->cart = $this->_get_cart_for_transaction($transaction);
916
-            return $transaction;
917
-        }
918
-        EE_Error::add_error(
919
-            __('Your Registration and Transaction information could not be retrieved from the db.', 'event_espresso'),
920
-            __FILE__, __FUNCTION__, __LINE__
921
-        );
922
-        return null;
923
-
924
-    }
925
-
926
-
927
-
928
-    /**
929
-     * _get_cart_for_transaction
930
-     *
931
-     * @access private
932
-     * @param EE_Transaction $transaction
933
-     * @return EE_Cart
934
-     */
935
-    private function _get_cart_for_transaction($transaction)
936
-    {
937
-        return $this->checkout->get_cart_for_transaction($transaction);
938
-    }
939
-
940
-
941
-
942
-    /**
943
-     * get_cart_for_transaction
944
-     *
945
-     * @access public
946
-     * @param EE_Transaction $transaction
947
-     * @return EE_Cart
948
-     */
949
-    public function get_cart_for_transaction(EE_Transaction $transaction)
950
-    {
951
-        return $this->checkout->get_cart_for_transaction($transaction);
952
-    }
953
-
954
-
955
-
956
-    /**
957
-     * _get_transaction_and_cart_for_current_session
958
-     *    generates a new EE_Transaction object and adds it to the $_transaction property.
959
-     *
960
-     * @access private
961
-     * @return EE_Transaction
962
-     * @throws EE_Error
963
-     */
964
-    private function _get_cart_for_current_session_and_setup_new_transaction()
965
-    {
966
-        //  if there's no transaction, then this is the FIRST visit to SPCO
967
-        // so load up the cart ( passing nothing for the TXN because it doesn't exist yet )
968
-        $this->checkout->cart = $this->_get_cart_for_transaction(null);
969
-        // and then create a new transaction
970
-        $transaction = $this->_initialize_transaction();
971
-        // verify transaction
972
-        if ($transaction instanceof EE_Transaction) {
973
-            // save it so that we have an ID for other objects to use
974
-            $transaction->save();
975
-            // and save TXN data to the cart
976
-            $this->checkout->cart->get_grand_total()->save_this_and_descendants_to_txn($transaction->ID());
977
-        } else {
978
-            EE_Error::add_error(
979
-                __('A Valid Transaction could not be initialized.', 'event_espresso'),
980
-                __FILE__, __FUNCTION__, __LINE__
981
-            );
982
-        }
983
-        return $transaction;
984
-    }
985
-
986
-
987
-
988
-    /**
989
-     *    generates a new EE_Transaction object and adds it to the $_transaction property.
990
-     *
991
-     * @access private
992
-     * @return mixed EE_Transaction|NULL
993
-     */
994
-    private function _initialize_transaction()
995
-    {
996
-        try {
997
-            // ensure cart totals have been calculated
998
-            $this->checkout->cart->get_grand_total()->recalculate_total_including_taxes();
999
-            // grab the cart grand total
1000
-            $cart_total = $this->checkout->cart->get_cart_grand_total();
1001
-            // create new TXN
1002
-            $transaction = EE_Transaction::new_instance(
1003
-                array(
1004
-                    'TXN_reg_steps' => $this->checkout->initialize_txn_reg_steps_array(),
1005
-                    'TXN_total'     => $cart_total > 0 ? $cart_total : 0,
1006
-                    'TXN_paid'      => 0,
1007
-                    'STS_ID'        => EEM_Transaction::failed_status_code,
1008
-                )
1009
-            );
1010
-            // save it so that we have an ID for other objects to use
1011
-            $transaction->save();
1012
-            // set cron job for following up on TXNs after their session has expired
1013
-            EE_Cron_Tasks::schedule_expired_transaction_check(
1014
-                EE_Registry::instance()->SSN->expiration() + 1,
1015
-                $transaction->ID()
1016
-            );
1017
-            return $transaction;
1018
-        } catch (Exception $e) {
1019
-            EE_Error::add_error($e->getMessage(), __FILE__, __FUNCTION__, __LINE__);
1020
-        }
1021
-        return null;
1022
-    }
1023
-
1024
-
1025
-    /**
1026
-     * _get_registrations
1027
-     *
1028
-     * @access private
1029
-     * @param EE_Transaction $transaction
1030
-     * @return void
1031
-     * @throws InvalidDataTypeException
1032
-     * @throws InvalidEntityException
1033
-     * @throws EE_Error
1034
-     */
1035
-    private function _get_registrations(EE_Transaction $transaction)
1036
-    {
1037
-        // first step: grab the registrants  { : o
1038
-        $registrations = $transaction->registrations($this->checkout->reg_cache_where_params, false);
1039
-        $this->checkout->total_ticket_count = count($registrations);
1040
-        // verify registrations have been set
1041
-        if (empty($registrations)) {
1042
-            // if no cached registrations, then check the db
1043
-            $registrations = $transaction->registrations($this->checkout->reg_cache_where_params, false);
1044
-            // still nothing ? well as long as this isn't a revisit
1045
-            if (empty($registrations) && ! $this->checkout->revisit) {
1046
-                // generate new registrations from scratch
1047
-                $registrations = $this->_initialize_registrations($transaction);
1048
-            }
1049
-        }
1050
-        // sort by their original registration order
1051
-        usort($registrations, array('EED_Single_Page_Checkout', 'sort_registrations_by_REG_count'));
1052
-        // then loop thru the array
1053
-        foreach ($registrations as $registration) {
1054
-            // verify each registration
1055
-            if ($registration instanceof EE_Registration) {
1056
-                // we display all attendee info for the primary registrant
1057
-                if ($this->checkout->reg_url_link === $registration->reg_url_link()
1058
-                    && $registration->is_primary_registrant()
1059
-                ) {
1060
-                    $this->checkout->primary_revisit = true;
1061
-                    break;
1062
-                }
1063
-                if ($this->checkout->revisit && $this->checkout->reg_url_link !== $registration->reg_url_link()) {
1064
-                    // but hide info if it doesn't belong to you
1065
-                    $transaction->clear_cache('Registration', $registration->ID());
1066
-                    $this->checkout->total_ticket_count--;
1067
-                }
1068
-                $this->checkout->set_reg_status_updated($registration->ID(), false);
1069
-            }
1070
-        }
1071
-    }
1072
-
1073
-
1074
-    /**
1075
-     *    adds related EE_Registration objects for each ticket in the cart to the current EE_Transaction object
1076
-     *
1077
-     * @access private
1078
-     * @param EE_Transaction $transaction
1079
-     * @return    array
1080
-     * @throws InvalidDataTypeException
1081
-     * @throws InvalidEntityException
1082
-     * @throws EE_Error
1083
-     */
1084
-    private function _initialize_registrations(EE_Transaction $transaction)
1085
-    {
1086
-        $att_nmbr = 0;
1087
-        $registrations = array();
1088
-        if ($transaction instanceof EE_Transaction) {
1089
-            /** @type EE_Registration_Processor $registration_processor */
1090
-            $registration_processor = EE_Registry::instance()->load_class('Registration_Processor');
1091
-            $this->checkout->total_ticket_count = $this->checkout->cart->all_ticket_quantity_count();
1092
-            // now let's add the cart items to the $transaction
1093
-            foreach ($this->checkout->cart->get_tickets() as $line_item) {
1094
-                //do the following for each ticket of this type they selected
1095
-                for ($x = 1; $x <= $line_item->quantity(); $x++) {
1096
-                    $att_nmbr++;
1097
-                    /** @var EventEspresso\core\services\commands\registration\CreateRegistrationCommand $CreateRegistrationCommand */
1098
-                    $CreateRegistrationCommand = EE_Registry::instance()->create(
1099
-                        'EventEspresso\core\services\commands\registration\CreateRegistrationCommand',
1100
-                        array(
1101
-                            $transaction,
1102
-                            $line_item,
1103
-                            $att_nmbr,
1104
-                            $this->checkout->total_ticket_count,
1105
-                        )
1106
-                    );
1107
-                    // override capabilities for frontend registrations
1108
-                    if ( ! is_admin()) {
1109
-                        $CreateRegistrationCommand->setCapCheck(
1110
-                            new PublicCapabilities('', 'create_new_registration')
1111
-                        );
1112
-                    }
1113
-                    $registration = EE_Registry::instance()->BUS->execute($CreateRegistrationCommand);
1114
-                    if ( ! $registration instanceof EE_Registration) {
1115
-                        throw new InvalidEntityException($registration, 'EE_Registration');
1116
-                    }
1117
-                    $registrations[ $registration->ID() ] = $registration;
1118
-                }
1119
-            }
1120
-            $registration_processor->fix_reg_final_price_rounding_issue($transaction);
1121
-        }
1122
-        return $registrations;
1123
-    }
1124
-
1125
-
1126
-
1127
-    /**
1128
-     * sorts registrations by REG_count
1129
-     *
1130
-     * @access public
1131
-     * @param EE_Registration $reg_A
1132
-     * @param EE_Registration $reg_B
1133
-     * @return int
1134
-     */
1135
-    public static function sort_registrations_by_REG_count(EE_Registration $reg_A, EE_Registration $reg_B)
1136
-    {
1137
-        // this shouldn't ever happen within the same TXN, but oh well
1138
-        if ($reg_A->count() === $reg_B->count()) {
1139
-            return 0;
1140
-        }
1141
-        return ($reg_A->count() > $reg_B->count()) ? 1 : -1;
1142
-    }
1143
-
1144
-
1145
-
1146
-    /**
1147
-     *    _final_verifications
1148
-     * just makes sure that everything is set up correctly before proceeding
1149
-     *
1150
-     * @access    private
1151
-     * @return    bool
1152
-     * @throws EE_Error
1153
-     */
1154
-    private function _final_verifications()
1155
-    {
1156
-        // filter checkout
1157
-        $this->checkout = apply_filters(
1158
-            'FHEE__EED_Single_Page_Checkout___final_verifications__checkout',
1159
-            $this->checkout
1160
-        );
1161
-        //verify that current step is still set correctly
1162
-        if ( ! $this->checkout->current_step instanceof EE_SPCO_Reg_Step) {
1163
-            EE_Error::add_error(
1164
-                __('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'),
1165
-                __FILE__,
1166
-                __FUNCTION__,
1167
-                __LINE__
1168
-            );
1169
-            return false;
1170
-        }
1171
-        // if returning to SPCO, then verify that primary registrant is set
1172
-        if ( ! empty($this->checkout->reg_url_link)) {
1173
-            $valid_registrant = $this->checkout->transaction->primary_registration();
1174
-            if ( ! $valid_registrant instanceof EE_Registration) {
1175
-                EE_Error::add_error(
1176
-                    __('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'),
1177
-                    __FILE__,
1178
-                    __FUNCTION__,
1179
-                    __LINE__
1180
-                );
1181
-                return false;
1182
-            }
1183
-            $valid_registrant = null;
1184
-            foreach (
1185
-                $this->checkout->transaction->registrations($this->checkout->reg_cache_where_params) as $registration
1186
-            ) {
1187
-                if (
1188
-                    $registration instanceof EE_Registration
1189
-                    && $registration->reg_url_link() === $this->checkout->reg_url_link
1190
-                ) {
1191
-                    $valid_registrant = $registration;
1192
-                }
1193
-            }
1194
-            if ( ! $valid_registrant instanceof EE_Registration) {
1195
-                // hmmm... maybe we have the wrong session because the user is opening multiple tabs ?
1196
-                if (EED_Single_Page_Checkout::$_checkout_verified) {
1197
-                    // clear the session, mark the checkout as unverified, and try again
1198
-                    EE_Registry::instance()->SSN->clear_session(__CLASS__, __FUNCTION__);
1199
-                    EED_Single_Page_Checkout::$_initialized = false;
1200
-                    EED_Single_Page_Checkout::$_checkout_verified = false;
1201
-                    $this->_initialize();
1202
-                    EE_Error::reset_notices();
1203
-                    return false;
1204
-                }
1205
-                EE_Error::add_error(
1206
-                    __(
1207
-                        '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.',
1208
-                        'event_espresso'
1209
-                    ),
1210
-                    __FILE__,
1211
-                    __FUNCTION__,
1212
-                    __LINE__
1213
-                );
1214
-                return false;
1215
-            }
1216
-        }
1217
-        // now that things have been kinda sufficiently verified,
1218
-        // let's add the checkout to the session so that it's available to other systems
1219
-        EE_Registry::instance()->SSN->set_checkout($this->checkout);
1220
-        return true;
1221
-    }
1222
-
1223
-
1224
-
1225
-    /**
1226
-     *    _initialize_reg_steps
1227
-     * first makes sure that EE_Transaction_Processor::set_reg_step_initiated() is called as required
1228
-     * then loops thru all of the active reg steps and calls the initialize_reg_step() method
1229
-     *
1230
-     * @access    private
1231
-     * @param bool $reinitializing
1232
-     * @throws EE_Error
1233
-     */
1234
-    private function _initialize_reg_steps($reinitializing = false)
1235
-    {
1236
-        $this->checkout->set_reg_step_initiated($this->checkout->current_step);
1237
-        // loop thru all steps to call their individual "initialize" methods and set i18n strings for JS
1238
-        foreach ($this->checkout->reg_steps as $reg_step) {
1239
-            if ( ! $reg_step->initialize_reg_step()) {
1240
-                // if not initialized then maybe this step is being removed...
1241
-                if ( ! $reinitializing && $reg_step->is_current_step()) {
1242
-                    // if it was the current step, then we need to start over here
1243
-                    $this->_initialize_reg_steps(true);
1244
-                    return;
1245
-                }
1246
-                continue;
1247
-            }
1248
-            // add css and JS for current step
1249
-            $reg_step->enqueue_styles_and_scripts();
1250
-            // i18n
1251
-            $reg_step->translate_js_strings();
1252
-            if ($reg_step->is_current_step()) {
1253
-                // the text that appears on the reg step form submit button
1254
-                $reg_step->set_submit_button_text();
1255
-            }
1256
-        }
1257
-        // dynamically creates hook point like: AHEE__Single_Page_Checkout___initialize_reg_step__attendee_information
1258
-        do_action(
1259
-            "AHEE__Single_Page_Checkout___initialize_reg_step__{$this->checkout->current_step->slug()}",
1260
-            $this->checkout->current_step
1261
-        );
1262
-    }
1263
-
1264
-
1265
-
1266
-    /**
1267
-     * _check_form_submission
1268
-     *
1269
-     * @access private
1270
-     * @return boolean
1271
-     */
1272
-    private function _check_form_submission()
1273
-    {
1274
-        //does this request require the reg form to be generated ?
1275
-        if ($this->checkout->generate_reg_form) {
1276
-            // ever heard that song by Blue Rodeo ?
1277
-            try {
1278
-                $this->checkout->current_step->reg_form = $this->checkout->current_step->generate_reg_form();
1279
-                // if not displaying a form, then check for form submission
1280
-                if (
1281
-                    $this->checkout->process_form_submission
1282
-                    && $this->checkout->current_step->reg_form->was_submitted()
1283
-                ) {
1284
-                    // clear out any old data in case this step is being run again
1285
-                    $this->checkout->current_step->set_valid_data(array());
1286
-                    // capture submitted form data
1287
-                    $this->checkout->current_step->reg_form->receive_form_submission(
1288
-                        apply_filters(
1289
-                            'FHEE__Single_Page_Checkout___check_form_submission__request_params',
1290
-                            EE_Registry::instance()->REQ->params(),
1291
-                            $this->checkout
1292
-                        )
1293
-                    );
1294
-                    // validate submitted form data
1295
-                    if ( ! $this->checkout->continue_reg || ! $this->checkout->current_step->reg_form->is_valid()) {
1296
-                        // thou shall not pass !!!
1297
-                        $this->checkout->continue_reg = false;
1298
-                        // any form validation errors?
1299
-                        if ($this->checkout->current_step->reg_form->submission_error_message() !== '') {
1300
-                            EE_Error::add_error(
1301
-                                $this->checkout->current_step->reg_form->submission_error_message(),
1302
-                                __FILE__, __FUNCTION__, __LINE__
1303
-                            );
1304
-                        }
1305
-                        // well not really... what will happen is
1306
-                        // we'll just get redirected back to redo the current step
1307
-                        $this->go_to_next_step();
1308
-                        return false;
1309
-                    }
1310
-                }
1311
-            } catch (EE_Error $e) {
1312
-                $e->get_error();
1313
-            }
1314
-        }
1315
-        return true;
1316
-    }
1317
-
1318
-
1319
-
1320
-    /**
1321
-     * _process_action
1322
-     *
1323
-     * @access private
1324
-     * @return void
1325
-     * @throws EE_Error
1326
-     */
1327
-    private function _process_form_action()
1328
-    {
1329
-        // what cha wanna do?
1330
-        switch ($this->checkout->action) {
1331
-            // AJAX next step reg form
1332
-            case 'display_spco_reg_step' :
1333
-                $this->checkout->redirect = false;
1334
-                if (EE_Registry::instance()->REQ->ajax) {
1335
-                    $this->checkout->json_response->set_reg_step_html(
1336
-                        $this->checkout->current_step->display_reg_form()
1337
-                    );
1338
-                }
1339
-                break;
1340
-            default :
1341
-                // meh... do one of those other steps first
1342
-                if (
1343
-                    ! empty($this->checkout->action)
1344
-                    && is_callable(array($this->checkout->current_step, $this->checkout->action))
1345
-                ) {
1346
-                    // dynamically creates hook point like:
1347
-                    //   AHEE__Single_Page_Checkout__before_attendee_information__process_reg_step
1348
-                    do_action(
1349
-                        "AHEE__Single_Page_Checkout__before_{$this->checkout->current_step->slug()}__{$this->checkout->action}",
1350
-                        $this->checkout->current_step
1351
-                    );
1352
-                    // call action on current step
1353
-                    if (call_user_func(array($this->checkout->current_step, $this->checkout->action))) {
1354
-                        // good registrant, you get to proceed
1355
-                        if (
1356
-                            $this->checkout->current_step->success_message() !== ''
1357
-                            && apply_filters(
1358
-                                'FHEE__Single_Page_Checkout___process_form_action__display_success',
1359
-                                false
1360
-                            )
1361
-                        ) {
1362
-                            EE_Error::add_success(
1363
-                                $this->checkout->current_step->success_message()
1364
-                                . '<br />' . $this->checkout->next_step->_instructions()
1365
-                            );
1366
-                        }
1367
-                        // pack it up, pack it in...
1368
-                        $this->_setup_redirect();
1369
-                    }
1370
-                    // dynamically creates hook point like:
1371
-                    //  AHEE__Single_Page_Checkout__after_payment_options__process_reg_step
1372
-                    do_action(
1373
-                        "AHEE__Single_Page_Checkout__after_{$this->checkout->current_step->slug()}__{$this->checkout->action}",
1374
-                        $this->checkout->current_step
1375
-                    );
1376
-                } else {
1377
-                    EE_Error::add_error(
1378
-                        sprintf(
1379
-                            __(
1380
-                                'The requested form action "%s" does not exist for the current "%s" registration step.',
1381
-                                'event_espresso'
1382
-                            ),
1383
-                            $this->checkout->action,
1384
-                            $this->checkout->current_step->name()
1385
-                        ),
1386
-                        __FILE__,
1387
-                        __FUNCTION__,
1388
-                        __LINE__
1389
-                    );
1390
-                }
1391
-            // end default
1392
-        }
1393
-        // store our progress so far
1394
-        $this->checkout->stash_transaction_and_checkout();
1395
-        // advance to the next step! If you pass GO, collect $200
1396
-        $this->go_to_next_step();
1397
-    }
1398
-
1399
-
1400
-
1401
-    /**
1402
-     *        add_styles_and_scripts
1403
-     *
1404
-     * @access        public
1405
-     * @return        void
1406
-     */
1407
-    public function add_styles_and_scripts()
1408
-    {
1409
-        // i18n
1410
-        $this->translate_js_strings();
1411
-        if ($this->checkout->admin_request) {
1412
-            add_action('admin_enqueue_scripts', array($this, 'enqueue_styles_and_scripts'), 10);
1413
-        } else {
1414
-            add_action('wp_enqueue_scripts', array($this, 'enqueue_styles_and_scripts'), 10);
1415
-        }
1416
-    }
1417
-
1418
-
1419
-
1420
-    /**
1421
-     *        translate_js_strings
1422
-     *
1423
-     * @access        public
1424
-     * @return        void
1425
-     */
1426
-    public function translate_js_strings()
1427
-    {
1428
-        EE_Registry::$i18n_js_strings['revisit'] = $this->checkout->revisit;
1429
-        EE_Registry::$i18n_js_strings['e_reg_url_link'] = $this->checkout->reg_url_link;
1430
-        EE_Registry::$i18n_js_strings['server_error'] = __(
1431
-            'An unknown error occurred on the server while attempting to process your request. Please refresh the page and try again or contact support.',
1432
-            'event_espresso'
1433
-        );
1434
-        EE_Registry::$i18n_js_strings['invalid_json_response'] = __(
1435
-            'An invalid response was returned from the server while attempting to process your request. Please refresh the page and try again or contact support.',
1436
-            'event_espresso'
1437
-        );
1438
-        EE_Registry::$i18n_js_strings['validation_error'] = __(
1439
-            'There appears to be a problem with the form validation configuration! Please check the admin settings or contact support.',
1440
-            'event_espresso'
1441
-        );
1442
-        EE_Registry::$i18n_js_strings['invalid_payment_method'] = __(
1443
-            'There appears to be a problem with the payment method configuration! Please refresh the page and try again or contact support.',
1444
-            'event_espresso'
1445
-        );
1446
-        EE_Registry::$i18n_js_strings['reg_step_error'] = __(
1447
-            'This registration step could not be completed. Please refresh the page and try again.',
1448
-            'event_espresso'
1449
-        );
1450
-        EE_Registry::$i18n_js_strings['invalid_coupon'] = __(
1451
-            'We\'re sorry but that coupon code does not appear to be valid. If this is incorrect, please contact the site administrator.',
1452
-            'event_espresso'
1453
-        );
1454
-        EE_Registry::$i18n_js_strings['process_registration'] = sprintf(
1455
-            __(
1456
-                'Please wait while we process your registration.%sDo not refresh the page or navigate away while this is happening.%sThank you for your patience.',
1457
-                'event_espresso'
1458
-            ),
1459
-            '<br/>',
1460
-            '<br/>'
1461
-        );
1462
-        EE_Registry::$i18n_js_strings['language'] = get_bloginfo('language');
1463
-        EE_Registry::$i18n_js_strings['EESID'] = EE_Registry::instance()->SSN->id();
1464
-        EE_Registry::$i18n_js_strings['currency'] = EE_Registry::instance()->CFG->currency;
1465
-        EE_Registry::$i18n_js_strings['datepicker_yearRange'] = '-150:+20';
1466
-        EE_Registry::$i18n_js_strings['timer_years'] = __('years', 'event_espresso');
1467
-        EE_Registry::$i18n_js_strings['timer_months'] = __('months', 'event_espresso');
1468
-        EE_Registry::$i18n_js_strings['timer_weeks'] = __('weeks', 'event_espresso');
1469
-        EE_Registry::$i18n_js_strings['timer_days'] = __('days', 'event_espresso');
1470
-        EE_Registry::$i18n_js_strings['timer_hours'] = __('hours', 'event_espresso');
1471
-        EE_Registry::$i18n_js_strings['timer_minutes'] = __('minutes', 'event_espresso');
1472
-        EE_Registry::$i18n_js_strings['timer_seconds'] = __('seconds', 'event_espresso');
1473
-        EE_Registry::$i18n_js_strings['timer_year'] = __('year', 'event_espresso');
1474
-        EE_Registry::$i18n_js_strings['timer_month'] = __('month', 'event_espresso');
1475
-        EE_Registry::$i18n_js_strings['timer_week'] = __('week', 'event_espresso');
1476
-        EE_Registry::$i18n_js_strings['timer_day'] = __('day', 'event_espresso');
1477
-        EE_Registry::$i18n_js_strings['timer_hour'] = __('hour', 'event_espresso');
1478
-        EE_Registry::$i18n_js_strings['timer_minute'] = __('minute', 'event_espresso');
1479
-        EE_Registry::$i18n_js_strings['timer_second'] = __('second', 'event_espresso');
1480
-        EE_Registry::$i18n_js_strings['registration_expiration_notice'] = EED_Single_Page_Checkout::getRegistrationExpirationNotice();
1481
-        EE_Registry::$i18n_js_strings['ajax_submit'] = apply_filters(
1482
-            'FHEE__Single_Page_Checkout__translate_js_strings__ajax_submit',
1483
-            true
1484
-        );
1485
-        EE_Registry::$i18n_js_strings['session_extension'] = absint(
1486
-            apply_filters('FHEE__EE_Session__extend_expiration__seconds_added', 10 * MINUTE_IN_SECONDS)
1487
-        );
1488
-        EE_Registry::$i18n_js_strings['session_expiration'] = gmdate(
1489
-            'M d, Y H:i:s',
1490
-            EE_Registry::instance()->SSN->expiration() + (get_option('gmt_offset') * HOUR_IN_SECONDS)
1491
-        );
1492
-    }
1493
-
1494
-
1495
-
1496
-    /**
1497
-     *    enqueue_styles_and_scripts
1498
-     *
1499
-     * @access        public
1500
-     * @return        void
1501
-     * @throws EE_Error
1502
-     */
1503
-    public function enqueue_styles_and_scripts()
1504
-    {
1505
-        // load css
1506
-        wp_register_style(
1507
-            'single_page_checkout',
1508
-            SPCO_CSS_URL . 'single_page_checkout.css',
1509
-            array('espresso_default'),
1510
-            EVENT_ESPRESSO_VERSION
1511
-        );
1512
-        wp_enqueue_style('single_page_checkout');
1513
-        // load JS
1514
-        wp_register_script(
1515
-            'jquery_plugin',
1516
-            EE_THIRD_PARTY_URL . 'jquery	.plugin.min.js',
1517
-            array('jquery'),
1518
-            '1.0.1',
1519
-            true
1520
-        );
1521
-        wp_register_script(
1522
-            'jquery_countdown',
1523
-            EE_THIRD_PARTY_URL . 'jquery	.countdown.min.js',
1524
-            array('jquery_plugin'),
1525
-            '2.0.2',
1526
-            true
1527
-        );
1528
-        wp_register_script(
1529
-            'single_page_checkout',
1530
-            SPCO_JS_URL . 'single_page_checkout.js',
1531
-            array('espresso_core', 'underscore', 'ee_form_section_validation', 'jquery_countdown'),
1532
-            EVENT_ESPRESSO_VERSION,
1533
-            true
1534
-        );
1535
-        if ($this->checkout->registration_form instanceof EE_Form_Section_Proper) {
1536
-            $this->checkout->registration_form->enqueue_js();
1537
-        }
1538
-        if ($this->checkout->current_step->reg_form instanceof EE_Form_Section_Proper) {
1539
-            $this->checkout->current_step->reg_form->enqueue_js();
1540
-        }
1541
-        wp_enqueue_script('single_page_checkout');
1542
-        /**
1543
-         * global action hook for enqueueing styles and scripts with
1544
-         * spco calls.
1545
-         */
1546
-        do_action('AHEE__EED_Single_Page_Checkout__enqueue_styles_and_scripts', $this);
1547
-        /**
1548
-         * dynamic action hook for enqueueing styles and scripts with spco calls.
1549
-         * The hook will end up being something like:
1550
-         *      AHEE__EED_Single_Page_Checkout__enqueue_styles_and_scripts__attendee_information
1551
-         */
1552
-        do_action(
1553
-            'AHEE__EED_Single_Page_Checkout__enqueue_styles_and_scripts__' . $this->checkout->current_step->slug(),
1554
-            $this
1555
-        );
1556
-    }
1557
-
1558
-
1559
-
1560
-    /**
1561
-     *    display the Registration Single Page Checkout Form
1562
-     *
1563
-     * @access    private
1564
-     * @return    void
1565
-     * @throws EE_Error
1566
-     */
1567
-    private function _display_spco_reg_form()
1568
-    {
1569
-        // if registering via the admin, just display the reg form for the current step
1570
-        if ($this->checkout->admin_request) {
1571
-            EE_Registry::instance()->REQ->add_output($this->checkout->current_step->display_reg_form());
1572
-        } else {
1573
-            // add powered by EE msg
1574
-            add_action('AHEE__SPCO__reg_form_footer', array('EED_Single_Page_Checkout', 'display_registration_footer'));
1575
-            $empty_cart = count(
1576
-                $this->checkout->transaction->registrations($this->checkout->reg_cache_where_params)
1577
-            ) < 1;
1578
-            EE_Registry::$i18n_js_strings['empty_cart'] = $empty_cart;
1579
-            $cookies_not_set_msg = '';
1580
-            if ($empty_cart) {
1581
-                $cookies_not_set_msg = apply_filters(
1582
-                    'FHEE__Single_Page_Checkout__display_spco_reg_form__cookies_not_set_msg',
1583
-                    sprintf(
1584
-                        __(
1585
-                            '%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',
1586
-                            'event_espresso'
1587
-                        ),
1588
-                        '<div class="ee-attention hidden" id="ee-cookies-not-set-msg">',
1589
-                        '</div>',
1590
-                        '<h6 class="important-notice">',
1591
-                        '</h6>',
1592
-                        '<p>',
1593
-                        '</p>',
1594
-                        '<br />',
1595
-                        '<a href="http://www.whatarecookies.com/enable.asp" target="_blank">',
1596
-                        '</a>'
1597
-                    )
1598
-                );
1599
-            }
1600
-            $this->checkout->registration_form = new EE_Form_Section_Proper(
1601
-                array(
1602
-                    'name'            => 'single-page-checkout',
1603
-                    'html_id'         => 'ee-single-page-checkout-dv',
1604
-                    'layout_strategy' =>
1605
-                        new EE_Template_Layout(
1606
-                            array(
1607
-                                'layout_template_file' => SPCO_TEMPLATES_PATH . 'registration_page_wrapper.template.php',
1608
-                                'template_args'        => array(
1609
-                                    'empty_cart'              => $empty_cart,
1610
-                                    'revisit'                 => $this->checkout->revisit,
1611
-                                    'reg_steps'               => $this->checkout->reg_steps,
1612
-                                    'next_step'               => $this->checkout->next_step instanceof EE_SPCO_Reg_Step
1613
-                                        ? $this->checkout->next_step->slug()
1614
-                                        : '',
1615
-                                    'empty_msg'               => apply_filters(
1616
-                                        'FHEE__Single_Page_Checkout__display_spco_reg_form__empty_msg',
1617
-                                        sprintf(
1618
-                                            __(
1619
-                                                'You need to %1$sReturn to Events list%2$sselect at least one event%3$s before you can proceed with the registration process.',
1620
-                                                'event_espresso'
1621
-                                            ),
1622
-                                            '<a href="'
1623
-                                            . get_post_type_archive_link('espresso_events')
1624
-                                            . '" title="',
1625
-                                            '">',
1626
-                                            '</a>'
1627
-                                        )
1628
-                                    ),
1629
-                                    'cookies_not_set_msg'     => $cookies_not_set_msg,
1630
-                                    'registration_time_limit' => $this->checkout->get_registration_time_limit(),
1631
-                                    'session_expiration'      => gmdate(
1632
-                                        'M d, Y H:i:s',
1633
-                                        EE_Registry::instance()->SSN->expiration()
1634
-                                        + (get_option('gmt_offset') * HOUR_IN_SECONDS)
1635
-                                    ),
1636
-                                ),
1637
-                            )
1638
-                        ),
1639
-                )
1640
-            );
1641
-            // load template and add to output sent that gets filtered into the_content()
1642
-            EE_Registry::instance()->REQ->add_output($this->checkout->registration_form->get_html());
1643
-        }
1644
-    }
1645
-
1646
-
1647
-
1648
-    /**
1649
-     *    add_extra_finalize_registration_inputs
1650
-     *
1651
-     * @access    public
1652
-     * @param $next_step
1653
-     * @internal  param string $label
1654
-     * @return void
1655
-     */
1656
-    public function add_extra_finalize_registration_inputs($next_step)
1657
-    {
1658
-        if ($next_step === 'finalize_registration') {
1659
-            echo '<div id="spco-extra-finalize_registration-inputs-dv"></div>';
1660
-        }
1661
-    }
1662
-
1663
-
1664
-
1665
-    /**
1666
-     *    display_registration_footer
1667
-     *
1668
-     * @access    public
1669
-     * @return    string
1670
-     */
1671
-    public static function display_registration_footer()
1672
-    {
1673
-        if (
1674
-        apply_filters(
1675
-            'FHEE__EE_Front__Controller__show_reg_footer',
1676
-            EE_Registry::instance()->CFG->admin->show_reg_footer
1677
-        )
1678
-        ) {
1679
-            add_filter(
1680
-                'FHEE__EEH_Template__powered_by_event_espresso__url',
1681
-                function ($url) {
1682
-                    return apply_filters('FHEE__EE_Front_Controller__registration_footer__url', $url);
1683
-                }
1684
-            );
1685
-            echo apply_filters(
1686
-                'FHEE__EE_Front_Controller__display_registration_footer',
1687
-                \EEH_Template::powered_by_event_espresso(
1688
-                    '',
1689
-                    'espresso-registration-footer-dv',
1690
-                    array('utm_content' => 'registration_checkout')
1691
-                )
1692
-            );
1693
-        }
1694
-        return '';
1695
-    }
1696
-
1697
-
1698
-
1699
-    /**
1700
-     *    unlock_transaction
1701
-     *
1702
-     * @access    public
1703
-     * @return    void
1704
-     * @throws EE_Error
1705
-     */
1706
-    public function unlock_transaction()
1707
-    {
1708
-        if ($this->checkout->transaction instanceof EE_Transaction) {
1709
-            $this->checkout->transaction->unlock();
1710
-        }
1711
-    }
1712
-
1713
-
1714
-
1715
-    /**
1716
-     *        _setup_redirect
1717
-     *
1718
-     * @access    private
1719
-     * @return void
1720
-     */
1721
-    private function _setup_redirect()
1722
-    {
1723
-        if ($this->checkout->continue_reg && $this->checkout->next_step instanceof EE_SPCO_Reg_Step) {
1724
-            $this->checkout->redirect = true;
1725
-            if (empty($this->checkout->redirect_url)) {
1726
-                $this->checkout->redirect_url = $this->checkout->next_step->reg_step_url();
1727
-            }
1728
-            $this->checkout->redirect_url = apply_filters(
1729
-                'FHEE__EED_Single_Page_Checkout___setup_redirect__checkout_redirect_url',
1730
-                $this->checkout->redirect_url,
1731
-                $this->checkout
1732
-            );
1733
-        }
1734
-    }
1735
-
1736
-
1737
-
1738
-    /**
1739
-     *   handle ajax message responses and redirects
1740
-     *
1741
-     * @access public
1742
-     * @return void
1743
-     * @throws EE_Error
1744
-     */
1745
-    public function go_to_next_step()
1746
-    {
1747
-        if (EE_Registry::instance()->REQ->ajax) {
1748
-            // capture contents of output buffer we started earlier in the request, and insert into JSON response
1749
-            $this->checkout->json_response->set_unexpected_errors(ob_get_clean());
1750
-        }
1751
-        $this->unlock_transaction();
1752
-        // just return for these conditions
1753
-        if (
1754
-            $this->checkout->admin_request
1755
-            || $this->checkout->action === 'redirect_form'
1756
-            || $this->checkout->action === 'update_checkout'
1757
-        ) {
1758
-            return;
1759
-        }
1760
-        // AJAX response
1761
-        $this->_handle_json_response();
1762
-        // redirect to next step or the Thank You page
1763
-        $this->_handle_html_redirects();
1764
-        // hmmm... must be something wrong, so let's just display the form again !
1765
-        $this->_display_spco_reg_form();
1766
-    }
1767
-
1768
-
1769
-
1770
-    /**
1771
-     *   _handle_json_response
1772
-     *
1773
-     * @access protected
1774
-     * @return void
1775
-     */
1776
-    protected function _handle_json_response()
1777
-    {
1778
-        // if this is an ajax request
1779
-        if (EE_Registry::instance()->REQ->ajax) {
1780
-            // DEBUG LOG
1781
-            //$this->checkout->log(
1782
-            //	__CLASS__, __FUNCTION__, __LINE__,
1783
-            //	array(
1784
-            //		'json_response_redirect_url' => $this->checkout->json_response->redirect_url(),
1785
-            //		'redirect'                   => $this->checkout->redirect,
1786
-            //		'continue_reg'               => $this->checkout->continue_reg,
1787
-            //	)
1788
-            //);
1789
-            $this->checkout->json_response->set_registration_time_limit(
1790
-                $this->checkout->get_registration_time_limit()
1791
-            );
1792
-            $this->checkout->json_response->set_payment_amount($this->checkout->amount_owing);
1793
-            // just send the ajax (
1794
-            $json_response = apply_filters(
1795
-                'FHEE__EE_Single_Page_Checkout__JSON_response',
1796
-                $this->checkout->json_response
1797
-            );
1798
-            echo $json_response;
1799
-            exit();
1800
-        }
1801
-    }
1802
-
1803
-
1804
-
1805
-    /**
1806
-     *   _handle_redirects
1807
-     *
1808
-     * @access protected
1809
-     * @return void
1810
-     */
1811
-    protected function _handle_html_redirects()
1812
-    {
1813
-        // going somewhere ?
1814
-        if ($this->checkout->redirect && ! empty($this->checkout->redirect_url)) {
1815
-            // store notices in a transient
1816
-            EE_Error::get_notices(false, true, true);
1817
-            // DEBUG LOG
1818
-            //$this->checkout->log(
1819
-            //	__CLASS__, __FUNCTION__, __LINE__,
1820
-            //	array(
1821
-            //		'headers_sent' => headers_sent(),
1822
-            //		'redirect_url'     => $this->checkout->redirect_url,
1823
-            //		'headers_list'    => headers_list(),
1824
-            //	)
1825
-            //);
1826
-            wp_safe_redirect($this->checkout->redirect_url);
1827
-            exit();
1828
-        }
1829
-    }
1830
-
1831
-
1832
-
1833
-    /**
1834
-     *   set_checkout_anchor
1835
-     *
1836
-     * @access public
1837
-     * @return void
1838
-     */
1839
-    public function set_checkout_anchor()
1840
-    {
1841
-        echo '<a id="checkout" style="float: left; margin-left: -999em;"></a>';
1842
-    }
1843
-
1844
-    /**
1845
-     *    getRegistrationExpirationNotice
1846
-     *
1847
-     * @since $VID:$
1848
-     * @access    public
1849
-     * @return    string
1850
-     */
1851
-    public static function getRegistrationExpirationNotice()
1852
-    {
1853
-        return sprintf(
1854
-            __('%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 accept our apologies for any inconvenience this may have caused.%8$s',
1855
-                'event_espresso'),
1856
-            '<h4 class="important-notice">',
1857
-            '</h4>',
1858
-            '<br />',
1859
-            '<p>',
1860
-            '<a href="' . get_post_type_archive_link('espresso_events') . '" title="',
1861
-            '">',
1862
-            '</a>',
1863
-            '</p>'
1864
-        );
1865
-    }
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'] = EED_Single_Page_Checkout::getRegistrationExpirationNotice();
236
+	}
237
+
238
+
239
+
240
+	/**
241
+	 * load_reg_steps
242
+	 * loads and instantiates each reg step based on the EE_Registry::instance()->CFG->registration->reg_steps array
243
+	 *
244
+	 * @access    private
245
+	 * @throws EE_Error
246
+	 */
247
+	public static function load_reg_steps()
248
+	{
249
+		static $reg_steps_loaded = false;
250
+		if ($reg_steps_loaded) {
251
+			return;
252
+		}
253
+		// filter list of reg_steps
254
+		$reg_steps_to_load = (array)apply_filters(
255
+			'AHEE__SPCO__load_reg_steps__reg_steps_to_load',
256
+			EED_Single_Page_Checkout::get_reg_steps()
257
+		);
258
+		// sort by key (order)
259
+		ksort($reg_steps_to_load);
260
+		// loop through folders
261
+		foreach ($reg_steps_to_load as $order => $reg_step) {
262
+			// we need a
263
+			if (isset($reg_step['file_path'], $reg_step['class_name'], $reg_step['slug'])) {
264
+				// copy over to the reg_steps_array
265
+				EED_Single_Page_Checkout::$_reg_steps_array[$order] = $reg_step;
266
+				// register custom key route for each reg step
267
+				// ie: step=>"slug" - this is the entire reason we load the reg steps array now
268
+				EE_Config::register_route(
269
+					$reg_step['slug'],
270
+					'EED_Single_Page_Checkout',
271
+					'run',
272
+					'step'
273
+				);
274
+				// add AJAX or other hooks
275
+				if (isset($reg_step['has_hooks']) && $reg_step['has_hooks']) {
276
+					// setup autoloaders if necessary
277
+					if ( ! class_exists($reg_step['class_name'])) {
278
+						EEH_Autoloader::register_autoloaders_for_each_file_in_folder(
279
+							$reg_step['file_path'],
280
+							true
281
+						);
282
+					}
283
+					if (is_callable($reg_step['class_name'], 'set_hooks')) {
284
+						call_user_func(array($reg_step['class_name'], 'set_hooks'));
285
+					}
286
+				}
287
+			}
288
+		}
289
+		$reg_steps_loaded = true;
290
+	}
291
+
292
+
293
+
294
+	/**
295
+	 *    get_reg_steps
296
+	 *
297
+	 * @access    public
298
+	 * @return    array
299
+	 */
300
+	public static function get_reg_steps()
301
+	{
302
+		$reg_steps = EE_Registry::instance()->CFG->registration->reg_steps;
303
+		if (empty($reg_steps)) {
304
+			$reg_steps = array(
305
+				10  => array(
306
+					'file_path'  => SPCO_REG_STEPS_PATH . 'attendee_information',
307
+					'class_name' => 'EE_SPCO_Reg_Step_Attendee_Information',
308
+					'slug'       => 'attendee_information',
309
+					'has_hooks'  => false,
310
+				),
311
+				20  => array(
312
+					'file_path'  => SPCO_REG_STEPS_PATH . 'registration_confirmation',
313
+					'class_name' => 'EE_SPCO_Reg_Step_Registration_Confirmation',
314
+					'slug'       => 'registration_confirmation',
315
+					'has_hooks'  => false,
316
+				),
317
+				30  => array(
318
+					'file_path'  => SPCO_REG_STEPS_PATH . 'payment_options',
319
+					'class_name' => 'EE_SPCO_Reg_Step_Payment_Options',
320
+					'slug'       => 'payment_options',
321
+					'has_hooks'  => true,
322
+				),
323
+				999 => array(
324
+					'file_path'  => SPCO_REG_STEPS_PATH . 'finalize_registration',
325
+					'class_name' => 'EE_SPCO_Reg_Step_Finalize_Registration',
326
+					'slug'       => 'finalize_registration',
327
+					'has_hooks'  => false,
328
+				),
329
+			);
330
+		}
331
+		return $reg_steps;
332
+	}
333
+
334
+
335
+
336
+	/**
337
+	 *    registration_checkout_for_admin
338
+	 *
339
+	 * @access    public
340
+	 * @return    string
341
+	 * @throws EE_Error
342
+	 */
343
+	public static function registration_checkout_for_admin()
344
+	{
345
+		EED_Single_Page_Checkout::load_request_handler();
346
+		EE_Registry::instance()->REQ->set('step', 'attendee_information');
347
+		EE_Registry::instance()->REQ->set('action', 'display_spco_reg_step');
348
+		EE_Registry::instance()->REQ->set('process_form_submission', false);
349
+		EED_Single_Page_Checkout::instance()->_initialize();
350
+		EED_Single_Page_Checkout::instance()->_display_spco_reg_form();
351
+		return EE_Registry::instance()->REQ->get_output();
352
+	}
353
+
354
+
355
+
356
+	/**
357
+	 * process_registration_from_admin
358
+	 *
359
+	 * @access public
360
+	 * @return \EE_Transaction
361
+	 * @throws EE_Error
362
+	 */
363
+	public static function process_registration_from_admin()
364
+	{
365
+		EED_Single_Page_Checkout::load_request_handler();
366
+		EE_Registry::instance()->REQ->set('step', 'attendee_information');
367
+		EE_Registry::instance()->REQ->set('action', 'process_reg_step');
368
+		EE_Registry::instance()->REQ->set('process_form_submission', true);
369
+		EED_Single_Page_Checkout::instance()->_initialize();
370
+		if (EED_Single_Page_Checkout::instance()->checkout->current_step->completed()) {
371
+			$final_reg_step = end(EED_Single_Page_Checkout::instance()->checkout->reg_steps);
372
+			if ($final_reg_step instanceof EE_SPCO_Reg_Step_Finalize_Registration) {
373
+				EED_Single_Page_Checkout::instance()->checkout->set_reg_step_initiated($final_reg_step);
374
+				if ($final_reg_step->process_reg_step()) {
375
+					$final_reg_step->set_completed();
376
+					EED_Single_Page_Checkout::instance()->checkout->update_txn_reg_steps_array();
377
+					return EED_Single_Page_Checkout::instance()->checkout->transaction;
378
+				}
379
+			}
380
+		}
381
+		return null;
382
+	}
383
+
384
+
385
+
386
+	/**
387
+	 *    run
388
+	 *
389
+	 * @access    public
390
+	 * @param WP_Query $WP_Query
391
+	 * @return    void
392
+	 * @throws EE_Error
393
+	 */
394
+	public function run($WP_Query)
395
+	{
396
+		if (
397
+			$WP_Query instanceof WP_Query
398
+			&& $WP_Query->is_main_query()
399
+			&& apply_filters('FHEE__EED_Single_Page_Checkout__run', true)
400
+			&& $this->_is_reg_checkout()
401
+		) {
402
+			$this->_initialize();
403
+		}
404
+	}
405
+
406
+
407
+
408
+	/**
409
+	 * determines whether current url matches reg page url
410
+	 *
411
+	 * @return bool
412
+	 */
413
+	protected function _is_reg_checkout()
414
+	{
415
+		// get current permalink for reg page without any extra query args
416
+		$reg_page_url = \get_permalink(EE_Config::instance()->core->reg_page_id);
417
+		// get request URI for current request, but without the scheme or host
418
+		$current_request_uri = \EEH_URL::filter_input_server_url('REQUEST_URI');
419
+		$current_request_uri = html_entity_decode($current_request_uri);
420
+		// get array of query args from the current request URI
421
+		$query_args = \EEH_URL::get_query_string($current_request_uri);
422
+		// grab page id if it is set
423
+		$page_id = isset($query_args['page_id']) ? absint($query_args['page_id']) : 0;
424
+		// and remove the page id from the query args (we will re-add it later)
425
+		unset($query_args['page_id']);
426
+		// now strip all query args from current request URI
427
+		$current_request_uri = remove_query_arg(array_keys($query_args), $current_request_uri);
428
+		// and re-add the page id if it was set
429
+		if ($page_id) {
430
+			$current_request_uri = add_query_arg('page_id', $page_id, $current_request_uri);
431
+		}
432
+		// remove slashes and ?
433
+		$current_request_uri = trim($current_request_uri, '?/');
434
+		// is current request URI part of the known full reg page URL ?
435
+		return ! empty($current_request_uri) && strpos($reg_page_url, $current_request_uri) !== false;
436
+	}
437
+
438
+
439
+
440
+	/**
441
+	 * @param WP_Query $wp_query
442
+	 * @return    void
443
+	 * @throws EE_Error
444
+	 */
445
+	public static function init($wp_query)
446
+	{
447
+		EED_Single_Page_Checkout::instance()->run($wp_query);
448
+	}
449
+
450
+
451
+
452
+	/**
453
+	 *    _initialize - initial module setup
454
+	 *
455
+	 * @access    private
456
+	 * @throws EE_Error
457
+	 * @return    void
458
+	 */
459
+	private function _initialize()
460
+	{
461
+		// ensure SPCO doesn't run twice
462
+		if (EED_Single_Page_Checkout::$_initialized) {
463
+			return;
464
+		}
465
+		try {
466
+			EED_Single_Page_Checkout::load_reg_steps();
467
+			$this->_verify_session();
468
+			// setup the EE_Checkout object
469
+			$this->checkout = $this->_initialize_checkout();
470
+			// filter checkout
471
+			$this->checkout = apply_filters('FHEE__EED_Single_Page_Checkout___initialize__checkout', $this->checkout);
472
+			// get the $_GET
473
+			$this->_get_request_vars();
474
+			if ($this->_block_bots()) {
475
+				return;
476
+			}
477
+			// filter continue_reg
478
+			$this->checkout->continue_reg = apply_filters(
479
+				'FHEE__EED_Single_Page_Checkout__init___continue_reg',
480
+				true,
481
+				$this->checkout
482
+			);
483
+			// load the reg steps array
484
+			if ( ! $this->_load_and_instantiate_reg_steps()) {
485
+				EED_Single_Page_Checkout::$_initialized = true;
486
+				return;
487
+			}
488
+			// set the current step
489
+			$this->checkout->set_current_step($this->checkout->step);
490
+			// and the next step
491
+			$this->checkout->set_next_step();
492
+			// verify that everything has been setup correctly
493
+			if ( ! ($this->_verify_transaction_and_get_registrations() && $this->_final_verifications())) {
494
+				EED_Single_Page_Checkout::$_initialized = true;
495
+				return;
496
+			}
497
+			// lock the transaction
498
+			$this->checkout->transaction->lock();
499
+			// make sure all of our cached objects are added to their respective model entity mappers
500
+			$this->checkout->refresh_all_entities();
501
+			// set amount owing
502
+			$this->checkout->amount_owing = $this->checkout->transaction->remaining();
503
+			// initialize each reg step, which gives them the chance to potentially alter the process
504
+			$this->_initialize_reg_steps();
505
+			// DEBUG LOG
506
+			//$this->checkout->log( __CLASS__, __FUNCTION__, __LINE__ );
507
+			// get reg form
508
+			if( ! $this->_check_form_submission()) {
509
+				EED_Single_Page_Checkout::$_initialized = true;
510
+				return;
511
+			}
512
+			// checkout the action!!!
513
+			$this->_process_form_action();
514
+			// add some style and make it dance
515
+			$this->add_styles_and_scripts();
516
+			// kk... SPCO has successfully run
517
+			EED_Single_Page_Checkout::$_initialized = true;
518
+			// set no cache headers and constants
519
+			EE_System::do_not_cache();
520
+			// add anchor
521
+			add_action('loop_start', array($this, 'set_checkout_anchor'), 1);
522
+			// remove transaction lock
523
+			add_action('shutdown', array($this, 'unlock_transaction'), 1);
524
+		} catch (Exception $e) {
525
+			EE_Error::add_error($e->getMessage(), __FILE__, __FUNCTION__, __LINE__);
526
+		}
527
+	}
528
+
529
+
530
+
531
+	/**
532
+	 *    _verify_session
533
+	 * checks that the session is valid and not expired
534
+	 *
535
+	 * @access    private
536
+	 * @throws EE_Error
537
+	 */
538
+	private function _verify_session()
539
+	{
540
+		if ( ! EE_Registry::instance()->SSN instanceof EE_Session) {
541
+			throw new EE_Error(__('The EE_Session class could not be loaded.', 'event_espresso'));
542
+		}
543
+		$clear_session_requested = filter_var(
544
+			EE_Registry::instance()->REQ->get('clear_session', false),
545
+			FILTER_VALIDATE_BOOLEAN
546
+		);
547
+		// is session still valid ?
548
+		if ($clear_session_requested
549
+			|| ( EE_Registry::instance()->SSN->expired()
550
+			  && EE_Registry::instance()->REQ->get('e_reg_url_link', '') === ''
551
+			)
552
+		) {
553
+			$this->checkout = new EE_Checkout();
554
+			EE_Registry::instance()->SSN->clear_session(__CLASS__, __FUNCTION__);
555
+			// EE_Registry::instance()->SSN->reset_cart();
556
+			// EE_Registry::instance()->SSN->reset_checkout();
557
+			// EE_Registry::instance()->SSN->reset_transaction();
558
+			if (! $clear_session_requested) {
559
+				EE_Error::add_attention(
560
+					EE_Registry::$i18n_js_strings['registration_expiration_notice'],
561
+					__FILE__, __FUNCTION__, __LINE__
562
+				);
563
+			}
564
+			// EE_Registry::instance()->SSN->reset_expired();
565
+		}
566
+	}
567
+
568
+
569
+
570
+	/**
571
+	 *    _initialize_checkout
572
+	 * loads and instantiates EE_Checkout
573
+	 *
574
+	 * @access    private
575
+	 * @throws EE_Error
576
+	 * @return EE_Checkout
577
+	 */
578
+	private function _initialize_checkout()
579
+	{
580
+		// look in session for existing checkout
581
+		/** @type EE_Checkout $checkout */
582
+		$checkout = EE_Registry::instance()->SSN->checkout();
583
+		// verify
584
+		if ( ! $checkout instanceof EE_Checkout) {
585
+			// instantiate EE_Checkout object for handling the properties of the current checkout process
586
+			$checkout = EE_Registry::instance()->load_file(
587
+				SPCO_INC_PATH,
588
+				'EE_Checkout',
589
+				'class', array(),
590
+				false
591
+			);
592
+		} else {
593
+			if ($checkout->current_step->is_final_step() && $checkout->exit_spco() === true) {
594
+				$this->unlock_transaction();
595
+				wp_safe_redirect($checkout->redirect_url);
596
+				exit();
597
+			}
598
+		}
599
+		$checkout = apply_filters('FHEE__EED_Single_Page_Checkout___initialize_checkout__checkout', $checkout);
600
+		// verify again
601
+		if ( ! $checkout instanceof EE_Checkout) {
602
+			throw new EE_Error(__('The EE_Checkout class could not be loaded.', 'event_espresso'));
603
+		}
604
+		// reset anything that needs a clean slate for each request
605
+		$checkout->reset_for_current_request();
606
+		return $checkout;
607
+	}
608
+
609
+
610
+
611
+	/**
612
+	 *    _get_request_vars
613
+	 *
614
+	 * @access    private
615
+	 * @return    void
616
+	 * @throws EE_Error
617
+	 */
618
+	private function _get_request_vars()
619
+	{
620
+		// load classes
621
+		EED_Single_Page_Checkout::load_request_handler();
622
+		//make sure this request is marked as belonging to EE
623
+		EE_Registry::instance()->REQ->set_espresso_page(true);
624
+		// which step is being requested ?
625
+		$this->checkout->step = EE_Registry::instance()->REQ->get('step', $this->_get_first_step());
626
+		// which step is being edited ?
627
+		$this->checkout->edit_step = EE_Registry::instance()->REQ->get('edit_step', '');
628
+		// and what we're doing on the current step
629
+		$this->checkout->action = EE_Registry::instance()->REQ->get('action', 'display_spco_reg_step');
630
+		// timestamp
631
+		$this->checkout->uts = EE_Registry::instance()->REQ->get('uts', 0);
632
+		// returning to edit ?
633
+		$this->checkout->reg_url_link = EE_Registry::instance()->REQ->get('e_reg_url_link', '');
634
+		// add reg url link to registration query params
635
+		if ($this->checkout->reg_url_link && strpos($this->checkout->reg_url_link, '1-') !== 0) {
636
+			$this->checkout->reg_cache_where_params[0]['REG_url_link'] = $this->checkout->reg_url_link;
637
+		}
638
+		// or some other kind of revisit ?
639
+		$this->checkout->revisit = filter_var(
640
+			EE_Registry::instance()->REQ->get('revisit', false),
641
+			FILTER_VALIDATE_BOOLEAN
642
+		);
643
+		// and whether or not to generate a reg form for this request
644
+		$this->checkout->generate_reg_form = filter_var(
645
+			EE_Registry::instance()->REQ->get('generate_reg_form', true),
646
+			FILTER_VALIDATE_BOOLEAN
647
+		);
648
+		// and whether or not to process a reg form submission for this request
649
+		$this->checkout->process_form_submission = filter_var(
650
+			EE_Registry::instance()->REQ->get(
651
+				'process_form_submission',
652
+				$this->checkout->action === 'process_reg_step'
653
+			),
654
+			FILTER_VALIDATE_BOOLEAN
655
+		);
656
+		$this->checkout->process_form_submission = filter_var(
657
+			$this->checkout->action !== 'display_spco_reg_step'
658
+				? $this->checkout->process_form_submission
659
+				: false,
660
+			FILTER_VALIDATE_BOOLEAN
661
+		);
662
+		// $this->_display_request_vars();
663
+	}
664
+
665
+
666
+
667
+	/**
668
+	 *  _display_request_vars
669
+	 *
670
+	 * @access    protected
671
+	 * @return    void
672
+	 */
673
+	protected function _display_request_vars()
674
+	{
675
+		if ( ! WP_DEBUG) {
676
+			return;
677
+		}
678
+		EEH_Debug_Tools::printr($_REQUEST, '$_REQUEST', __FILE__, __LINE__);
679
+		EEH_Debug_Tools::printr($this->checkout->step, '$this->checkout->step', __FILE__, __LINE__);
680
+		EEH_Debug_Tools::printr($this->checkout->edit_step, '$this->checkout->edit_step', __FILE__, __LINE__);
681
+		EEH_Debug_Tools::printr($this->checkout->action, '$this->checkout->action', __FILE__, __LINE__);
682
+		EEH_Debug_Tools::printr($this->checkout->reg_url_link, '$this->checkout->reg_url_link', __FILE__, __LINE__);
683
+		EEH_Debug_Tools::printr($this->checkout->revisit, '$this->checkout->revisit', __FILE__, __LINE__);
684
+		EEH_Debug_Tools::printr($this->checkout->generate_reg_form, '$this->checkout->generate_reg_form', __FILE__, __LINE__);
685
+		EEH_Debug_Tools::printr($this->checkout->process_form_submission, '$this->checkout->process_form_submission', __FILE__, __LINE__);
686
+	}
687
+
688
+
689
+
690
+	/**
691
+	 * _block_bots
692
+	 * checks that the incoming request has either of the following set:
693
+	 *  a uts (unix timestamp) which indicates that the request was redirected from the Ticket Selector
694
+	 *  a REG URL Link, which indicates that the request is a return visit to SPCO for a valid TXN
695
+	 * so if you're not coming from the Ticket Selector nor returning for a valid IP...
696
+	 * then where you coming from man?
697
+	 *
698
+	 * @return boolean
699
+	 */
700
+	private function _block_bots()
701
+	{
702
+		$invalid_checkout_access = EED_Invalid_Checkout_Access::getInvalidCheckoutAccess();
703
+		if ($invalid_checkout_access->checkoutAccessIsInvalid($this->checkout)) {
704
+			return true;
705
+		}
706
+		return false;
707
+	}
708
+
709
+
710
+
711
+	/**
712
+	 *    _get_first_step
713
+	 *  gets slug for first step in $_reg_steps_array
714
+	 *
715
+	 * @access    private
716
+	 * @throws EE_Error
717
+	 * @return    string
718
+	 */
719
+	private function _get_first_step()
720
+	{
721
+		$first_step = reset(EED_Single_Page_Checkout::$_reg_steps_array);
722
+		return isset($first_step['slug']) ? $first_step['slug'] : 'attendee_information';
723
+	}
724
+
725
+
726
+
727
+	/**
728
+	 *    _load_and_instantiate_reg_steps
729
+	 *  instantiates each reg step based on the loaded reg_steps array
730
+	 *
731
+	 * @access    private
732
+	 * @throws EE_Error
733
+	 * @return    bool
734
+	 */
735
+	private function _load_and_instantiate_reg_steps()
736
+	{
737
+		do_action('AHEE__Single_Page_Checkout___load_and_instantiate_reg_steps__start', $this->checkout);
738
+		// have reg_steps already been instantiated ?
739
+		if (
740
+			empty($this->checkout->reg_steps)
741
+			|| apply_filters('FHEE__Single_Page_Checkout__load_reg_steps__reload_reg_steps', false, $this->checkout)
742
+		) {
743
+			// if not, then loop through raw reg steps array
744
+			foreach (EED_Single_Page_Checkout::$_reg_steps_array as $order => $reg_step) {
745
+				if ( ! $this->_load_and_instantiate_reg_step($reg_step, $order)) {
746
+					return false;
747
+				}
748
+			}
749
+			EE_Registry::instance()->CFG->registration->skip_reg_confirmation = true;
750
+			EE_Registry::instance()->CFG->registration->reg_confirmation_last = true;
751
+			// skip the registration_confirmation page ?
752
+			if (EE_Registry::instance()->CFG->registration->skip_reg_confirmation) {
753
+				// just remove it from the reg steps array
754
+				$this->checkout->remove_reg_step('registration_confirmation', false);
755
+			} else if (
756
+				isset($this->checkout->reg_steps['registration_confirmation'])
757
+				&& EE_Registry::instance()->CFG->registration->reg_confirmation_last
758
+			) {
759
+				// set the order to something big like 100
760
+				$this->checkout->set_reg_step_order('registration_confirmation', 100);
761
+			}
762
+			// filter the array for good luck
763
+			$this->checkout->reg_steps = apply_filters(
764
+				'FHEE__Single_Page_Checkout__load_reg_steps__reg_steps',
765
+				$this->checkout->reg_steps
766
+			);
767
+			// finally re-sort based on the reg step class order properties
768
+			$this->checkout->sort_reg_steps();
769
+		} else {
770
+			foreach ($this->checkout->reg_steps as $reg_step) {
771
+				// set all current step stati to FALSE
772
+				$reg_step->set_is_current_step(false);
773
+			}
774
+		}
775
+		if (empty($this->checkout->reg_steps)) {
776
+			EE_Error::add_error(
777
+				__('No Reg Steps were loaded..', 'event_espresso'),
778
+				__FILE__, __FUNCTION__, __LINE__
779
+			);
780
+			return false;
781
+		}
782
+		// make reg step details available to JS
783
+		$this->checkout->set_reg_step_JSON_info();
784
+		return true;
785
+	}
786
+
787
+
788
+
789
+	/**
790
+	 *     _load_and_instantiate_reg_step
791
+	 *
792
+	 * @access    private
793
+	 * @param array $reg_step
794
+	 * @param int   $order
795
+	 * @return bool
796
+	 */
797
+	private function _load_and_instantiate_reg_step($reg_step = array(), $order = 0)
798
+	{
799
+		// we need a file_path, class_name, and slug to add a reg step
800
+		if (isset($reg_step['file_path'], $reg_step['class_name'], $reg_step['slug'])) {
801
+			// if editing a specific step, but this is NOT that step... (and it's not the 'finalize_registration' step)
802
+			if (
803
+				$this->checkout->reg_url_link
804
+				&& $this->checkout->step !== $reg_step['slug']
805
+				&& $reg_step['slug'] !== 'finalize_registration'
806
+				// normally at this point we would NOT load the reg step, but this filter can change that
807
+				&& apply_filters(
808
+					'FHEE__Single_Page_Checkout___load_and_instantiate_reg_step__bypass_reg_step',
809
+					true,
810
+					$reg_step,
811
+					$this->checkout
812
+				)
813
+			) {
814
+				return true;
815
+			}
816
+			// instantiate step class using file path and class name
817
+			$reg_step_obj = EE_Registry::instance()->load_file(
818
+				$reg_step['file_path'],
819
+				$reg_step['class_name'],
820
+				'class',
821
+				$this->checkout,
822
+				false
823
+			);
824
+			// did we gets the goods ?
825
+			if ($reg_step_obj instanceof EE_SPCO_Reg_Step) {
826
+				// set reg step order based on config
827
+				$reg_step_obj->set_order($order);
828
+				// add instantiated reg step object to the master reg steps array
829
+				$this->checkout->add_reg_step($reg_step_obj);
830
+			} else {
831
+				EE_Error::add_error(
832
+					__('The current step could not be set.', 'event_espresso'),
833
+					__FILE__, __FUNCTION__, __LINE__
834
+				);
835
+				return false;
836
+			}
837
+		} else {
838
+			if (WP_DEBUG) {
839
+				EE_Error::add_error(
840
+					sprintf(
841
+						__(
842
+							'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',
843
+							'event_espresso'
844
+						),
845
+						isset($reg_step['file_path']) ? $reg_step['file_path'] : '',
846
+						isset($reg_step['class_name']) ? $reg_step['class_name'] : '',
847
+						isset($reg_step['slug']) ? $reg_step['slug'] : '',
848
+						'<ul>',
849
+						'<li>',
850
+						'</li>',
851
+						'</ul>'
852
+					),
853
+					__FILE__, __FUNCTION__, __LINE__
854
+				);
855
+			}
856
+			return false;
857
+		}
858
+		return true;
859
+	}
860
+
861
+
862
+	/**
863
+	 * _verify_transaction_and_get_registrations
864
+	 *
865
+	 * @access private
866
+	 * @return bool
867
+	 * @throws InvalidDataTypeException
868
+	 * @throws InvalidEntityException
869
+	 * @throws EE_Error
870
+	 */
871
+	private function _verify_transaction_and_get_registrations()
872
+	{
873
+		// was there already a valid transaction in the checkout from the session ?
874
+		if ( ! $this->checkout->transaction instanceof EE_Transaction) {
875
+			// get transaction from db or session
876
+			$this->checkout->transaction = $this->checkout->reg_url_link && ! is_admin()
877
+				? $this->_get_transaction_and_cart_for_previous_visit()
878
+				: $this->_get_cart_for_current_session_and_setup_new_transaction();
879
+			if ( ! $this->checkout->transaction instanceof EE_Transaction) {
880
+				EE_Error::add_error(
881
+					__('Your Registration and Transaction information could not be retrieved from the db.',
882
+						'event_espresso'),
883
+					__FILE__, __FUNCTION__, __LINE__
884
+				);
885
+				$this->checkout->transaction = EE_Transaction::new_instance();
886
+				// add some style and make it dance
887
+				$this->add_styles_and_scripts();
888
+				EED_Single_Page_Checkout::$_initialized = true;
889
+				return false;
890
+			}
891
+			// and the registrations for the transaction
892
+			$this->_get_registrations($this->checkout->transaction);
893
+		}
894
+		return true;
895
+	}
896
+
897
+
898
+
899
+	/**
900
+	 * _get_transaction_and_cart_for_previous_visit
901
+	 *
902
+	 * @access private
903
+	 * @return mixed EE_Transaction|NULL
904
+	 */
905
+	private function _get_transaction_and_cart_for_previous_visit()
906
+	{
907
+		/** @var $TXN_model EEM_Transaction */
908
+		$TXN_model = EE_Registry::instance()->load_model('Transaction');
909
+		// because the reg_url_link is present in the request,
910
+		// this is a return visit to SPCO, so we'll get the transaction data from the db
911
+		$transaction = $TXN_model->get_transaction_from_reg_url_link($this->checkout->reg_url_link);
912
+		// verify transaction
913
+		if ($transaction instanceof EE_Transaction) {
914
+			// and get the cart that was used for that transaction
915
+			$this->checkout->cart = $this->_get_cart_for_transaction($transaction);
916
+			return $transaction;
917
+		}
918
+		EE_Error::add_error(
919
+			__('Your Registration and Transaction information could not be retrieved from the db.', 'event_espresso'),
920
+			__FILE__, __FUNCTION__, __LINE__
921
+		);
922
+		return null;
923
+
924
+	}
925
+
926
+
927
+
928
+	/**
929
+	 * _get_cart_for_transaction
930
+	 *
931
+	 * @access private
932
+	 * @param EE_Transaction $transaction
933
+	 * @return EE_Cart
934
+	 */
935
+	private function _get_cart_for_transaction($transaction)
936
+	{
937
+		return $this->checkout->get_cart_for_transaction($transaction);
938
+	}
939
+
940
+
941
+
942
+	/**
943
+	 * get_cart_for_transaction
944
+	 *
945
+	 * @access public
946
+	 * @param EE_Transaction $transaction
947
+	 * @return EE_Cart
948
+	 */
949
+	public function get_cart_for_transaction(EE_Transaction $transaction)
950
+	{
951
+		return $this->checkout->get_cart_for_transaction($transaction);
952
+	}
953
+
954
+
955
+
956
+	/**
957
+	 * _get_transaction_and_cart_for_current_session
958
+	 *    generates a new EE_Transaction object and adds it to the $_transaction property.
959
+	 *
960
+	 * @access private
961
+	 * @return EE_Transaction
962
+	 * @throws EE_Error
963
+	 */
964
+	private function _get_cart_for_current_session_and_setup_new_transaction()
965
+	{
966
+		//  if there's no transaction, then this is the FIRST visit to SPCO
967
+		// so load up the cart ( passing nothing for the TXN because it doesn't exist yet )
968
+		$this->checkout->cart = $this->_get_cart_for_transaction(null);
969
+		// and then create a new transaction
970
+		$transaction = $this->_initialize_transaction();
971
+		// verify transaction
972
+		if ($transaction instanceof EE_Transaction) {
973
+			// save it so that we have an ID for other objects to use
974
+			$transaction->save();
975
+			// and save TXN data to the cart
976
+			$this->checkout->cart->get_grand_total()->save_this_and_descendants_to_txn($transaction->ID());
977
+		} else {
978
+			EE_Error::add_error(
979
+				__('A Valid Transaction could not be initialized.', 'event_espresso'),
980
+				__FILE__, __FUNCTION__, __LINE__
981
+			);
982
+		}
983
+		return $transaction;
984
+	}
985
+
986
+
987
+
988
+	/**
989
+	 *    generates a new EE_Transaction object and adds it to the $_transaction property.
990
+	 *
991
+	 * @access private
992
+	 * @return mixed EE_Transaction|NULL
993
+	 */
994
+	private function _initialize_transaction()
995
+	{
996
+		try {
997
+			// ensure cart totals have been calculated
998
+			$this->checkout->cart->get_grand_total()->recalculate_total_including_taxes();
999
+			// grab the cart grand total
1000
+			$cart_total = $this->checkout->cart->get_cart_grand_total();
1001
+			// create new TXN
1002
+			$transaction = EE_Transaction::new_instance(
1003
+				array(
1004
+					'TXN_reg_steps' => $this->checkout->initialize_txn_reg_steps_array(),
1005
+					'TXN_total'     => $cart_total > 0 ? $cart_total : 0,
1006
+					'TXN_paid'      => 0,
1007
+					'STS_ID'        => EEM_Transaction::failed_status_code,
1008
+				)
1009
+			);
1010
+			// save it so that we have an ID for other objects to use
1011
+			$transaction->save();
1012
+			// set cron job for following up on TXNs after their session has expired
1013
+			EE_Cron_Tasks::schedule_expired_transaction_check(
1014
+				EE_Registry::instance()->SSN->expiration() + 1,
1015
+				$transaction->ID()
1016
+			);
1017
+			return $transaction;
1018
+		} catch (Exception $e) {
1019
+			EE_Error::add_error($e->getMessage(), __FILE__, __FUNCTION__, __LINE__);
1020
+		}
1021
+		return null;
1022
+	}
1023
+
1024
+
1025
+	/**
1026
+	 * _get_registrations
1027
+	 *
1028
+	 * @access private
1029
+	 * @param EE_Transaction $transaction
1030
+	 * @return void
1031
+	 * @throws InvalidDataTypeException
1032
+	 * @throws InvalidEntityException
1033
+	 * @throws EE_Error
1034
+	 */
1035
+	private function _get_registrations(EE_Transaction $transaction)
1036
+	{
1037
+		// first step: grab the registrants  { : o
1038
+		$registrations = $transaction->registrations($this->checkout->reg_cache_where_params, false);
1039
+		$this->checkout->total_ticket_count = count($registrations);
1040
+		// verify registrations have been set
1041
+		if (empty($registrations)) {
1042
+			// if no cached registrations, then check the db
1043
+			$registrations = $transaction->registrations($this->checkout->reg_cache_where_params, false);
1044
+			// still nothing ? well as long as this isn't a revisit
1045
+			if (empty($registrations) && ! $this->checkout->revisit) {
1046
+				// generate new registrations from scratch
1047
+				$registrations = $this->_initialize_registrations($transaction);
1048
+			}
1049
+		}
1050
+		// sort by their original registration order
1051
+		usort($registrations, array('EED_Single_Page_Checkout', 'sort_registrations_by_REG_count'));
1052
+		// then loop thru the array
1053
+		foreach ($registrations as $registration) {
1054
+			// verify each registration
1055
+			if ($registration instanceof EE_Registration) {
1056
+				// we display all attendee info for the primary registrant
1057
+				if ($this->checkout->reg_url_link === $registration->reg_url_link()
1058
+					&& $registration->is_primary_registrant()
1059
+				) {
1060
+					$this->checkout->primary_revisit = true;
1061
+					break;
1062
+				}
1063
+				if ($this->checkout->revisit && $this->checkout->reg_url_link !== $registration->reg_url_link()) {
1064
+					// but hide info if it doesn't belong to you
1065
+					$transaction->clear_cache('Registration', $registration->ID());
1066
+					$this->checkout->total_ticket_count--;
1067
+				}
1068
+				$this->checkout->set_reg_status_updated($registration->ID(), false);
1069
+			}
1070
+		}
1071
+	}
1072
+
1073
+
1074
+	/**
1075
+	 *    adds related EE_Registration objects for each ticket in the cart to the current EE_Transaction object
1076
+	 *
1077
+	 * @access private
1078
+	 * @param EE_Transaction $transaction
1079
+	 * @return    array
1080
+	 * @throws InvalidDataTypeException
1081
+	 * @throws InvalidEntityException
1082
+	 * @throws EE_Error
1083
+	 */
1084
+	private function _initialize_registrations(EE_Transaction $transaction)
1085
+	{
1086
+		$att_nmbr = 0;
1087
+		$registrations = array();
1088
+		if ($transaction instanceof EE_Transaction) {
1089
+			/** @type EE_Registration_Processor $registration_processor */
1090
+			$registration_processor = EE_Registry::instance()->load_class('Registration_Processor');
1091
+			$this->checkout->total_ticket_count = $this->checkout->cart->all_ticket_quantity_count();
1092
+			// now let's add the cart items to the $transaction
1093
+			foreach ($this->checkout->cart->get_tickets() as $line_item) {
1094
+				//do the following for each ticket of this type they selected
1095
+				for ($x = 1; $x <= $line_item->quantity(); $x++) {
1096
+					$att_nmbr++;
1097
+					/** @var EventEspresso\core\services\commands\registration\CreateRegistrationCommand $CreateRegistrationCommand */
1098
+					$CreateRegistrationCommand = EE_Registry::instance()->create(
1099
+						'EventEspresso\core\services\commands\registration\CreateRegistrationCommand',
1100
+						array(
1101
+							$transaction,
1102
+							$line_item,
1103
+							$att_nmbr,
1104
+							$this->checkout->total_ticket_count,
1105
+						)
1106
+					);
1107
+					// override capabilities for frontend registrations
1108
+					if ( ! is_admin()) {
1109
+						$CreateRegistrationCommand->setCapCheck(
1110
+							new PublicCapabilities('', 'create_new_registration')
1111
+						);
1112
+					}
1113
+					$registration = EE_Registry::instance()->BUS->execute($CreateRegistrationCommand);
1114
+					if ( ! $registration instanceof EE_Registration) {
1115
+						throw new InvalidEntityException($registration, 'EE_Registration');
1116
+					}
1117
+					$registrations[ $registration->ID() ] = $registration;
1118
+				}
1119
+			}
1120
+			$registration_processor->fix_reg_final_price_rounding_issue($transaction);
1121
+		}
1122
+		return $registrations;
1123
+	}
1124
+
1125
+
1126
+
1127
+	/**
1128
+	 * sorts registrations by REG_count
1129
+	 *
1130
+	 * @access public
1131
+	 * @param EE_Registration $reg_A
1132
+	 * @param EE_Registration $reg_B
1133
+	 * @return int
1134
+	 */
1135
+	public static function sort_registrations_by_REG_count(EE_Registration $reg_A, EE_Registration $reg_B)
1136
+	{
1137
+		// this shouldn't ever happen within the same TXN, but oh well
1138
+		if ($reg_A->count() === $reg_B->count()) {
1139
+			return 0;
1140
+		}
1141
+		return ($reg_A->count() > $reg_B->count()) ? 1 : -1;
1142
+	}
1143
+
1144
+
1145
+
1146
+	/**
1147
+	 *    _final_verifications
1148
+	 * just makes sure that everything is set up correctly before proceeding
1149
+	 *
1150
+	 * @access    private
1151
+	 * @return    bool
1152
+	 * @throws EE_Error
1153
+	 */
1154
+	private function _final_verifications()
1155
+	{
1156
+		// filter checkout
1157
+		$this->checkout = apply_filters(
1158
+			'FHEE__EED_Single_Page_Checkout___final_verifications__checkout',
1159
+			$this->checkout
1160
+		);
1161
+		//verify that current step is still set correctly
1162
+		if ( ! $this->checkout->current_step instanceof EE_SPCO_Reg_Step) {
1163
+			EE_Error::add_error(
1164
+				__('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'),
1165
+				__FILE__,
1166
+				__FUNCTION__,
1167
+				__LINE__
1168
+			);
1169
+			return false;
1170
+		}
1171
+		// if returning to SPCO, then verify that primary registrant is set
1172
+		if ( ! empty($this->checkout->reg_url_link)) {
1173
+			$valid_registrant = $this->checkout->transaction->primary_registration();
1174
+			if ( ! $valid_registrant instanceof EE_Registration) {
1175
+				EE_Error::add_error(
1176
+					__('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'),
1177
+					__FILE__,
1178
+					__FUNCTION__,
1179
+					__LINE__
1180
+				);
1181
+				return false;
1182
+			}
1183
+			$valid_registrant = null;
1184
+			foreach (
1185
+				$this->checkout->transaction->registrations($this->checkout->reg_cache_where_params) as $registration
1186
+			) {
1187
+				if (
1188
+					$registration instanceof EE_Registration
1189
+					&& $registration->reg_url_link() === $this->checkout->reg_url_link
1190
+				) {
1191
+					$valid_registrant = $registration;
1192
+				}
1193
+			}
1194
+			if ( ! $valid_registrant instanceof EE_Registration) {
1195
+				// hmmm... maybe we have the wrong session because the user is opening multiple tabs ?
1196
+				if (EED_Single_Page_Checkout::$_checkout_verified) {
1197
+					// clear the session, mark the checkout as unverified, and try again
1198
+					EE_Registry::instance()->SSN->clear_session(__CLASS__, __FUNCTION__);
1199
+					EED_Single_Page_Checkout::$_initialized = false;
1200
+					EED_Single_Page_Checkout::$_checkout_verified = false;
1201
+					$this->_initialize();
1202
+					EE_Error::reset_notices();
1203
+					return false;
1204
+				}
1205
+				EE_Error::add_error(
1206
+					__(
1207
+						'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.',
1208
+						'event_espresso'
1209
+					),
1210
+					__FILE__,
1211
+					__FUNCTION__,
1212
+					__LINE__
1213
+				);
1214
+				return false;
1215
+			}
1216
+		}
1217
+		// now that things have been kinda sufficiently verified,
1218
+		// let's add the checkout to the session so that it's available to other systems
1219
+		EE_Registry::instance()->SSN->set_checkout($this->checkout);
1220
+		return true;
1221
+	}
1222
+
1223
+
1224
+
1225
+	/**
1226
+	 *    _initialize_reg_steps
1227
+	 * first makes sure that EE_Transaction_Processor::set_reg_step_initiated() is called as required
1228
+	 * then loops thru all of the active reg steps and calls the initialize_reg_step() method
1229
+	 *
1230
+	 * @access    private
1231
+	 * @param bool $reinitializing
1232
+	 * @throws EE_Error
1233
+	 */
1234
+	private function _initialize_reg_steps($reinitializing = false)
1235
+	{
1236
+		$this->checkout->set_reg_step_initiated($this->checkout->current_step);
1237
+		// loop thru all steps to call their individual "initialize" methods and set i18n strings for JS
1238
+		foreach ($this->checkout->reg_steps as $reg_step) {
1239
+			if ( ! $reg_step->initialize_reg_step()) {
1240
+				// if not initialized then maybe this step is being removed...
1241
+				if ( ! $reinitializing && $reg_step->is_current_step()) {
1242
+					// if it was the current step, then we need to start over here
1243
+					$this->_initialize_reg_steps(true);
1244
+					return;
1245
+				}
1246
+				continue;
1247
+			}
1248
+			// add css and JS for current step
1249
+			$reg_step->enqueue_styles_and_scripts();
1250
+			// i18n
1251
+			$reg_step->translate_js_strings();
1252
+			if ($reg_step->is_current_step()) {
1253
+				// the text that appears on the reg step form submit button
1254
+				$reg_step->set_submit_button_text();
1255
+			}
1256
+		}
1257
+		// dynamically creates hook point like: AHEE__Single_Page_Checkout___initialize_reg_step__attendee_information
1258
+		do_action(
1259
+			"AHEE__Single_Page_Checkout___initialize_reg_step__{$this->checkout->current_step->slug()}",
1260
+			$this->checkout->current_step
1261
+		);
1262
+	}
1263
+
1264
+
1265
+
1266
+	/**
1267
+	 * _check_form_submission
1268
+	 *
1269
+	 * @access private
1270
+	 * @return boolean
1271
+	 */
1272
+	private function _check_form_submission()
1273
+	{
1274
+		//does this request require the reg form to be generated ?
1275
+		if ($this->checkout->generate_reg_form) {
1276
+			// ever heard that song by Blue Rodeo ?
1277
+			try {
1278
+				$this->checkout->current_step->reg_form = $this->checkout->current_step->generate_reg_form();
1279
+				// if not displaying a form, then check for form submission
1280
+				if (
1281
+					$this->checkout->process_form_submission
1282
+					&& $this->checkout->current_step->reg_form->was_submitted()
1283
+				) {
1284
+					// clear out any old data in case this step is being run again
1285
+					$this->checkout->current_step->set_valid_data(array());
1286
+					// capture submitted form data
1287
+					$this->checkout->current_step->reg_form->receive_form_submission(
1288
+						apply_filters(
1289
+							'FHEE__Single_Page_Checkout___check_form_submission__request_params',
1290
+							EE_Registry::instance()->REQ->params(),
1291
+							$this->checkout
1292
+						)
1293
+					);
1294
+					// validate submitted form data
1295
+					if ( ! $this->checkout->continue_reg || ! $this->checkout->current_step->reg_form->is_valid()) {
1296
+						// thou shall not pass !!!
1297
+						$this->checkout->continue_reg = false;
1298
+						// any form validation errors?
1299
+						if ($this->checkout->current_step->reg_form->submission_error_message() !== '') {
1300
+							EE_Error::add_error(
1301
+								$this->checkout->current_step->reg_form->submission_error_message(),
1302
+								__FILE__, __FUNCTION__, __LINE__
1303
+							);
1304
+						}
1305
+						// well not really... what will happen is
1306
+						// we'll just get redirected back to redo the current step
1307
+						$this->go_to_next_step();
1308
+						return false;
1309
+					}
1310
+				}
1311
+			} catch (EE_Error $e) {
1312
+				$e->get_error();
1313
+			}
1314
+		}
1315
+		return true;
1316
+	}
1317
+
1318
+
1319
+
1320
+	/**
1321
+	 * _process_action
1322
+	 *
1323
+	 * @access private
1324
+	 * @return void
1325
+	 * @throws EE_Error
1326
+	 */
1327
+	private function _process_form_action()
1328
+	{
1329
+		// what cha wanna do?
1330
+		switch ($this->checkout->action) {
1331
+			// AJAX next step reg form
1332
+			case 'display_spco_reg_step' :
1333
+				$this->checkout->redirect = false;
1334
+				if (EE_Registry::instance()->REQ->ajax) {
1335
+					$this->checkout->json_response->set_reg_step_html(
1336
+						$this->checkout->current_step->display_reg_form()
1337
+					);
1338
+				}
1339
+				break;
1340
+			default :
1341
+				// meh... do one of those other steps first
1342
+				if (
1343
+					! empty($this->checkout->action)
1344
+					&& is_callable(array($this->checkout->current_step, $this->checkout->action))
1345
+				) {
1346
+					// dynamically creates hook point like:
1347
+					//   AHEE__Single_Page_Checkout__before_attendee_information__process_reg_step
1348
+					do_action(
1349
+						"AHEE__Single_Page_Checkout__before_{$this->checkout->current_step->slug()}__{$this->checkout->action}",
1350
+						$this->checkout->current_step
1351
+					);
1352
+					// call action on current step
1353
+					if (call_user_func(array($this->checkout->current_step, $this->checkout->action))) {
1354
+						// good registrant, you get to proceed
1355
+						if (
1356
+							$this->checkout->current_step->success_message() !== ''
1357
+							&& apply_filters(
1358
+								'FHEE__Single_Page_Checkout___process_form_action__display_success',
1359
+								false
1360
+							)
1361
+						) {
1362
+							EE_Error::add_success(
1363
+								$this->checkout->current_step->success_message()
1364
+								. '<br />' . $this->checkout->next_step->_instructions()
1365
+							);
1366
+						}
1367
+						// pack it up, pack it in...
1368
+						$this->_setup_redirect();
1369
+					}
1370
+					// dynamically creates hook point like:
1371
+					//  AHEE__Single_Page_Checkout__after_payment_options__process_reg_step
1372
+					do_action(
1373
+						"AHEE__Single_Page_Checkout__after_{$this->checkout->current_step->slug()}__{$this->checkout->action}",
1374
+						$this->checkout->current_step
1375
+					);
1376
+				} else {
1377
+					EE_Error::add_error(
1378
+						sprintf(
1379
+							__(
1380
+								'The requested form action "%s" does not exist for the current "%s" registration step.',
1381
+								'event_espresso'
1382
+							),
1383
+							$this->checkout->action,
1384
+							$this->checkout->current_step->name()
1385
+						),
1386
+						__FILE__,
1387
+						__FUNCTION__,
1388
+						__LINE__
1389
+					);
1390
+				}
1391
+			// end default
1392
+		}
1393
+		// store our progress so far
1394
+		$this->checkout->stash_transaction_and_checkout();
1395
+		// advance to the next step! If you pass GO, collect $200
1396
+		$this->go_to_next_step();
1397
+	}
1398
+
1399
+
1400
+
1401
+	/**
1402
+	 *        add_styles_and_scripts
1403
+	 *
1404
+	 * @access        public
1405
+	 * @return        void
1406
+	 */
1407
+	public function add_styles_and_scripts()
1408
+	{
1409
+		// i18n
1410
+		$this->translate_js_strings();
1411
+		if ($this->checkout->admin_request) {
1412
+			add_action('admin_enqueue_scripts', array($this, 'enqueue_styles_and_scripts'), 10);
1413
+		} else {
1414
+			add_action('wp_enqueue_scripts', array($this, 'enqueue_styles_and_scripts'), 10);
1415
+		}
1416
+	}
1417
+
1418
+
1419
+
1420
+	/**
1421
+	 *        translate_js_strings
1422
+	 *
1423
+	 * @access        public
1424
+	 * @return        void
1425
+	 */
1426
+	public function translate_js_strings()
1427
+	{
1428
+		EE_Registry::$i18n_js_strings['revisit'] = $this->checkout->revisit;
1429
+		EE_Registry::$i18n_js_strings['e_reg_url_link'] = $this->checkout->reg_url_link;
1430
+		EE_Registry::$i18n_js_strings['server_error'] = __(
1431
+			'An unknown error occurred on the server while attempting to process your request. Please refresh the page and try again or contact support.',
1432
+			'event_espresso'
1433
+		);
1434
+		EE_Registry::$i18n_js_strings['invalid_json_response'] = __(
1435
+			'An invalid response was returned from the server while attempting to process your request. Please refresh the page and try again or contact support.',
1436
+			'event_espresso'
1437
+		);
1438
+		EE_Registry::$i18n_js_strings['validation_error'] = __(
1439
+			'There appears to be a problem with the form validation configuration! Please check the admin settings or contact support.',
1440
+			'event_espresso'
1441
+		);
1442
+		EE_Registry::$i18n_js_strings['invalid_payment_method'] = __(
1443
+			'There appears to be a problem with the payment method configuration! Please refresh the page and try again or contact support.',
1444
+			'event_espresso'
1445
+		);
1446
+		EE_Registry::$i18n_js_strings['reg_step_error'] = __(
1447
+			'This registration step could not be completed. Please refresh the page and try again.',
1448
+			'event_espresso'
1449
+		);
1450
+		EE_Registry::$i18n_js_strings['invalid_coupon'] = __(
1451
+			'We\'re sorry but that coupon code does not appear to be valid. If this is incorrect, please contact the site administrator.',
1452
+			'event_espresso'
1453
+		);
1454
+		EE_Registry::$i18n_js_strings['process_registration'] = sprintf(
1455
+			__(
1456
+				'Please wait while we process your registration.%sDo not refresh the page or navigate away while this is happening.%sThank you for your patience.',
1457
+				'event_espresso'
1458
+			),
1459
+			'<br/>',
1460
+			'<br/>'
1461
+		);
1462
+		EE_Registry::$i18n_js_strings['language'] = get_bloginfo('language');
1463
+		EE_Registry::$i18n_js_strings['EESID'] = EE_Registry::instance()->SSN->id();
1464
+		EE_Registry::$i18n_js_strings['currency'] = EE_Registry::instance()->CFG->currency;
1465
+		EE_Registry::$i18n_js_strings['datepicker_yearRange'] = '-150:+20';
1466
+		EE_Registry::$i18n_js_strings['timer_years'] = __('years', 'event_espresso');
1467
+		EE_Registry::$i18n_js_strings['timer_months'] = __('months', 'event_espresso');
1468
+		EE_Registry::$i18n_js_strings['timer_weeks'] = __('weeks', 'event_espresso');
1469
+		EE_Registry::$i18n_js_strings['timer_days'] = __('days', 'event_espresso');
1470
+		EE_Registry::$i18n_js_strings['timer_hours'] = __('hours', 'event_espresso');
1471
+		EE_Registry::$i18n_js_strings['timer_minutes'] = __('minutes', 'event_espresso');
1472
+		EE_Registry::$i18n_js_strings['timer_seconds'] = __('seconds', 'event_espresso');
1473
+		EE_Registry::$i18n_js_strings['timer_year'] = __('year', 'event_espresso');
1474
+		EE_Registry::$i18n_js_strings['timer_month'] = __('month', 'event_espresso');
1475
+		EE_Registry::$i18n_js_strings['timer_week'] = __('week', 'event_espresso');
1476
+		EE_Registry::$i18n_js_strings['timer_day'] = __('day', 'event_espresso');
1477
+		EE_Registry::$i18n_js_strings['timer_hour'] = __('hour', 'event_espresso');
1478
+		EE_Registry::$i18n_js_strings['timer_minute'] = __('minute', 'event_espresso');
1479
+		EE_Registry::$i18n_js_strings['timer_second'] = __('second', 'event_espresso');
1480
+		EE_Registry::$i18n_js_strings['registration_expiration_notice'] = EED_Single_Page_Checkout::getRegistrationExpirationNotice();
1481
+		EE_Registry::$i18n_js_strings['ajax_submit'] = apply_filters(
1482
+			'FHEE__Single_Page_Checkout__translate_js_strings__ajax_submit',
1483
+			true
1484
+		);
1485
+		EE_Registry::$i18n_js_strings['session_extension'] = absint(
1486
+			apply_filters('FHEE__EE_Session__extend_expiration__seconds_added', 10 * MINUTE_IN_SECONDS)
1487
+		);
1488
+		EE_Registry::$i18n_js_strings['session_expiration'] = gmdate(
1489
+			'M d, Y H:i:s',
1490
+			EE_Registry::instance()->SSN->expiration() + (get_option('gmt_offset') * HOUR_IN_SECONDS)
1491
+		);
1492
+	}
1493
+
1494
+
1495
+
1496
+	/**
1497
+	 *    enqueue_styles_and_scripts
1498
+	 *
1499
+	 * @access        public
1500
+	 * @return        void
1501
+	 * @throws EE_Error
1502
+	 */
1503
+	public function enqueue_styles_and_scripts()
1504
+	{
1505
+		// load css
1506
+		wp_register_style(
1507
+			'single_page_checkout',
1508
+			SPCO_CSS_URL . 'single_page_checkout.css',
1509
+			array('espresso_default'),
1510
+			EVENT_ESPRESSO_VERSION
1511
+		);
1512
+		wp_enqueue_style('single_page_checkout');
1513
+		// load JS
1514
+		wp_register_script(
1515
+			'jquery_plugin',
1516
+			EE_THIRD_PARTY_URL . 'jquery	.plugin.min.js',
1517
+			array('jquery'),
1518
+			'1.0.1',
1519
+			true
1520
+		);
1521
+		wp_register_script(
1522
+			'jquery_countdown',
1523
+			EE_THIRD_PARTY_URL . 'jquery	.countdown.min.js',
1524
+			array('jquery_plugin'),
1525
+			'2.0.2',
1526
+			true
1527
+		);
1528
+		wp_register_script(
1529
+			'single_page_checkout',
1530
+			SPCO_JS_URL . 'single_page_checkout.js',
1531
+			array('espresso_core', 'underscore', 'ee_form_section_validation', 'jquery_countdown'),
1532
+			EVENT_ESPRESSO_VERSION,
1533
+			true
1534
+		);
1535
+		if ($this->checkout->registration_form instanceof EE_Form_Section_Proper) {
1536
+			$this->checkout->registration_form->enqueue_js();
1537
+		}
1538
+		if ($this->checkout->current_step->reg_form instanceof EE_Form_Section_Proper) {
1539
+			$this->checkout->current_step->reg_form->enqueue_js();
1540
+		}
1541
+		wp_enqueue_script('single_page_checkout');
1542
+		/**
1543
+		 * global action hook for enqueueing styles and scripts with
1544
+		 * spco calls.
1545
+		 */
1546
+		do_action('AHEE__EED_Single_Page_Checkout__enqueue_styles_and_scripts', $this);
1547
+		/**
1548
+		 * dynamic action hook for enqueueing styles and scripts with spco calls.
1549
+		 * The hook will end up being something like:
1550
+		 *      AHEE__EED_Single_Page_Checkout__enqueue_styles_and_scripts__attendee_information
1551
+		 */
1552
+		do_action(
1553
+			'AHEE__EED_Single_Page_Checkout__enqueue_styles_and_scripts__' . $this->checkout->current_step->slug(),
1554
+			$this
1555
+		);
1556
+	}
1557
+
1558
+
1559
+
1560
+	/**
1561
+	 *    display the Registration Single Page Checkout Form
1562
+	 *
1563
+	 * @access    private
1564
+	 * @return    void
1565
+	 * @throws EE_Error
1566
+	 */
1567
+	private function _display_spco_reg_form()
1568
+	{
1569
+		// if registering via the admin, just display the reg form for the current step
1570
+		if ($this->checkout->admin_request) {
1571
+			EE_Registry::instance()->REQ->add_output($this->checkout->current_step->display_reg_form());
1572
+		} else {
1573
+			// add powered by EE msg
1574
+			add_action('AHEE__SPCO__reg_form_footer', array('EED_Single_Page_Checkout', 'display_registration_footer'));
1575
+			$empty_cart = count(
1576
+				$this->checkout->transaction->registrations($this->checkout->reg_cache_where_params)
1577
+			) < 1;
1578
+			EE_Registry::$i18n_js_strings['empty_cart'] = $empty_cart;
1579
+			$cookies_not_set_msg = '';
1580
+			if ($empty_cart) {
1581
+				$cookies_not_set_msg = apply_filters(
1582
+					'FHEE__Single_Page_Checkout__display_spco_reg_form__cookies_not_set_msg',
1583
+					sprintf(
1584
+						__(
1585
+							'%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',
1586
+							'event_espresso'
1587
+						),
1588
+						'<div class="ee-attention hidden" id="ee-cookies-not-set-msg">',
1589
+						'</div>',
1590
+						'<h6 class="important-notice">',
1591
+						'</h6>',
1592
+						'<p>',
1593
+						'</p>',
1594
+						'<br />',
1595
+						'<a href="http://www.whatarecookies.com/enable.asp" target="_blank">',
1596
+						'</a>'
1597
+					)
1598
+				);
1599
+			}
1600
+			$this->checkout->registration_form = new EE_Form_Section_Proper(
1601
+				array(
1602
+					'name'            => 'single-page-checkout',
1603
+					'html_id'         => 'ee-single-page-checkout-dv',
1604
+					'layout_strategy' =>
1605
+						new EE_Template_Layout(
1606
+							array(
1607
+								'layout_template_file' => SPCO_TEMPLATES_PATH . 'registration_page_wrapper.template.php',
1608
+								'template_args'        => array(
1609
+									'empty_cart'              => $empty_cart,
1610
+									'revisit'                 => $this->checkout->revisit,
1611
+									'reg_steps'               => $this->checkout->reg_steps,
1612
+									'next_step'               => $this->checkout->next_step instanceof EE_SPCO_Reg_Step
1613
+										? $this->checkout->next_step->slug()
1614
+										: '',
1615
+									'empty_msg'               => apply_filters(
1616
+										'FHEE__Single_Page_Checkout__display_spco_reg_form__empty_msg',
1617
+										sprintf(
1618
+											__(
1619
+												'You need to %1$sReturn to Events list%2$sselect at least one event%3$s before you can proceed with the registration process.',
1620
+												'event_espresso'
1621
+											),
1622
+											'<a href="'
1623
+											. get_post_type_archive_link('espresso_events')
1624
+											. '" title="',
1625
+											'">',
1626
+											'</a>'
1627
+										)
1628
+									),
1629
+									'cookies_not_set_msg'     => $cookies_not_set_msg,
1630
+									'registration_time_limit' => $this->checkout->get_registration_time_limit(),
1631
+									'session_expiration'      => gmdate(
1632
+										'M d, Y H:i:s',
1633
+										EE_Registry::instance()->SSN->expiration()
1634
+										+ (get_option('gmt_offset') * HOUR_IN_SECONDS)
1635
+									),
1636
+								),
1637
+							)
1638
+						),
1639
+				)
1640
+			);
1641
+			// load template and add to output sent that gets filtered into the_content()
1642
+			EE_Registry::instance()->REQ->add_output($this->checkout->registration_form->get_html());
1643
+		}
1644
+	}
1645
+
1646
+
1647
+
1648
+	/**
1649
+	 *    add_extra_finalize_registration_inputs
1650
+	 *
1651
+	 * @access    public
1652
+	 * @param $next_step
1653
+	 * @internal  param string $label
1654
+	 * @return void
1655
+	 */
1656
+	public function add_extra_finalize_registration_inputs($next_step)
1657
+	{
1658
+		if ($next_step === 'finalize_registration') {
1659
+			echo '<div id="spco-extra-finalize_registration-inputs-dv"></div>';
1660
+		}
1661
+	}
1662
+
1663
+
1664
+
1665
+	/**
1666
+	 *    display_registration_footer
1667
+	 *
1668
+	 * @access    public
1669
+	 * @return    string
1670
+	 */
1671
+	public static function display_registration_footer()
1672
+	{
1673
+		if (
1674
+		apply_filters(
1675
+			'FHEE__EE_Front__Controller__show_reg_footer',
1676
+			EE_Registry::instance()->CFG->admin->show_reg_footer
1677
+		)
1678
+		) {
1679
+			add_filter(
1680
+				'FHEE__EEH_Template__powered_by_event_espresso__url',
1681
+				function ($url) {
1682
+					return apply_filters('FHEE__EE_Front_Controller__registration_footer__url', $url);
1683
+				}
1684
+			);
1685
+			echo apply_filters(
1686
+				'FHEE__EE_Front_Controller__display_registration_footer',
1687
+				\EEH_Template::powered_by_event_espresso(
1688
+					'',
1689
+					'espresso-registration-footer-dv',
1690
+					array('utm_content' => 'registration_checkout')
1691
+				)
1692
+			);
1693
+		}
1694
+		return '';
1695
+	}
1696
+
1697
+
1698
+
1699
+	/**
1700
+	 *    unlock_transaction
1701
+	 *
1702
+	 * @access    public
1703
+	 * @return    void
1704
+	 * @throws EE_Error
1705
+	 */
1706
+	public function unlock_transaction()
1707
+	{
1708
+		if ($this->checkout->transaction instanceof EE_Transaction) {
1709
+			$this->checkout->transaction->unlock();
1710
+		}
1711
+	}
1712
+
1713
+
1714
+
1715
+	/**
1716
+	 *        _setup_redirect
1717
+	 *
1718
+	 * @access    private
1719
+	 * @return void
1720
+	 */
1721
+	private function _setup_redirect()
1722
+	{
1723
+		if ($this->checkout->continue_reg && $this->checkout->next_step instanceof EE_SPCO_Reg_Step) {
1724
+			$this->checkout->redirect = true;
1725
+			if (empty($this->checkout->redirect_url)) {
1726
+				$this->checkout->redirect_url = $this->checkout->next_step->reg_step_url();
1727
+			}
1728
+			$this->checkout->redirect_url = apply_filters(
1729
+				'FHEE__EED_Single_Page_Checkout___setup_redirect__checkout_redirect_url',
1730
+				$this->checkout->redirect_url,
1731
+				$this->checkout
1732
+			);
1733
+		}
1734
+	}
1735
+
1736
+
1737
+
1738
+	/**
1739
+	 *   handle ajax message responses and redirects
1740
+	 *
1741
+	 * @access public
1742
+	 * @return void
1743
+	 * @throws EE_Error
1744
+	 */
1745
+	public function go_to_next_step()
1746
+	{
1747
+		if (EE_Registry::instance()->REQ->ajax) {
1748
+			// capture contents of output buffer we started earlier in the request, and insert into JSON response
1749
+			$this->checkout->json_response->set_unexpected_errors(ob_get_clean());
1750
+		}
1751
+		$this->unlock_transaction();
1752
+		// just return for these conditions
1753
+		if (
1754
+			$this->checkout->admin_request
1755
+			|| $this->checkout->action === 'redirect_form'
1756
+			|| $this->checkout->action === 'update_checkout'
1757
+		) {
1758
+			return;
1759
+		}
1760
+		// AJAX response
1761
+		$this->_handle_json_response();
1762
+		// redirect to next step or the Thank You page
1763
+		$this->_handle_html_redirects();
1764
+		// hmmm... must be something wrong, so let's just display the form again !
1765
+		$this->_display_spco_reg_form();
1766
+	}
1767
+
1768
+
1769
+
1770
+	/**
1771
+	 *   _handle_json_response
1772
+	 *
1773
+	 * @access protected
1774
+	 * @return void
1775
+	 */
1776
+	protected function _handle_json_response()
1777
+	{
1778
+		// if this is an ajax request
1779
+		if (EE_Registry::instance()->REQ->ajax) {
1780
+			// DEBUG LOG
1781
+			//$this->checkout->log(
1782
+			//	__CLASS__, __FUNCTION__, __LINE__,
1783
+			//	array(
1784
+			//		'json_response_redirect_url' => $this->checkout->json_response->redirect_url(),
1785
+			//		'redirect'                   => $this->checkout->redirect,
1786
+			//		'continue_reg'               => $this->checkout->continue_reg,
1787
+			//	)
1788
+			//);
1789
+			$this->checkout->json_response->set_registration_time_limit(
1790
+				$this->checkout->get_registration_time_limit()
1791
+			);
1792
+			$this->checkout->json_response->set_payment_amount($this->checkout->amount_owing);
1793
+			// just send the ajax (
1794
+			$json_response = apply_filters(
1795
+				'FHEE__EE_Single_Page_Checkout__JSON_response',
1796
+				$this->checkout->json_response
1797
+			);
1798
+			echo $json_response;
1799
+			exit();
1800
+		}
1801
+	}
1802
+
1803
+
1804
+
1805
+	/**
1806
+	 *   _handle_redirects
1807
+	 *
1808
+	 * @access protected
1809
+	 * @return void
1810
+	 */
1811
+	protected function _handle_html_redirects()
1812
+	{
1813
+		// going somewhere ?
1814
+		if ($this->checkout->redirect && ! empty($this->checkout->redirect_url)) {
1815
+			// store notices in a transient
1816
+			EE_Error::get_notices(false, true, true);
1817
+			// DEBUG LOG
1818
+			//$this->checkout->log(
1819
+			//	__CLASS__, __FUNCTION__, __LINE__,
1820
+			//	array(
1821
+			//		'headers_sent' => headers_sent(),
1822
+			//		'redirect_url'     => $this->checkout->redirect_url,
1823
+			//		'headers_list'    => headers_list(),
1824
+			//	)
1825
+			//);
1826
+			wp_safe_redirect($this->checkout->redirect_url);
1827
+			exit();
1828
+		}
1829
+	}
1830
+
1831
+
1832
+
1833
+	/**
1834
+	 *   set_checkout_anchor
1835
+	 *
1836
+	 * @access public
1837
+	 * @return void
1838
+	 */
1839
+	public function set_checkout_anchor()
1840
+	{
1841
+		echo '<a id="checkout" style="float: left; margin-left: -999em;"></a>';
1842
+	}
1843
+
1844
+	/**
1845
+	 *    getRegistrationExpirationNotice
1846
+	 *
1847
+	 * @since $VID:$
1848
+	 * @access    public
1849
+	 * @return    string
1850
+	 */
1851
+	public static function getRegistrationExpirationNotice()
1852
+	{
1853
+		return sprintf(
1854
+			__('%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 accept our apologies for any inconvenience this may have caused.%8$s',
1855
+				'event_espresso'),
1856
+			'<h4 class="important-notice">',
1857
+			'</h4>',
1858
+			'<br />',
1859
+			'<p>',
1860
+			'<a href="' . get_post_type_archive_link('espresso_events') . '" title="',
1861
+			'">',
1862
+			'</a>',
1863
+			'</p>'
1864
+		);
1865
+	}
1866 1866
 
1867 1867
 }
1868 1868
 // End of file EED_Single_Page_Checkout.module.php
Please login to merge, or discard this patch.
attendee_information/EE_SPCO_Reg_Step_Attendee_Information.class.php 2 patches
Indentation   +1335 added lines, -1335 removed lines patch added patch discarded remove patch
@@ -17,1343 +17,1343 @@
 block discarded – undo
17 17
 class EE_SPCO_Reg_Step_Attendee_Information extends EE_SPCO_Reg_Step
18 18
 {
19 19
 
20
-    /**
21
-     * @type bool $_print_copy_info
22
-     */
23
-    private $_print_copy_info = false;
24
-
25
-    /**
26
-     * @type array $_attendee_data
27
-     */
28
-    private $_attendee_data = array();
29
-
30
-    /**
31
-     * @type array $_required_questions
32
-     */
33
-    private $_required_questions = array();
34
-
35
-    /**
36
-     * @type array $_registration_answers
37
-     */
38
-    private $_registration_answers = array();
39
-
40
-
41
-    /**
42
-     *    class constructor
43
-     *
44
-     * @access    public
45
-     * @param    EE_Checkout $checkout
46
-     */
47
-    public function __construct(EE_Checkout $checkout)
48
-    {
49
-        $this->_slug     = 'attendee_information';
50
-        $this->_name     = esc_html__('Attendee Information', 'event_espresso');
51
-        $this->_template = SPCO_REG_STEPS_PATH . $this->_slug . DS . 'attendee_info_main.template.php';
52
-        $this->checkout  = $checkout;
53
-        $this->_reset_success_message();
54
-        $this->set_instructions(
55
-            esc_html__('Please answer the following registration questions before proceeding.', 'event_espresso')
56
-        );
57
-    }
58
-
59
-
60
-    public function translate_js_strings()
61
-    {
62
-        EE_Registry::$i18n_js_strings['required_field']            = esc_html__(
63
-            ' is a required question.',
64
-            'event_espresso'
65
-        );
66
-        EE_Registry::$i18n_js_strings['required_multi_field']      = esc_html__(
67
-            ' is a required question. Please enter a value for at least one of the options.',
68
-            'event_espresso'
69
-        );
70
-        EE_Registry::$i18n_js_strings['answer_required_questions'] = esc_html__(
71
-            'Please answer all required questions correctly before proceeding.',
72
-            'event_espresso'
73
-        );
74
-        EE_Registry::$i18n_js_strings['attendee_info_copied']      = sprintf(
75
-            esc_html__(
76
-                'The attendee information was successfully copied.%sPlease ensure the rest of the registration form is completed before proceeding.',
77
-                'event_espresso'
78
-            ),
79
-            '<br/>'
80
-        );
81
-        EE_Registry::$i18n_js_strings['attendee_info_copy_error']  = esc_html__(
82
-            'An unknown error occurred on the server while attempting to copy the attendee information. Please refresh the page and try again.',
83
-            'event_espresso'
84
-        );
85
-        EE_Registry::$i18n_js_strings['enter_valid_email']         = esc_html__(
86
-            'You must enter a valid email address.',
87
-            'event_espresso'
88
-        );
89
-        EE_Registry::$i18n_js_strings['valid_email_and_questions'] = esc_html__(
90
-            'You must enter a valid email address and answer all other required questions before you can proceed.',
91
-            'event_espresso'
92
-        );
93
-    }
94
-
95
-
96
-    public function enqueue_styles_and_scripts()
97
-    {
98
-    }
99
-
100
-
101
-    /**
102
-     * @return boolean
103
-     */
104
-    public function initialize_reg_step()
105
-    {
106
-        return true;
107
-    }
108
-
109
-
110
-    /**
111
-     * @return EE_Form_Section_Proper
112
-     * @throws EE_Error
113
-     * @throws InvalidArgumentException
114
-     * @throws \EventEspresso\core\exceptions\EntityNotFoundException
115
-     * @throws \EventEspresso\core\exceptions\InvalidDataTypeException
116
-     * @throws \EventEspresso\core\exceptions\InvalidInterfaceException
117
-     */
118
-    public function generate_reg_form()
119
-    {
120
-        $this->_print_copy_info = false;
121
-        $primary_registrant     = null;
122
-        // autoload Line_Item_Display classes
123
-        EEH_Autoloader::register_line_item_display_autoloaders();
124
-        $Line_Item_Display = new EE_Line_Item_Display();
125
-        // calculate taxes
126
-        $Line_Item_Display->display_line_item(
127
-            $this->checkout->cart->get_grand_total(),
128
-            array('set_tax_rate' => true)
129
-        );
130
-        /** @var $subsections EE_Form_Section_Proper[] */
131
-        $subsections   = array(
132
-            'default_hidden_inputs' => $this->reg_step_hidden_inputs(),
133
-        );
134
-        $template_args = array(
135
-            'revisit'       => $this->checkout->revisit,
136
-            'registrations' => array(),
137
-            'ticket_count'  => array(),
138
-        );
139
-        // grab the saved registrations from the transaction
140
-        $registrations = $this->checkout->transaction->registrations($this->checkout->reg_cache_where_params);
141
-        if ($registrations) {
142
-            foreach ($registrations as $registration) {
143
-                // can this registration be processed during this visit ?
144
-                if ($registration instanceof EE_Registration
145
-                    && $this->checkout->visit_allows_processing_of_this_registration($registration)
146
-                ) {
147
-                    $subsections[$registration->reg_url_link()] = $this->_registrations_reg_form($registration);
148
-                    if (! $this->checkout->admin_request) {
149
-                        $template_args['registrations'][$registration->reg_url_link()]    = $registration;
150
-                        $template_args['ticket_count'][$registration->ticket()->ID()]     = isset(
151
-                            $template_args['ticket_count'][$registration->ticket()->ID()]
152
-                        )
153
-                            ? $template_args['ticket_count'][$registration->ticket()->ID()] + 1
154
-                            : 1;
155
-                        $ticket_line_item = EEH_Line_Item::get_line_items_by_object_type_and_IDs(
156
-                            $this->checkout->cart->get_grand_total(),
157
-                            'Ticket',
158
-                            array($registration->ticket()->ID())
159
-                        );
160
-                        $ticket_line_item = is_array($ticket_line_item)
161
-                            ? reset($ticket_line_item)
162
-                            : $ticket_line_item;
163
-                        $template_args['ticket_line_item'][$registration->ticket()->ID()] =
164
-                            $Line_Item_Display->display_line_item($ticket_line_item);
165
-                    }
166
-                    if ($registration->is_primary_registrant()) {
167
-                        $primary_registrant = $registration->reg_url_link();
168
-                    }
169
-                }
170
-            }
171
-            // print_copy_info ?
172
-            if ($primary_registrant && ! $this->checkout->admin_request && count($registrations) > 1) {
173
-                // TODO: add admin option for toggling copy attendee info,
174
-                // then use that value to change $this->_print_copy_info
175
-                $copy_options['spco_copy_attendee_chk'] = $this->_print_copy_info
176
-                    ? $this->_copy_attendee_info_form()
177
-                    : $this->_auto_copy_attendee_info();
178
-                // generate hidden input
179
-                if (isset($subsections[$primary_registrant])
180
-                    && $subsections[$primary_registrant] instanceof EE_Form_Section_Proper
181
-                ) {
182
-                    $subsections[$primary_registrant]->add_subsections(
183
-                        $copy_options,
184
-                        'primary_registrant',
185
-                        false
186
-                    );
187
-                }
188
-            }
189
-        }
190
-
191
-        return new EE_Form_Section_Proper(
192
-            array(
193
-                'name'            => $this->reg_form_name(),
194
-                'html_id'         => $this->reg_form_name(),
195
-                'subsections'     => $subsections,
196
-                'layout_strategy' => $this->checkout->admin_request ?
197
-                    new EE_Div_Per_Section_Layout() :
198
-                    new EE_Template_Layout(
199
-                        array(
200
-                            'layout_template_file' => $this->_template, // layout_template
201
-                            'template_args'        => $template_args,
202
-                        )
203
-                    ),
204
-            )
205
-        );
206
-    }
207
-
208
-
209
-    /**
210
-     * @param EE_Registration $registration
211
-     * @return EE_Form_Section_Base
212
-     * @throws EE_Error
213
-     * @throws InvalidArgumentException
214
-     * @throws \EventEspresso\core\exceptions\EntityNotFoundException
215
-     * @throws \EventEspresso\core\exceptions\InvalidDataTypeException
216
-     * @throws \EventEspresso\core\exceptions\InvalidInterfaceException
217
-     */
218
-    private function _registrations_reg_form(EE_Registration $registration)
219
-    {
220
-        static $attendee_nmbr = 1;
221
-        $form_args = array();
222
-        // verify that registration has valid event
223
-        if ($registration->event() instanceof EE_Event) {
224
-            $question_groups = $registration->event()->question_groups(
225
-                apply_filters(
226
-                    'FHEE__EE_SPCO_Reg_Step_Attendee_Information___registrations_reg_form__question_groups_query_parameters',
227
-                    array(
228
-                        array(
229
-                            'Event.EVT_ID'                     => $registration->event()->ID(),
230
-                            'Event_Question_Group.EQG_primary' => $registration->count() === 1 ? true : false,
231
-                        ),
232
-                        'order_by' => array('QSG_order' => 'ASC'),
233
-                    ),
234
-                    $registration,
235
-                    $this
236
-                )
237
-            );
238
-            if ($question_groups) {
239
-                // array of params to pass to parent constructor
240
-                $form_args = array(
241
-                    'html_id'         => 'ee-registration-' . $registration->reg_url_link(),
242
-                    'html_class'      => 'ee-reg-form-attendee-dv',
243
-                    'html_style'      => $this->checkout->admin_request
244
-                        ? 'padding:0em 2em 1em; margin:3em 0 0; border:1px solid #ddd;'
245
-                        : '',
246
-                    'subsections'     => array(),
247
-                    'layout_strategy' => new EE_Fieldset_Section_Layout(
248
-                        array(
249
-                            'legend_class' => 'spco-attendee-lgnd smaller-text lt-grey-text',
250
-                            'legend_text'  => sprintf(__('Attendee %d', 'event_espresso'), $attendee_nmbr),
251
-                        )
252
-                    ),
253
-                );
254
-                foreach ($question_groups as $question_group) {
255
-                    if ($question_group instanceof EE_Question_Group) {
256
-                        $form_args['subsections'][$question_group->identifier()] = $this->_question_group_reg_form(
257
-                            $registration,
258
-                            $question_group
259
-                        );
260
-                    }
261
-                }
262
-                // add hidden input
263
-                $form_args['subsections']['additional_attendee_reg_info'] = $this->_additional_attendee_reg_info_input(
264
-                    $registration
265
-                );
266
-                // if we have question groups for additional attendees, then display the copy options
267
-                $this->_print_copy_info = $attendee_nmbr > 1 ? true : $this->_print_copy_info;
268
-                if ($registration->is_primary_registrant()) {
269
-                    // generate hidden input
270
-                    $form_args['subsections']['primary_registrant'] = $this->_additional_primary_registrant_inputs(
271
-                        $registration
272
-                    );
273
-                }
274
-            }
275
-        }
276
-        $attendee_nmbr++;
277
-        return ! empty($form_args) ? new EE_Form_Section_Proper($form_args) : new EE_Form_Section_HTML();
278
-    }
279
-
280
-
281
-    /**
282
-     * _additional_attendee_reg_info_input
283
-     *
284
-     * @access public
285
-     * @param EE_Registration $registration
286
-     * @param bool            $additional_attendee_reg_info
287
-     * @return    EE_Form_Input_Base
288
-     * @throws \EE_Error
289
-     */
290
-    private function _additional_attendee_reg_info_input(
291
-        EE_Registration $registration,
292
-        $additional_attendee_reg_info = true
293
-    ) {
294
-        // generate hidden input
295
-        return new EE_Hidden_Input(
296
-            array(
297
-                'html_id' => 'additional-attendee-reg-info-' . $registration->reg_url_link(),
298
-                'default' => $additional_attendee_reg_info,
299
-            )
300
-        );
301
-    }
302
-
303
-
304
-    /**
305
-     * @param EE_Registration   $registration
306
-     * @param EE_Question_Group $question_group
307
-     * @return EE_Form_Section_Proper
308
-     * @throws EE_Error
309
-     * @throws InvalidArgumentException
310
-     * @throws \EventEspresso\core\exceptions\InvalidDataTypeException
311
-     * @throws \EventEspresso\core\exceptions\InvalidInterfaceException
312
-     */
313
-    private function _question_group_reg_form(EE_Registration $registration, EE_Question_Group $question_group)
314
-    {
315
-        // array of params to pass to parent constructor
316
-        $form_args = array(
317
-            'html_id'         => 'ee-reg-form-qstn-grp-' . $question_group->identifier() . '-' . $registration->ID(),
318
-            'html_class'      => $this->checkout->admin_request
319
-                ? 'form-table ee-reg-form-qstn-grp-dv'
320
-                : 'ee-reg-form-qstn-grp-dv',
321
-            'html_label_id'   => 'ee-reg-form-qstn-grp-' . $question_group->identifier() .  '-' . $registration->ID() . '-lbl',
322
-            'subsections'     => array(
323
-                'reg_form_qstn_grp_hdr' => $this->_question_group_header($question_group),
324
-            ),
325
-            'layout_strategy' => $this->checkout->admin_request
326
-                ? new EE_Admin_Two_Column_Layout()
327
-                : new EE_Div_Per_Section_Layout(),
328
-        );
329
-        // where params
330
-        $query_params = array('QST_deleted' => 0);
331
-        // don't load admin only questions on the frontend
332
-        if (! $this->checkout->admin_request) {
333
-            $query_params['QST_admin_only'] = array('!=', true);
334
-        }
335
-        $questions = $question_group->get_many_related(
336
-            'Question',
337
-            apply_filters(
338
-                'FHEE__EE_SPCO_Reg_Step_Attendee_Information___question_group_reg_form__related_questions_query_params',
339
-                array(
340
-                    $query_params,
341
-                    'order_by' => array(
342
-                        'Question_Group_Question.QGQ_order' => 'ASC',
343
-                    ),
344
-                ),
345
-                $question_group,
346
-                $registration,
347
-                $this
348
-            )
349
-        );
350
-        // filter for additional content before questions
351
-        $form_args['subsections']['reg_form_questions_before'] = new EE_Form_Section_HTML(
352
-            apply_filters(
353
-                'FHEE__EEH_Form_Fields__generate_question_groups_html__before_question_group_questions',
354
-                '',
355
-                $registration,
356
-                $question_group,
357
-                $this
358
-            )
359
-        );
360
-        // loop thru questions
361
-        foreach ($questions as $question) {
362
-            if ($question instanceof EE_Question) {
363
-                $identifier                            = $question->is_system_question()
364
-                    ? $question->system_ID()
365
-                    : $question->ID();
366
-                $form_args['subsections'][$identifier] = $this->reg_form_question($registration, $question);
367
-            }
368
-        }
369
-        $form_args['subsections'] = apply_filters(
370
-            'FHEE__EE_SPCO_Reg_Step_Attendee_Information__question_group_reg_form__subsections_array',
371
-            $form_args['subsections'],
372
-            $registration,
373
-            $question_group,
374
-            $this
375
-        );
376
-        // filter for additional content after questions
377
-        $form_args['subsections']['reg_form_questions_after'] = new EE_Form_Section_HTML(
378
-            apply_filters(
379
-                'FHEE__EEH_Form_Fields__generate_question_groups_html__after_question_group_questions',
380
-                '',
381
-                $registration,
382
-                $question_group,
383
-                $this
384
-            )
385
-        );
20
+	/**
21
+	 * @type bool $_print_copy_info
22
+	 */
23
+	private $_print_copy_info = false;
24
+
25
+	/**
26
+	 * @type array $_attendee_data
27
+	 */
28
+	private $_attendee_data = array();
29
+
30
+	/**
31
+	 * @type array $_required_questions
32
+	 */
33
+	private $_required_questions = array();
34
+
35
+	/**
36
+	 * @type array $_registration_answers
37
+	 */
38
+	private $_registration_answers = array();
39
+
40
+
41
+	/**
42
+	 *    class constructor
43
+	 *
44
+	 * @access    public
45
+	 * @param    EE_Checkout $checkout
46
+	 */
47
+	public function __construct(EE_Checkout $checkout)
48
+	{
49
+		$this->_slug     = 'attendee_information';
50
+		$this->_name     = esc_html__('Attendee Information', 'event_espresso');
51
+		$this->_template = SPCO_REG_STEPS_PATH . $this->_slug . DS . 'attendee_info_main.template.php';
52
+		$this->checkout  = $checkout;
53
+		$this->_reset_success_message();
54
+		$this->set_instructions(
55
+			esc_html__('Please answer the following registration questions before proceeding.', 'event_espresso')
56
+		);
57
+	}
58
+
59
+
60
+	public function translate_js_strings()
61
+	{
62
+		EE_Registry::$i18n_js_strings['required_field']            = esc_html__(
63
+			' is a required question.',
64
+			'event_espresso'
65
+		);
66
+		EE_Registry::$i18n_js_strings['required_multi_field']      = esc_html__(
67
+			' is a required question. Please enter a value for at least one of the options.',
68
+			'event_espresso'
69
+		);
70
+		EE_Registry::$i18n_js_strings['answer_required_questions'] = esc_html__(
71
+			'Please answer all required questions correctly before proceeding.',
72
+			'event_espresso'
73
+		);
74
+		EE_Registry::$i18n_js_strings['attendee_info_copied']      = sprintf(
75
+			esc_html__(
76
+				'The attendee information was successfully copied.%sPlease ensure the rest of the registration form is completed before proceeding.',
77
+				'event_espresso'
78
+			),
79
+			'<br/>'
80
+		);
81
+		EE_Registry::$i18n_js_strings['attendee_info_copy_error']  = esc_html__(
82
+			'An unknown error occurred on the server while attempting to copy the attendee information. Please refresh the page and try again.',
83
+			'event_espresso'
84
+		);
85
+		EE_Registry::$i18n_js_strings['enter_valid_email']         = esc_html__(
86
+			'You must enter a valid email address.',
87
+			'event_espresso'
88
+		);
89
+		EE_Registry::$i18n_js_strings['valid_email_and_questions'] = esc_html__(
90
+			'You must enter a valid email address and answer all other required questions before you can proceed.',
91
+			'event_espresso'
92
+		);
93
+	}
94
+
95
+
96
+	public function enqueue_styles_and_scripts()
97
+	{
98
+	}
99
+
100
+
101
+	/**
102
+	 * @return boolean
103
+	 */
104
+	public function initialize_reg_step()
105
+	{
106
+		return true;
107
+	}
108
+
109
+
110
+	/**
111
+	 * @return EE_Form_Section_Proper
112
+	 * @throws EE_Error
113
+	 * @throws InvalidArgumentException
114
+	 * @throws \EventEspresso\core\exceptions\EntityNotFoundException
115
+	 * @throws \EventEspresso\core\exceptions\InvalidDataTypeException
116
+	 * @throws \EventEspresso\core\exceptions\InvalidInterfaceException
117
+	 */
118
+	public function generate_reg_form()
119
+	{
120
+		$this->_print_copy_info = false;
121
+		$primary_registrant     = null;
122
+		// autoload Line_Item_Display classes
123
+		EEH_Autoloader::register_line_item_display_autoloaders();
124
+		$Line_Item_Display = new EE_Line_Item_Display();
125
+		// calculate taxes
126
+		$Line_Item_Display->display_line_item(
127
+			$this->checkout->cart->get_grand_total(),
128
+			array('set_tax_rate' => true)
129
+		);
130
+		/** @var $subsections EE_Form_Section_Proper[] */
131
+		$subsections   = array(
132
+			'default_hidden_inputs' => $this->reg_step_hidden_inputs(),
133
+		);
134
+		$template_args = array(
135
+			'revisit'       => $this->checkout->revisit,
136
+			'registrations' => array(),
137
+			'ticket_count'  => array(),
138
+		);
139
+		// grab the saved registrations from the transaction
140
+		$registrations = $this->checkout->transaction->registrations($this->checkout->reg_cache_where_params);
141
+		if ($registrations) {
142
+			foreach ($registrations as $registration) {
143
+				// can this registration be processed during this visit ?
144
+				if ($registration instanceof EE_Registration
145
+					&& $this->checkout->visit_allows_processing_of_this_registration($registration)
146
+				) {
147
+					$subsections[$registration->reg_url_link()] = $this->_registrations_reg_form($registration);
148
+					if (! $this->checkout->admin_request) {
149
+						$template_args['registrations'][$registration->reg_url_link()]    = $registration;
150
+						$template_args['ticket_count'][$registration->ticket()->ID()]     = isset(
151
+							$template_args['ticket_count'][$registration->ticket()->ID()]
152
+						)
153
+							? $template_args['ticket_count'][$registration->ticket()->ID()] + 1
154
+							: 1;
155
+						$ticket_line_item = EEH_Line_Item::get_line_items_by_object_type_and_IDs(
156
+							$this->checkout->cart->get_grand_total(),
157
+							'Ticket',
158
+							array($registration->ticket()->ID())
159
+						);
160
+						$ticket_line_item = is_array($ticket_line_item)
161
+							? reset($ticket_line_item)
162
+							: $ticket_line_item;
163
+						$template_args['ticket_line_item'][$registration->ticket()->ID()] =
164
+							$Line_Item_Display->display_line_item($ticket_line_item);
165
+					}
166
+					if ($registration->is_primary_registrant()) {
167
+						$primary_registrant = $registration->reg_url_link();
168
+					}
169
+				}
170
+			}
171
+			// print_copy_info ?
172
+			if ($primary_registrant && ! $this->checkout->admin_request && count($registrations) > 1) {
173
+				// TODO: add admin option for toggling copy attendee info,
174
+				// then use that value to change $this->_print_copy_info
175
+				$copy_options['spco_copy_attendee_chk'] = $this->_print_copy_info
176
+					? $this->_copy_attendee_info_form()
177
+					: $this->_auto_copy_attendee_info();
178
+				// generate hidden input
179
+				if (isset($subsections[$primary_registrant])
180
+					&& $subsections[$primary_registrant] instanceof EE_Form_Section_Proper
181
+				) {
182
+					$subsections[$primary_registrant]->add_subsections(
183
+						$copy_options,
184
+						'primary_registrant',
185
+						false
186
+					);
187
+				}
188
+			}
189
+		}
190
+
191
+		return new EE_Form_Section_Proper(
192
+			array(
193
+				'name'            => $this->reg_form_name(),
194
+				'html_id'         => $this->reg_form_name(),
195
+				'subsections'     => $subsections,
196
+				'layout_strategy' => $this->checkout->admin_request ?
197
+					new EE_Div_Per_Section_Layout() :
198
+					new EE_Template_Layout(
199
+						array(
200
+							'layout_template_file' => $this->_template, // layout_template
201
+							'template_args'        => $template_args,
202
+						)
203
+					),
204
+			)
205
+		);
206
+	}
207
+
208
+
209
+	/**
210
+	 * @param EE_Registration $registration
211
+	 * @return EE_Form_Section_Base
212
+	 * @throws EE_Error
213
+	 * @throws InvalidArgumentException
214
+	 * @throws \EventEspresso\core\exceptions\EntityNotFoundException
215
+	 * @throws \EventEspresso\core\exceptions\InvalidDataTypeException
216
+	 * @throws \EventEspresso\core\exceptions\InvalidInterfaceException
217
+	 */
218
+	private function _registrations_reg_form(EE_Registration $registration)
219
+	{
220
+		static $attendee_nmbr = 1;
221
+		$form_args = array();
222
+		// verify that registration has valid event
223
+		if ($registration->event() instanceof EE_Event) {
224
+			$question_groups = $registration->event()->question_groups(
225
+				apply_filters(
226
+					'FHEE__EE_SPCO_Reg_Step_Attendee_Information___registrations_reg_form__question_groups_query_parameters',
227
+					array(
228
+						array(
229
+							'Event.EVT_ID'                     => $registration->event()->ID(),
230
+							'Event_Question_Group.EQG_primary' => $registration->count() === 1 ? true : false,
231
+						),
232
+						'order_by' => array('QSG_order' => 'ASC'),
233
+					),
234
+					$registration,
235
+					$this
236
+				)
237
+			);
238
+			if ($question_groups) {
239
+				// array of params to pass to parent constructor
240
+				$form_args = array(
241
+					'html_id'         => 'ee-registration-' . $registration->reg_url_link(),
242
+					'html_class'      => 'ee-reg-form-attendee-dv',
243
+					'html_style'      => $this->checkout->admin_request
244
+						? 'padding:0em 2em 1em; margin:3em 0 0; border:1px solid #ddd;'
245
+						: '',
246
+					'subsections'     => array(),
247
+					'layout_strategy' => new EE_Fieldset_Section_Layout(
248
+						array(
249
+							'legend_class' => 'spco-attendee-lgnd smaller-text lt-grey-text',
250
+							'legend_text'  => sprintf(__('Attendee %d', 'event_espresso'), $attendee_nmbr),
251
+						)
252
+					),
253
+				);
254
+				foreach ($question_groups as $question_group) {
255
+					if ($question_group instanceof EE_Question_Group) {
256
+						$form_args['subsections'][$question_group->identifier()] = $this->_question_group_reg_form(
257
+							$registration,
258
+							$question_group
259
+						);
260
+					}
261
+				}
262
+				// add hidden input
263
+				$form_args['subsections']['additional_attendee_reg_info'] = $this->_additional_attendee_reg_info_input(
264
+					$registration
265
+				);
266
+				// if we have question groups for additional attendees, then display the copy options
267
+				$this->_print_copy_info = $attendee_nmbr > 1 ? true : $this->_print_copy_info;
268
+				if ($registration->is_primary_registrant()) {
269
+					// generate hidden input
270
+					$form_args['subsections']['primary_registrant'] = $this->_additional_primary_registrant_inputs(
271
+						$registration
272
+					);
273
+				}
274
+			}
275
+		}
276
+		$attendee_nmbr++;
277
+		return ! empty($form_args) ? new EE_Form_Section_Proper($form_args) : new EE_Form_Section_HTML();
278
+	}
279
+
280
+
281
+	/**
282
+	 * _additional_attendee_reg_info_input
283
+	 *
284
+	 * @access public
285
+	 * @param EE_Registration $registration
286
+	 * @param bool            $additional_attendee_reg_info
287
+	 * @return    EE_Form_Input_Base
288
+	 * @throws \EE_Error
289
+	 */
290
+	private function _additional_attendee_reg_info_input(
291
+		EE_Registration $registration,
292
+		$additional_attendee_reg_info = true
293
+	) {
294
+		// generate hidden input
295
+		return new EE_Hidden_Input(
296
+			array(
297
+				'html_id' => 'additional-attendee-reg-info-' . $registration->reg_url_link(),
298
+				'default' => $additional_attendee_reg_info,
299
+			)
300
+		);
301
+	}
302
+
303
+
304
+	/**
305
+	 * @param EE_Registration   $registration
306
+	 * @param EE_Question_Group $question_group
307
+	 * @return EE_Form_Section_Proper
308
+	 * @throws EE_Error
309
+	 * @throws InvalidArgumentException
310
+	 * @throws \EventEspresso\core\exceptions\InvalidDataTypeException
311
+	 * @throws \EventEspresso\core\exceptions\InvalidInterfaceException
312
+	 */
313
+	private function _question_group_reg_form(EE_Registration $registration, EE_Question_Group $question_group)
314
+	{
315
+		// array of params to pass to parent constructor
316
+		$form_args = array(
317
+			'html_id'         => 'ee-reg-form-qstn-grp-' . $question_group->identifier() . '-' . $registration->ID(),
318
+			'html_class'      => $this->checkout->admin_request
319
+				? 'form-table ee-reg-form-qstn-grp-dv'
320
+				: 'ee-reg-form-qstn-grp-dv',
321
+			'html_label_id'   => 'ee-reg-form-qstn-grp-' . $question_group->identifier() .  '-' . $registration->ID() . '-lbl',
322
+			'subsections'     => array(
323
+				'reg_form_qstn_grp_hdr' => $this->_question_group_header($question_group),
324
+			),
325
+			'layout_strategy' => $this->checkout->admin_request
326
+				? new EE_Admin_Two_Column_Layout()
327
+				: new EE_Div_Per_Section_Layout(),
328
+		);
329
+		// where params
330
+		$query_params = array('QST_deleted' => 0);
331
+		// don't load admin only questions on the frontend
332
+		if (! $this->checkout->admin_request) {
333
+			$query_params['QST_admin_only'] = array('!=', true);
334
+		}
335
+		$questions = $question_group->get_many_related(
336
+			'Question',
337
+			apply_filters(
338
+				'FHEE__EE_SPCO_Reg_Step_Attendee_Information___question_group_reg_form__related_questions_query_params',
339
+				array(
340
+					$query_params,
341
+					'order_by' => array(
342
+						'Question_Group_Question.QGQ_order' => 'ASC',
343
+					),
344
+				),
345
+				$question_group,
346
+				$registration,
347
+				$this
348
+			)
349
+		);
350
+		// filter for additional content before questions
351
+		$form_args['subsections']['reg_form_questions_before'] = new EE_Form_Section_HTML(
352
+			apply_filters(
353
+				'FHEE__EEH_Form_Fields__generate_question_groups_html__before_question_group_questions',
354
+				'',
355
+				$registration,
356
+				$question_group,
357
+				$this
358
+			)
359
+		);
360
+		// loop thru questions
361
+		foreach ($questions as $question) {
362
+			if ($question instanceof EE_Question) {
363
+				$identifier                            = $question->is_system_question()
364
+					? $question->system_ID()
365
+					: $question->ID();
366
+				$form_args['subsections'][$identifier] = $this->reg_form_question($registration, $question);
367
+			}
368
+		}
369
+		$form_args['subsections'] = apply_filters(
370
+			'FHEE__EE_SPCO_Reg_Step_Attendee_Information__question_group_reg_form__subsections_array',
371
+			$form_args['subsections'],
372
+			$registration,
373
+			$question_group,
374
+			$this
375
+		);
376
+		// filter for additional content after questions
377
+		$form_args['subsections']['reg_form_questions_after'] = new EE_Form_Section_HTML(
378
+			apply_filters(
379
+				'FHEE__EEH_Form_Fields__generate_question_groups_html__after_question_group_questions',
380
+				'',
381
+				$registration,
382
+				$question_group,
383
+				$this
384
+			)
385
+		);
386 386
 //		d( $form_args );
387
-        $question_group_reg_form = new EE_Form_Section_Proper($form_args);
388
-        return apply_filters(
389
-            'FHEE__EE_SPCO_Reg_Step_Attendee_Information___question_group_reg_form__question_group_reg_form',
390
-            $question_group_reg_form,
391
-            $registration,
392
-            $question_group,
393
-            $this
394
-        );
395
-    }
396
-
397
-
398
-    /**
399
-     * @access public
400
-     * @param EE_Question_Group $question_group
401
-     * @return    EE_Form_Section_HTML
402
-     */
403
-    private function _question_group_header(EE_Question_Group $question_group)
404
-    {
405
-        $html = '';
406
-        // group_name
407
-        if ($question_group->show_group_name() && $question_group->name() !== '') {
408
-            if ($this->checkout->admin_request) {
409
-                $html .= EEH_HTML::br();
410
-                $html .= EEH_HTML::h3(
411
-                    $question_group->name(),
412
-                    '',
413
-                    'ee-reg-form-qstn-grp-title title',
414
-                    'font-size: 1.3em; padding-left:0;'
415
-                );
416
-            } else {
417
-                $html .= EEH_HTML::h4(
418
-                    $question_group->name(),
419
-                    '',
420
-                    'ee-reg-form-qstn-grp-title section-title'
421
-                );
422
-            }
423
-        }
424
-        // group_desc
425
-        if ($question_group->show_group_desc() && $question_group->desc() !== '') {
426
-            $html .= EEH_HTML::p(
427
-                $question_group->desc(),
428
-                '',
429
-                $this->checkout->admin_request
430
-                    ? 'ee-reg-form-qstn-grp-desc-pg'
431
-                    : 'ee-reg-form-qstn-grp-desc-pg small-text lt-grey-text'
432
-            );
433
-        }
434
-        return new EE_Form_Section_HTML($html);
435
-    }
436
-
437
-
438
-    /**
439
-     * @access public
440
-     * @return    EE_Form_Section_Proper
441
-     * @throws \EE_Error
442
-     */
443
-    private function _copy_attendee_info_form()
444
-    {
445
-        // array of params to pass to parent constructor
446
-        return new EE_Form_Section_Proper(
447
-            array(
448
-                'subsections'     => $this->_copy_attendee_info_inputs(),
449
-                'layout_strategy' => new EE_Template_Layout(
450
-                    array(
451
-                        'layout_template_file'     => SPCO_REG_STEPS_PATH
452
-                                                      . $this->_slug
453
-                                                      . DS
454
-                                                      . 'copy_attendee_info.template.php',
455
-                        'begin_template_file'      => null,
456
-                        'input_template_file'      => null,
457
-                        'subsection_template_file' => null,
458
-                        'end_template_file'        => null,
459
-                    )
460
-                ),
461
-            )
462
-        );
463
-    }
464
-
465
-
466
-    /**
467
-     * _auto_copy_attendee_info
468
-     *
469
-     * @access public
470
-     * @return EE_Form_Section_HTML
471
-     */
472
-    private function _auto_copy_attendee_info()
473
-    {
474
-        return new EE_Form_Section_HTML(
475
-            EEH_Template::locate_template(
476
-                SPCO_REG_STEPS_PATH . $this->_slug . DS . '_auto_copy_attendee_info.template.php',
477
-                apply_filters(
478
-                    'FHEE__EE_SPCO_Reg_Step_Attendee_Information__auto_copy_attendee_info__template_args',
479
-                    array()
480
-                ),
481
-                true,
482
-                true
483
-            )
484
-        );
485
-    }
486
-
487
-
488
-    /**
489
-     * _copy_attendee_info_inputs
490
-     *
491
-     * @access public
492
-     * @return array
493
-     * @throws \EE_Error
494
-     */
495
-    private function _copy_attendee_info_inputs()
496
-    {
497
-        $copy_attendee_info_inputs = array();
498
-        $prev_ticket               = null;
499
-        // grab the saved registrations from the transaction
500
-        $registrations = $this->checkout->transaction->registrations($this->checkout->reg_cache_where_params);
501
-        foreach ($registrations as $registration) {
502
-            // for all  attendees other than the primary attendee
503
-            if ($registration instanceof EE_Registration && ! $registration->is_primary_registrant()) {
504
-                // if this is a new ticket OR if this is the very first additional attendee after the primary attendee
505
-                if ($registration->ticket()->ID() !== $prev_ticket) {
506
-                    $item_name = $registration->ticket()->name();
507
-                    $item_name .= $registration->ticket()->description() !== ''
508
-                        ? ' - ' . $registration->ticket()->description()
509
-                        : '';
510
-                    $copy_attendee_info_inputs['spco_copy_attendee_chk[ticket-' . $registration->ticket()->ID() . ']'] =
511
-                        new EE_Form_Section_HTML(
512
-                            '<h6 class="spco-copy-attendee-event-hdr">' . $item_name . '</h6>'
513
-                        );
514
-                    $prev_ticket = $registration->ticket()->ID();
515
-                }
516
-
517
-                $copy_attendee_info_inputs['spco_copy_attendee_chk[' . $registration->ID() . ']'] =
518
-                    new EE_Checkbox_Multi_Input(
519
-                        array(
520
-                            $registration->ID() => sprintf(
521
-                                esc_html__('Attendee #%s', 'event_espresso'),
522
-                                $registration->count()
523
-                            ),
524
-                        ),
525
-                        array(
526
-                            'html_id'                 => 'spco-copy-attendee-chk-' . $registration->reg_url_link(),
527
-                            'html_class'              => 'spco-copy-attendee-chk ee-do-not-validate',
528
-                            'display_html_label_text' => false,
529
-                        )
530
-                    );
531
-            }
532
-        }
533
-        return $copy_attendee_info_inputs;
534
-    }
535
-
536
-
537
-    /**
538
-     * _additional_primary_registrant_inputs
539
-     *
540
-     * @access public
541
-     * @param EE_Registration $registration
542
-     * @return    EE_Form_Input_Base
543
-     * @throws \EE_Error
544
-     */
545
-    private function _additional_primary_registrant_inputs(EE_Registration $registration)
546
-    {
547
-        // generate hidden input
548
-        return new EE_Hidden_Input(
549
-            array(
550
-                'html_id' => 'primary_registrant',
551
-                'default' => $registration->reg_url_link(),
552
-            )
553
-        );
554
-    }
555
-
556
-
557
-    /**
558
-     * @access public
559
-     * @param EE_Registration $registration
560
-     * @param EE_Question     $question
561
-     * @return EE_Form_Input_Base
562
-     * @throws EE_Error
563
-     * @throws InvalidArgumentException
564
-     * @throws \EventEspresso\core\exceptions\InvalidDataTypeException
565
-     * @throws \EventEspresso\core\exceptions\InvalidInterfaceException
566
-     */
567
-    public function reg_form_question(EE_Registration $registration, EE_Question $question)
568
-    {
569
-
570
-        // if this question was for an attendee detail, then check for that answer
571
-        $answer_value = EEM_Answer::instance()->get_attendee_property_answer_value(
572
-            $registration,
573
-            $question->system_ID()
574
-        );
575
-        $answer       = $answer_value === null
576
-            ? EEM_Answer::instance()->get_one(
577
-                array(array('QST_ID' => $question->ID(), 'REG_ID' => $registration->ID()))
578
-            )
579
-            : null;
580
-        // if NOT returning to edit an existing registration
581
-        // OR if this question is for an attendee property
582
-        // OR we still don't have an EE_Answer object
583
-        if ($answer_value || ! $answer instanceof EE_Answer || ! $registration->reg_url_link()) {
584
-            // create an EE_Answer object for storing everything in
585
-            $answer = EE_Answer::new_instance(array(
586
-                'QST_ID' => $question->ID(),
587
-                'REG_ID' => $registration->ID(),
588
-            ));
589
-        }
590
-        // verify instance
591
-        if ($answer instanceof EE_Answer) {
592
-            if (! empty($answer_value)) {
593
-                $answer->set('ANS_value', $answer_value);
594
-            }
595
-            $answer->cache('Question', $question);
596
-            //remember system ID had a bug where sometimes it could be null
597
-            $answer_cache_id = $question->is_system_question()
598
-                ? $question->system_ID() . '-' . $registration->reg_url_link()
599
-                : $question->ID() . '-' . $registration->reg_url_link();
600
-            $registration->cache('Answer', $answer, $answer_cache_id);
601
-        }
602
-        return $this->_generate_question_input($registration, $question, $answer);
603
-    }
604
-
605
-
606
-    /**
607
-     * @param EE_Registration $registration
608
-     * @param EE_Question     $question
609
-     * @param                 mixed EE_Answer|NULL      $answer
610
-     * @return EE_Form_Input_Base
611
-     * @throws \EE_Error
612
-     */
613
-    private function _generate_question_input(EE_Registration $registration, EE_Question $question, $answer)
614
-    {
615
-        $identifier                             = $question->is_system_question()
616
-            ? $question->system_ID()
617
-            : $question->ID();
618
-        $this->_required_questions[$identifier] = $question->required() ? true : false;
619
-        add_filter(
620
-            'FHEE__EE_Question__generate_form_input__country_options',
621
-            array($this, 'use_cached_countries_for_form_input'),
622
-            10,
623
-            4
624
-        );
625
-        add_filter(
626
-            'FHEE__EE_Question__generate_form_input__state_options',
627
-            array($this, 'use_cached_states_for_form_input'),
628
-            10,
629
-            4
630
-        );
631
-        $input_constructor_args                  = array(
632
-            'html_name'        => 'ee_reg_qstn[' . $registration->ID() . '][' . $identifier . ']',
633
-            'html_id'          => 'ee_reg_qstn-' . $registration->ID() . '-' . $identifier,
634
-            'html_class'       => 'ee-reg-qstn ee-reg-qstn-' . $identifier,
635
-            'html_label_id'    => 'ee_reg_qstn-' . $registration->ID() . '-' . $identifier,
636
-            'html_label_class' => 'ee-reg-qstn',
637
-        );
638
-        $input_constructor_args['html_label_id'] .= '-lbl';
639
-        if ($answer instanceof EE_Answer && $answer->ID()) {
640
-            $input_constructor_args['html_name']     .= '[' . $answer->ID() . ']';
641
-            $input_constructor_args['html_id']       .= '-' . $answer->ID();
642
-            $input_constructor_args['html_label_id'] .= '-' . $answer->ID();
643
-        }
644
-        $form_input = $question->generate_form_input(
645
-            $registration,
646
-            $answer,
647
-            $input_constructor_args
648
-        );
649
-        remove_filter(
650
-            'FHEE__EE_Question__generate_form_input__country_options',
651
-            array($this, 'use_cached_countries_for_form_input')
652
-        );
653
-        remove_filter(
654
-            'FHEE__EE_Question__generate_form_input__state_options',
655
-            array($this, 'use_cached_states_for_form_input')
656
-        );
657
-        return $form_input;
658
-    }
659
-
660
-
661
-    /**
662
-     * Gets the list of countries for the form input
663
-     *
664
-     * @param array|null       $countries_list
665
-     * @param \EE_Question     $question
666
-     * @param \EE_Registration $registration
667
-     * @param \EE_Answer       $answer
668
-     * @return array 2d keys are country IDs, values are their names
669
-     * @throws EE_Error
670
-     * @throws InvalidArgumentException
671
-     * @throws \EventEspresso\core\exceptions\InvalidDataTypeException
672
-     * @throws \EventEspresso\core\exceptions\InvalidInterfaceException
673
-     */
674
-    public function use_cached_countries_for_form_input(
675
-        $countries_list,
676
-        \EE_Question $question = null,
677
-        \EE_Registration $registration = null,
678
-        \EE_Answer $answer = null
679
-    ) {
680
-        $country_options = array('' => '');
681
-        // get possibly cached list of countries
682
-        $countries = $this->checkout->action === 'process_reg_step'
683
-            ? EEM_Country::instance()->get_all_countries()
684
-            : EEM_Country::instance()->get_all_active_countries();
685
-        if (! empty($countries)) {
686
-            foreach ($countries as $country) {
687
-                if ($country instanceof EE_Country) {
688
-                    $country_options[$country->ID()] = $country->name();
689
-                }
690
-            }
691
-        }
692
-        if ($question instanceof EE_Question
693
-            && $registration instanceof EE_Registration) {
694
-            $answer = EEM_Answer::instance()->get_one(
695
-                array(array('QST_ID' => $question->ID(), 'REG_ID' => $registration->ID()))
696
-            );
697
-        } else {
698
-            $answer = EE_Answer::new_instance();
699
-        }
700
-        $country_options = apply_filters(
701
-            'FHEE__EE_SPCO_Reg_Step_Attendee_Information___generate_question_input__country_options',
702
-            $country_options,
703
-            $this,
704
-            $registration,
705
-            $question,
706
-            $answer
707
-        );
708
-        return $country_options;
709
-    }
710
-
711
-
712
-    /**
713
-     * Gets the list of states for the form input
714
-     *
715
-     * @param array|null       $states_list
716
-     * @param \EE_Question     $question
717
-     * @param \EE_Registration $registration
718
-     * @param \EE_Answer       $answer
719
-     * @return array 2d keys are state IDs, values are their names
720
-     * @throws EE_Error
721
-     * @throws InvalidArgumentException
722
-     * @throws \EventEspresso\core\exceptions\InvalidDataTypeException
723
-     * @throws \EventEspresso\core\exceptions\InvalidInterfaceException
724
-     */
725
-    public function use_cached_states_for_form_input(
726
-        $states_list,
727
-        \EE_Question $question = null,
728
-        \EE_Registration $registration = null,
729
-        \EE_Answer $answer = null
730
-    ) {
731
-        $state_options = array('' => array('' => ''));
732
-        $states        = $this->checkout->action === 'process_reg_step'
733
-            ? EEM_State::instance()->get_all_states()
734
-            : EEM_State::instance()->get_all_active_states();
735
-        if (! empty($states)) {
736
-            foreach ($states as $state) {
737
-                if ($state instanceof EE_State) {
738
-                    $state_options[$state->country()->name()][$state->ID()] = $state->name();
739
-                }
740
-            }
741
-        }
742
-        $state_options = apply_filters(
743
-            'FHEE__EE_SPCO_Reg_Step_Attendee_Information___generate_question_input__state_options',
744
-            $state_options,
745
-            $this,
746
-            $registration,
747
-            $question,
748
-            $answer
749
-        );
750
-        return $state_options;
751
-    }
752
-
753
-
754
-
755
-
756
-
757
-
758
-    /********************************************************************************************************/
759
-    /****************************************  PROCESS REG STEP  ****************************************/
760
-    /********************************************************************************************************/
761
-    /**
762
-     * @return bool
763
-     * @throws EE_Error
764
-     * @throws InvalidArgumentException
765
-     * @throws ReflectionException
766
-     * @throws RuntimeException
767
-     * @throws \EventEspresso\core\exceptions\InvalidDataTypeException
768
-     * @throws \EventEspresso\core\exceptions\InvalidInterfaceException
769
-     */
770
-    public function process_reg_step()
771
-    {
772
-        do_action('AHEE_log', __FILE__, __FUNCTION__, '');
773
-        // grab validated data from form
774
-        $valid_data = $this->checkout->current_step->valid_data();
775
-        // EEH_Debug_Tools::printr( $_REQUEST, '$_REQUEST', __FILE__, __LINE__ );
776
-        // EEH_Debug_Tools::printr( $valid_data, '$valid_data', __FILE__, __LINE__ );
777
-        // if we don't have any $valid_data then something went TERRIBLY WRONG !!!
778
-        if (empty($valid_data)) {
779
-            EE_Error::add_error(
780
-                esc_html__('No valid question responses were received.', 'event_espresso'),
781
-                __FILE__,
782
-                __FUNCTION__,
783
-                __LINE__
784
-            );
785
-            return false;
786
-        }
787
-        if (! $this->checkout->transaction instanceof EE_Transaction || ! $this->checkout->continue_reg) {
788
-            EE_Error::add_error(
789
-                esc_html__(
790
-                    'A valid transaction could not be initiated for processing your registrations.',
791
-                    'event_espresso'
792
-                ),
793
-                __FILE__,
794
-                __FUNCTION__,
795
-                __LINE__
796
-            );
797
-            return false;
798
-        }
799
-        // get cached registrations
800
-        $registrations = $this->checkout->transaction->registrations($this->checkout->reg_cache_where_params);
801
-        // verify we got the goods
802
-        if (empty($registrations)) {
803
-            //combine the old translated string with a new one, in order to not break translations
804
-            $error_message = esc_html__( 'Your form data could not be applied to any valid registrations.', 'event_espresso' )
805
-                             . sprintf(
806
-                                 esc_html__('%3$sThis can sometimes happen if too much time has been taken to complete the registration process.%3$sPlease return to the %1$sEvent List%2$s and reselect your tickets. If the problem continues, please contact the site administrator.', 'event_espresso'),
807
-                                 '<a href="' . get_post_type_archive_link('espresso_events') . '" >',
808
-                                 '</a>',
809
-                                 '<br />'
810
-                             );
811
-            EE_Error::add_error(
812
-                $error_message,
813
-                __FILE__,
814
-                __FUNCTION__,
815
-                __LINE__
816
-            );
817
-            return false;
818
-        }
819
-        // extract attendee info from form data and save to model objects
820
-        $registrations_processed = $this->_process_registrations($registrations, $valid_data);
821
-        // if first pass thru SPCO,
822
-        // then let's check processed registrations against the total number of tickets in the cart
823
-        if ($registrations_processed === false) {
824
-            // but return immediately if the previous step exited early due to errors
825
-            return false;
826
-        } elseif (! $this->checkout->revisit && $registrations_processed !== $this->checkout->total_ticket_count) {
827
-            // generate a correctly translated string for all possible singular/plural combinations
828
-            if ($this->checkout->total_ticket_count === 1 && $registrations_processed !== 1) {
829
-                $error_msg = sprintf(
830
-                    esc_html__(
831
-                        'There was %1$d ticket in the Event Queue, but %2$ds registrations were processed',
832
-                        'event_espresso'
833
-                    ),
834
-                    $this->checkout->total_ticket_count,
835
-                    $registrations_processed
836
-                );
837
-            } elseif ($this->checkout->total_ticket_count !== 1 && $registrations_processed === 1) {
838
-                $error_msg = sprintf(
839
-                    esc_html__(
840
-                        'There was a total of %1$d tickets in the Event Queue, but only %2$ds registration was processed',
841
-                        'event_espresso'
842
-                    ),
843
-                    $this->checkout->total_ticket_count,
844
-                    $registrations_processed
845
-                );
846
-            } else {
847
-                $error_msg = sprintf(
848
-                    esc_html__(
849
-                        'There was a total of %1$d tickets in the Event Queue, but %2$ds registrations were processed',
850
-                        'event_espresso'
851
-                    ),
852
-                    $this->checkout->total_ticket_count,
853
-                    $registrations_processed
854
-                );
855
-            }
856
-            EE_Error::add_error($error_msg, __FILE__, __FUNCTION__, __LINE__);
857
-            return false;
858
-        }
859
-        // mark this reg step as completed
860
-        $this->set_completed();
861
-        $this->_set_success_message(
862
-            esc_html__('The Attendee Information Step has been successfully completed.', 'event_espresso')
863
-        );
864
-        //do action in case a plugin wants to do something with the data submitted in step 1.
865
-        //passes EE_Single_Page_Checkout, and it's posted data
866
-        do_action('AHEE__EE_Single_Page_Checkout__process_attendee_information__end', $this, $valid_data);
867
-        return true;
868
-    }
869
-
870
-
871
-    /**
872
-     *    _process_registrations
873
-     *
874
-     * @param EE_Registration[] $registrations
875
-     * @param array             $valid_data
876
-     * @return bool|int
877
-     * @throws \EventEspresso\core\exceptions\EntityNotFoundException
878
-     * @throws EE_Error
879
-     * @throws InvalidArgumentException
880
-     * @throws ReflectionException
881
-     * @throws RuntimeException
882
-     * @throws \EventEspresso\core\exceptions\InvalidDataTypeException
883
-     * @throws \EventEspresso\core\exceptions\InvalidInterfaceException
884
-     */
885
-    private function _process_registrations($registrations = array(), $valid_data = array())
886
-    {
887
-        // load resources and set some defaults
888
-        EE_Registry::instance()->load_model('Attendee');
889
-        // holder for primary registrant attendee object
890
-        $this->checkout->primary_attendee_obj = null;
891
-        // array for tracking reg form data for the primary registrant
892
-        $primary_registrant = array(
893
-            'line_item_id' => null,
894
-        );
895
-        $copy_primary       = false;
896
-        // reg form sections that do not contain inputs
897
-        $non_input_form_sections = array(
898
-            'primary_registrant',
899
-            'additional_attendee_reg_info',
900
-            'spco_copy_attendee_chk',
901
-        );
902
-        // attendee counter
903
-        $att_nmbr = 0;
904
-        // grab the saved registrations from the transaction
905
-        foreach ($registrations as $registration) {
906
-            // verify EE_Registration object
907
-            if (! $registration instanceof EE_Registration) {
908
-                EE_Error::add_error(
909
-                    esc_html__(
910
-                        'An invalid Registration object was discovered when attempting to process your registration information.',
911
-                        'event_espresso'
912
-                    ),
913
-                    __FILE__,
914
-                    __FUNCTION__,
915
-                    __LINE__
916
-                );
917
-                return false;
918
-            }
919
-            /** @var string $reg_url_link */
920
-            $reg_url_link = $registration->reg_url_link();
921
-            // reg_url_link exists ?
922
-            if (! empty($reg_url_link)) {
923
-                // should this registration be processed during this visit ?
924
-                if ($this->checkout->visit_allows_processing_of_this_registration($registration)) {
925
-                    // if NOT revisiting, then let's save the registration now,
926
-                    // so that we have a REG_ID to use when generating other objects
927
-                    if (! $this->checkout->revisit) {
928
-                        $registration->save();
929
-                    }
930
-                    /**
931
-                     * This allows plugins to trigger a fail on processing of a
932
-                     * registration for any conditions they may have for it to pass.
933
-                     *
934
-                     * @var bool   if true is returned by the plugin then the
935
-                     *            registration processing is halted.
936
-                     */
937
-                    if (apply_filters(
938
-                        'FHEE__EE_SPCO_Reg_Step_Attendee_Information___process_registrations__pre_registration_process',
939
-                        false,
940
-                        $att_nmbr,
941
-                        $registration,
942
-                        $registrations,
943
-                        $valid_data,
944
-                        $this
945
-                    )) {
946
-                        return false;
947
-                    }
948
-
949
-                    // Houston, we have a registration!
950
-                    $att_nmbr++;
951
-                    $this->_attendee_data[$reg_url_link] = array();
952
-                    // grab any existing related answer objects
953
-                    $this->_registration_answers = $registration->answers();
954
-                    // unset( $valid_data[ $reg_url_link ]['additional_attendee_reg_info'] );
955
-                    if (isset($valid_data[$reg_url_link])) {
956
-                        // do we need to copy basic info from primary attendee ?
957
-                        $copy_primary = isset($valid_data[$reg_url_link]['additional_attendee_reg_info'])
958
-                                        && absint($valid_data[$reg_url_link]['additional_attendee_reg_info']) === 0
959
-                            ? true
960
-                            : false;
961
-                        // filter form input data for this registration
962
-                        $valid_data[$reg_url_link] = (array)apply_filters(
963
-                            'FHEE__EE_Single_Page_Checkout__process_attendee_information__valid_data_line_item',
964
-                            $valid_data[$reg_url_link]
965
-                        );
966
-                        if (isset($valid_data['primary_attendee'])) {
967
-                            $primary_registrant['line_item_id'] = ! empty($valid_data['primary_attendee'])
968
-                                ? $valid_data['primary_attendee']
969
-                                : false;
970
-                            unset($valid_data['primary_attendee']);
971
-                        }
972
-                        // now loop through our array of valid post data && process attendee reg forms
973
-                        foreach ($valid_data[$reg_url_link] as $form_section => $form_inputs) {
974
-                            if (! in_array($form_section, $non_input_form_sections)) {
975
-                                foreach ($form_inputs as $form_input => $input_value) {
976
-                                    // \EEH_Debug_Tools::printr( $input_value, $form_input, __FILE__, __LINE__ );
977
-                                    // check for critical inputs
978
-                                    if (! $this->_verify_critical_attendee_details_are_set_and_validate_email(
979
-                                        $form_input,
980
-                                        $input_value
981
-                                    )
982
-                                    ) {
983
-                                        return false;
984
-                                    }
985
-                                    // store a bit of data about the primary attendee
986
-                                    if ($att_nmbr === 1
987
-                                        && ! empty($input_value)
988
-                                        && $reg_url_link === $primary_registrant['line_item_id']
989
-                                    ) {
990
-                                        $primary_registrant[$form_input] = $input_value;
991
-                                    } elseif ($copy_primary
992
-                                        && $input_value === null
993
-                                        && isset($primary_registrant[$form_input])
994
-                                    ) {
995
-                                        $input_value = $primary_registrant[$form_input];
996
-                                    }
997
-                                    // now attempt to save the input data
998
-                                    if (! $this->_save_registration_form_input(
999
-                                        $registration,
1000
-                                        $form_input,
1001
-                                        $input_value
1002
-                                    )
1003
-                                    ) {
1004
-                                        EE_Error::add_error(
1005
-                                            sprintf(
1006
-                                                esc_html__(
1007
-                                                    'Unable to save registration form data for the form input: "%1$s" with the submitted value: "%2$s"',
1008
-                                                    'event_espresso'
1009
-                                                ),
1010
-                                                $form_input,
1011
-                                                $input_value
1012
-                                            ),
1013
-                                            __FILE__,
1014
-                                            __FUNCTION__,
1015
-                                            __LINE__
1016
-                                        );
1017
-                                        return false;
1018
-                                    }
1019
-                                }
1020
-                            }
1021
-                        }  // end of foreach ( $valid_data[ $reg_url_link ] as $form_section => $form_inputs )
1022
-                    }
1023
-                    //EEH_Debug_Tools::printr( $this->_attendee_data, '$this->_attendee_data', __FILE__, __LINE__ );
1024
-                    // this registration does not require additional attendee information ?
1025
-                    if ($copy_primary
1026
-                        && $att_nmbr > 1
1027
-                        && $this->checkout->primary_attendee_obj instanceof EE_Attendee
1028
-                    ) {
1029
-                        // just copy the primary registrant
1030
-                        $attendee = $this->checkout->primary_attendee_obj;
1031
-                    } else {
1032
-                        // ensure critical details are set for additional attendees
1033
-                        $this->_attendee_data[$reg_url_link] = $att_nmbr > 1
1034
-                            ? $this->_copy_critical_attendee_details_from_primary_registrant(
1035
-                                $this->_attendee_data[$reg_url_link]
1036
-                            )
1037
-                            : $this->_attendee_data[$reg_url_link];
1038
-                        // execute create attendee command (which may return an existing attendee)
1039
-                        $attendee = EE_Registry::instance()->BUS->execute(
1040
-                            new CreateAttendeeCommand(
1041
-                                $this->_attendee_data[$reg_url_link],
1042
-                                $registration
1043
-                            )
1044
-                        );
1045
-                        // who's #1 ?
1046
-                        if ($att_nmbr === 1) {
1047
-                            $this->checkout->primary_attendee_obj = $attendee;
1048
-                        }
1049
-                    }
1050
-                    // EEH_Debug_Tools::printr( $attendee, '$attendee', __FILE__, __LINE__ );
1051
-                    // add relation to registration, set attendee ID, and cache attendee
1052
-                    $this->_associate_attendee_with_registration($registration, $attendee);
1053
-                    // \EEH_Debug_Tools::printr( $registration, '$registration', __FILE__, __LINE__ );
1054
-                    if (! $registration->attendee() instanceof EE_Attendee) {
1055
-                        EE_Error::add_error(
1056
-                            sprintf(
1057
-                                esc_html__(
1058
-                                    'Registration %s has an invalid or missing Attendee object.',
1059
-                                    'event_espresso'
1060
-                                ),
1061
-                                $reg_url_link
1062
-                            ),
1063
-                            __FILE__,
1064
-                            __FUNCTION__,
1065
-                            __LINE__
1066
-                        );
1067
-                        return false;
1068
-                    }
1069
-                    /** @type EE_Registration_Processor $registration_processor */
1070
-                    $registration_processor = EE_Registry::instance()->load_class('Registration_Processor');
1071
-                    // at this point, we should have enough details about the registrant to consider the registration
1072
-                    // NOT incomplete
1073
-                    $registration_processor->toggle_incomplete_registration_status_to_default(
1074
-                        $registration,
1075
-                        false,
1076
-                        new Context(
1077
-                            'spco_reg_step_attendee_information_process_registrations',
1078
-                            esc_html__(
1079
-                                'Finished populating registration with details from the registration form after submitting the Attendee Information Reg Step.',
1080
-                                'event_espresso'
1081
-                            )
1082
-                        )
1083
-                    );
1084
-                    // we can also consider the TXN to not have been failed, so temporarily upgrade it's status to
1085
-                    // abandoned
1086
-                    $this->checkout->transaction->toggle_failed_transaction_status();
1087
-                    // if we've gotten this far, then let's save what we have
1088
-                    $registration->save();
1089
-                    // add relation between TXN and registration
1090
-                    $this->_associate_registration_with_transaction($registration);
1091
-                }
1092
-            } else {
1093
-                EE_Error::add_error(
1094
-                    esc_html__(
1095
-                        'An invalid or missing line item ID was encountered while attempting to process the registration form.',
1096
-                        'event_espresso'
1097
-                    ),
1098
-                    __FILE__,
1099
-                    __FUNCTION__,
1100
-                    __LINE__
1101
-                );
1102
-                // remove malformed data
1103
-                unset($valid_data[$reg_url_link]);
1104
-                return false;
1105
-            }
1106
-
1107
-        } // end of foreach ( $this->checkout->transaction->registrations()  as $registration )
1108
-        return $att_nmbr;
1109
-    }
1110
-
1111
-
1112
-    /**
1113
-     *    _save_registration_form_input
1114
-     *
1115
-     * @param EE_Registration $registration
1116
-     * @param string          $form_input
1117
-     * @param string          $input_value
1118
-     * @return bool
1119
-     * @throws EE_Error
1120
-     * @throws InvalidArgumentException
1121
-     * @throws \EventEspresso\core\exceptions\InvalidDataTypeException
1122
-     * @throws \EventEspresso\core\exceptions\InvalidInterfaceException
1123
-     */
1124
-    private function _save_registration_form_input(
1125
-        EE_Registration $registration,
1126
-        $form_input = '',
1127
-        $input_value = ''
1128
-    ) {
1129
-        // \EEH_Debug_Tools::printr( __FUNCTION__, __CLASS__, __FILE__, __LINE__, 2 );
1130
-        // \EEH_Debug_Tools::printr( $form_input, '$form_input', __FILE__, __LINE__ );
1131
-        // \EEH_Debug_Tools::printr( $input_value, '$input_value', __FILE__, __LINE__ );
1132
-        // allow for plugins to hook in and do their own processing of the form input.
1133
-        // For plugins to bypass normal processing here, they just need to return a boolean value.
1134
-        if (apply_filters(
1135
-            'FHEE__EE_SPCO_Reg_Step_Attendee_Information___save_registration_form_input',
1136
-            false,
1137
-            $registration,
1138
-            $form_input,
1139
-            $input_value,
1140
-            $this
1141
-        )) {
1142
-            return true;
1143
-        }
1144
-        /*
387
+		$question_group_reg_form = new EE_Form_Section_Proper($form_args);
388
+		return apply_filters(
389
+			'FHEE__EE_SPCO_Reg_Step_Attendee_Information___question_group_reg_form__question_group_reg_form',
390
+			$question_group_reg_form,
391
+			$registration,
392
+			$question_group,
393
+			$this
394
+		);
395
+	}
396
+
397
+
398
+	/**
399
+	 * @access public
400
+	 * @param EE_Question_Group $question_group
401
+	 * @return    EE_Form_Section_HTML
402
+	 */
403
+	private function _question_group_header(EE_Question_Group $question_group)
404
+	{
405
+		$html = '';
406
+		// group_name
407
+		if ($question_group->show_group_name() && $question_group->name() !== '') {
408
+			if ($this->checkout->admin_request) {
409
+				$html .= EEH_HTML::br();
410
+				$html .= EEH_HTML::h3(
411
+					$question_group->name(),
412
+					'',
413
+					'ee-reg-form-qstn-grp-title title',
414
+					'font-size: 1.3em; padding-left:0;'
415
+				);
416
+			} else {
417
+				$html .= EEH_HTML::h4(
418
+					$question_group->name(),
419
+					'',
420
+					'ee-reg-form-qstn-grp-title section-title'
421
+				);
422
+			}
423
+		}
424
+		// group_desc
425
+		if ($question_group->show_group_desc() && $question_group->desc() !== '') {
426
+			$html .= EEH_HTML::p(
427
+				$question_group->desc(),
428
+				'',
429
+				$this->checkout->admin_request
430
+					? 'ee-reg-form-qstn-grp-desc-pg'
431
+					: 'ee-reg-form-qstn-grp-desc-pg small-text lt-grey-text'
432
+			);
433
+		}
434
+		return new EE_Form_Section_HTML($html);
435
+	}
436
+
437
+
438
+	/**
439
+	 * @access public
440
+	 * @return    EE_Form_Section_Proper
441
+	 * @throws \EE_Error
442
+	 */
443
+	private function _copy_attendee_info_form()
444
+	{
445
+		// array of params to pass to parent constructor
446
+		return new EE_Form_Section_Proper(
447
+			array(
448
+				'subsections'     => $this->_copy_attendee_info_inputs(),
449
+				'layout_strategy' => new EE_Template_Layout(
450
+					array(
451
+						'layout_template_file'     => SPCO_REG_STEPS_PATH
452
+													  . $this->_slug
453
+													  . DS
454
+													  . 'copy_attendee_info.template.php',
455
+						'begin_template_file'      => null,
456
+						'input_template_file'      => null,
457
+						'subsection_template_file' => null,
458
+						'end_template_file'        => null,
459
+					)
460
+				),
461
+			)
462
+		);
463
+	}
464
+
465
+
466
+	/**
467
+	 * _auto_copy_attendee_info
468
+	 *
469
+	 * @access public
470
+	 * @return EE_Form_Section_HTML
471
+	 */
472
+	private function _auto_copy_attendee_info()
473
+	{
474
+		return new EE_Form_Section_HTML(
475
+			EEH_Template::locate_template(
476
+				SPCO_REG_STEPS_PATH . $this->_slug . DS . '_auto_copy_attendee_info.template.php',
477
+				apply_filters(
478
+					'FHEE__EE_SPCO_Reg_Step_Attendee_Information__auto_copy_attendee_info__template_args',
479
+					array()
480
+				),
481
+				true,
482
+				true
483
+			)
484
+		);
485
+	}
486
+
487
+
488
+	/**
489
+	 * _copy_attendee_info_inputs
490
+	 *
491
+	 * @access public
492
+	 * @return array
493
+	 * @throws \EE_Error
494
+	 */
495
+	private function _copy_attendee_info_inputs()
496
+	{
497
+		$copy_attendee_info_inputs = array();
498
+		$prev_ticket               = null;
499
+		// grab the saved registrations from the transaction
500
+		$registrations = $this->checkout->transaction->registrations($this->checkout->reg_cache_where_params);
501
+		foreach ($registrations as $registration) {
502
+			// for all  attendees other than the primary attendee
503
+			if ($registration instanceof EE_Registration && ! $registration->is_primary_registrant()) {
504
+				// if this is a new ticket OR if this is the very first additional attendee after the primary attendee
505
+				if ($registration->ticket()->ID() !== $prev_ticket) {
506
+					$item_name = $registration->ticket()->name();
507
+					$item_name .= $registration->ticket()->description() !== ''
508
+						? ' - ' . $registration->ticket()->description()
509
+						: '';
510
+					$copy_attendee_info_inputs['spco_copy_attendee_chk[ticket-' . $registration->ticket()->ID() . ']'] =
511
+						new EE_Form_Section_HTML(
512
+							'<h6 class="spco-copy-attendee-event-hdr">' . $item_name . '</h6>'
513
+						);
514
+					$prev_ticket = $registration->ticket()->ID();
515
+				}
516
+
517
+				$copy_attendee_info_inputs['spco_copy_attendee_chk[' . $registration->ID() . ']'] =
518
+					new EE_Checkbox_Multi_Input(
519
+						array(
520
+							$registration->ID() => sprintf(
521
+								esc_html__('Attendee #%s', 'event_espresso'),
522
+								$registration->count()
523
+							),
524
+						),
525
+						array(
526
+							'html_id'                 => 'spco-copy-attendee-chk-' . $registration->reg_url_link(),
527
+							'html_class'              => 'spco-copy-attendee-chk ee-do-not-validate',
528
+							'display_html_label_text' => false,
529
+						)
530
+					);
531
+			}
532
+		}
533
+		return $copy_attendee_info_inputs;
534
+	}
535
+
536
+
537
+	/**
538
+	 * _additional_primary_registrant_inputs
539
+	 *
540
+	 * @access public
541
+	 * @param EE_Registration $registration
542
+	 * @return    EE_Form_Input_Base
543
+	 * @throws \EE_Error
544
+	 */
545
+	private function _additional_primary_registrant_inputs(EE_Registration $registration)
546
+	{
547
+		// generate hidden input
548
+		return new EE_Hidden_Input(
549
+			array(
550
+				'html_id' => 'primary_registrant',
551
+				'default' => $registration->reg_url_link(),
552
+			)
553
+		);
554
+	}
555
+
556
+
557
+	/**
558
+	 * @access public
559
+	 * @param EE_Registration $registration
560
+	 * @param EE_Question     $question
561
+	 * @return EE_Form_Input_Base
562
+	 * @throws EE_Error
563
+	 * @throws InvalidArgumentException
564
+	 * @throws \EventEspresso\core\exceptions\InvalidDataTypeException
565
+	 * @throws \EventEspresso\core\exceptions\InvalidInterfaceException
566
+	 */
567
+	public function reg_form_question(EE_Registration $registration, EE_Question $question)
568
+	{
569
+
570
+		// if this question was for an attendee detail, then check for that answer
571
+		$answer_value = EEM_Answer::instance()->get_attendee_property_answer_value(
572
+			$registration,
573
+			$question->system_ID()
574
+		);
575
+		$answer       = $answer_value === null
576
+			? EEM_Answer::instance()->get_one(
577
+				array(array('QST_ID' => $question->ID(), 'REG_ID' => $registration->ID()))
578
+			)
579
+			: null;
580
+		// if NOT returning to edit an existing registration
581
+		// OR if this question is for an attendee property
582
+		// OR we still don't have an EE_Answer object
583
+		if ($answer_value || ! $answer instanceof EE_Answer || ! $registration->reg_url_link()) {
584
+			// create an EE_Answer object for storing everything in
585
+			$answer = EE_Answer::new_instance(array(
586
+				'QST_ID' => $question->ID(),
587
+				'REG_ID' => $registration->ID(),
588
+			));
589
+		}
590
+		// verify instance
591
+		if ($answer instanceof EE_Answer) {
592
+			if (! empty($answer_value)) {
593
+				$answer->set('ANS_value', $answer_value);
594
+			}
595
+			$answer->cache('Question', $question);
596
+			//remember system ID had a bug where sometimes it could be null
597
+			$answer_cache_id = $question->is_system_question()
598
+				? $question->system_ID() . '-' . $registration->reg_url_link()
599
+				: $question->ID() . '-' . $registration->reg_url_link();
600
+			$registration->cache('Answer', $answer, $answer_cache_id);
601
+		}
602
+		return $this->_generate_question_input($registration, $question, $answer);
603
+	}
604
+
605
+
606
+	/**
607
+	 * @param EE_Registration $registration
608
+	 * @param EE_Question     $question
609
+	 * @param                 mixed EE_Answer|NULL      $answer
610
+	 * @return EE_Form_Input_Base
611
+	 * @throws \EE_Error
612
+	 */
613
+	private function _generate_question_input(EE_Registration $registration, EE_Question $question, $answer)
614
+	{
615
+		$identifier                             = $question->is_system_question()
616
+			? $question->system_ID()
617
+			: $question->ID();
618
+		$this->_required_questions[$identifier] = $question->required() ? true : false;
619
+		add_filter(
620
+			'FHEE__EE_Question__generate_form_input__country_options',
621
+			array($this, 'use_cached_countries_for_form_input'),
622
+			10,
623
+			4
624
+		);
625
+		add_filter(
626
+			'FHEE__EE_Question__generate_form_input__state_options',
627
+			array($this, 'use_cached_states_for_form_input'),
628
+			10,
629
+			4
630
+		);
631
+		$input_constructor_args                  = array(
632
+			'html_name'        => 'ee_reg_qstn[' . $registration->ID() . '][' . $identifier . ']',
633
+			'html_id'          => 'ee_reg_qstn-' . $registration->ID() . '-' . $identifier,
634
+			'html_class'       => 'ee-reg-qstn ee-reg-qstn-' . $identifier,
635
+			'html_label_id'    => 'ee_reg_qstn-' . $registration->ID() . '-' . $identifier,
636
+			'html_label_class' => 'ee-reg-qstn',
637
+		);
638
+		$input_constructor_args['html_label_id'] .= '-lbl';
639
+		if ($answer instanceof EE_Answer && $answer->ID()) {
640
+			$input_constructor_args['html_name']     .= '[' . $answer->ID() . ']';
641
+			$input_constructor_args['html_id']       .= '-' . $answer->ID();
642
+			$input_constructor_args['html_label_id'] .= '-' . $answer->ID();
643
+		}
644
+		$form_input = $question->generate_form_input(
645
+			$registration,
646
+			$answer,
647
+			$input_constructor_args
648
+		);
649
+		remove_filter(
650
+			'FHEE__EE_Question__generate_form_input__country_options',
651
+			array($this, 'use_cached_countries_for_form_input')
652
+		);
653
+		remove_filter(
654
+			'FHEE__EE_Question__generate_form_input__state_options',
655
+			array($this, 'use_cached_states_for_form_input')
656
+		);
657
+		return $form_input;
658
+	}
659
+
660
+
661
+	/**
662
+	 * Gets the list of countries for the form input
663
+	 *
664
+	 * @param array|null       $countries_list
665
+	 * @param \EE_Question     $question
666
+	 * @param \EE_Registration $registration
667
+	 * @param \EE_Answer       $answer
668
+	 * @return array 2d keys are country IDs, values are their names
669
+	 * @throws EE_Error
670
+	 * @throws InvalidArgumentException
671
+	 * @throws \EventEspresso\core\exceptions\InvalidDataTypeException
672
+	 * @throws \EventEspresso\core\exceptions\InvalidInterfaceException
673
+	 */
674
+	public function use_cached_countries_for_form_input(
675
+		$countries_list,
676
+		\EE_Question $question = null,
677
+		\EE_Registration $registration = null,
678
+		\EE_Answer $answer = null
679
+	) {
680
+		$country_options = array('' => '');
681
+		// get possibly cached list of countries
682
+		$countries = $this->checkout->action === 'process_reg_step'
683
+			? EEM_Country::instance()->get_all_countries()
684
+			: EEM_Country::instance()->get_all_active_countries();
685
+		if (! empty($countries)) {
686
+			foreach ($countries as $country) {
687
+				if ($country instanceof EE_Country) {
688
+					$country_options[$country->ID()] = $country->name();
689
+				}
690
+			}
691
+		}
692
+		if ($question instanceof EE_Question
693
+			&& $registration instanceof EE_Registration) {
694
+			$answer = EEM_Answer::instance()->get_one(
695
+				array(array('QST_ID' => $question->ID(), 'REG_ID' => $registration->ID()))
696
+			);
697
+		} else {
698
+			$answer = EE_Answer::new_instance();
699
+		}
700
+		$country_options = apply_filters(
701
+			'FHEE__EE_SPCO_Reg_Step_Attendee_Information___generate_question_input__country_options',
702
+			$country_options,
703
+			$this,
704
+			$registration,
705
+			$question,
706
+			$answer
707
+		);
708
+		return $country_options;
709
+	}
710
+
711
+
712
+	/**
713
+	 * Gets the list of states for the form input
714
+	 *
715
+	 * @param array|null       $states_list
716
+	 * @param \EE_Question     $question
717
+	 * @param \EE_Registration $registration
718
+	 * @param \EE_Answer       $answer
719
+	 * @return array 2d keys are state IDs, values are their names
720
+	 * @throws EE_Error
721
+	 * @throws InvalidArgumentException
722
+	 * @throws \EventEspresso\core\exceptions\InvalidDataTypeException
723
+	 * @throws \EventEspresso\core\exceptions\InvalidInterfaceException
724
+	 */
725
+	public function use_cached_states_for_form_input(
726
+		$states_list,
727
+		\EE_Question $question = null,
728
+		\EE_Registration $registration = null,
729
+		\EE_Answer $answer = null
730
+	) {
731
+		$state_options = array('' => array('' => ''));
732
+		$states        = $this->checkout->action === 'process_reg_step'
733
+			? EEM_State::instance()->get_all_states()
734
+			: EEM_State::instance()->get_all_active_states();
735
+		if (! empty($states)) {
736
+			foreach ($states as $state) {
737
+				if ($state instanceof EE_State) {
738
+					$state_options[$state->country()->name()][$state->ID()] = $state->name();
739
+				}
740
+			}
741
+		}
742
+		$state_options = apply_filters(
743
+			'FHEE__EE_SPCO_Reg_Step_Attendee_Information___generate_question_input__state_options',
744
+			$state_options,
745
+			$this,
746
+			$registration,
747
+			$question,
748
+			$answer
749
+		);
750
+		return $state_options;
751
+	}
752
+
753
+
754
+
755
+
756
+
757
+
758
+	/********************************************************************************************************/
759
+	/****************************************  PROCESS REG STEP  ****************************************/
760
+	/********************************************************************************************************/
761
+	/**
762
+	 * @return bool
763
+	 * @throws EE_Error
764
+	 * @throws InvalidArgumentException
765
+	 * @throws ReflectionException
766
+	 * @throws RuntimeException
767
+	 * @throws \EventEspresso\core\exceptions\InvalidDataTypeException
768
+	 * @throws \EventEspresso\core\exceptions\InvalidInterfaceException
769
+	 */
770
+	public function process_reg_step()
771
+	{
772
+		do_action('AHEE_log', __FILE__, __FUNCTION__, '');
773
+		// grab validated data from form
774
+		$valid_data = $this->checkout->current_step->valid_data();
775
+		// EEH_Debug_Tools::printr( $_REQUEST, '$_REQUEST', __FILE__, __LINE__ );
776
+		// EEH_Debug_Tools::printr( $valid_data, '$valid_data', __FILE__, __LINE__ );
777
+		// if we don't have any $valid_data then something went TERRIBLY WRONG !!!
778
+		if (empty($valid_data)) {
779
+			EE_Error::add_error(
780
+				esc_html__('No valid question responses were received.', 'event_espresso'),
781
+				__FILE__,
782
+				__FUNCTION__,
783
+				__LINE__
784
+			);
785
+			return false;
786
+		}
787
+		if (! $this->checkout->transaction instanceof EE_Transaction || ! $this->checkout->continue_reg) {
788
+			EE_Error::add_error(
789
+				esc_html__(
790
+					'A valid transaction could not be initiated for processing your registrations.',
791
+					'event_espresso'
792
+				),
793
+				__FILE__,
794
+				__FUNCTION__,
795
+				__LINE__
796
+			);
797
+			return false;
798
+		}
799
+		// get cached registrations
800
+		$registrations = $this->checkout->transaction->registrations($this->checkout->reg_cache_where_params);
801
+		// verify we got the goods
802
+		if (empty($registrations)) {
803
+			//combine the old translated string with a new one, in order to not break translations
804
+			$error_message = esc_html__( 'Your form data could not be applied to any valid registrations.', 'event_espresso' )
805
+							 . sprintf(
806
+								 esc_html__('%3$sThis can sometimes happen if too much time has been taken to complete the registration process.%3$sPlease return to the %1$sEvent List%2$s and reselect your tickets. If the problem continues, please contact the site administrator.', 'event_espresso'),
807
+								 '<a href="' . get_post_type_archive_link('espresso_events') . '" >',
808
+								 '</a>',
809
+								 '<br />'
810
+							 );
811
+			EE_Error::add_error(
812
+				$error_message,
813
+				__FILE__,
814
+				__FUNCTION__,
815
+				__LINE__
816
+			);
817
+			return false;
818
+		}
819
+		// extract attendee info from form data and save to model objects
820
+		$registrations_processed = $this->_process_registrations($registrations, $valid_data);
821
+		// if first pass thru SPCO,
822
+		// then let's check processed registrations against the total number of tickets in the cart
823
+		if ($registrations_processed === false) {
824
+			// but return immediately if the previous step exited early due to errors
825
+			return false;
826
+		} elseif (! $this->checkout->revisit && $registrations_processed !== $this->checkout->total_ticket_count) {
827
+			// generate a correctly translated string for all possible singular/plural combinations
828
+			if ($this->checkout->total_ticket_count === 1 && $registrations_processed !== 1) {
829
+				$error_msg = sprintf(
830
+					esc_html__(
831
+						'There was %1$d ticket in the Event Queue, but %2$ds registrations were processed',
832
+						'event_espresso'
833
+					),
834
+					$this->checkout->total_ticket_count,
835
+					$registrations_processed
836
+				);
837
+			} elseif ($this->checkout->total_ticket_count !== 1 && $registrations_processed === 1) {
838
+				$error_msg = sprintf(
839
+					esc_html__(
840
+						'There was a total of %1$d tickets in the Event Queue, but only %2$ds registration was processed',
841
+						'event_espresso'
842
+					),
843
+					$this->checkout->total_ticket_count,
844
+					$registrations_processed
845
+				);
846
+			} else {
847
+				$error_msg = sprintf(
848
+					esc_html__(
849
+						'There was a total of %1$d tickets in the Event Queue, but %2$ds registrations were processed',
850
+						'event_espresso'
851
+					),
852
+					$this->checkout->total_ticket_count,
853
+					$registrations_processed
854
+				);
855
+			}
856
+			EE_Error::add_error($error_msg, __FILE__, __FUNCTION__, __LINE__);
857
+			return false;
858
+		}
859
+		// mark this reg step as completed
860
+		$this->set_completed();
861
+		$this->_set_success_message(
862
+			esc_html__('The Attendee Information Step has been successfully completed.', 'event_espresso')
863
+		);
864
+		//do action in case a plugin wants to do something with the data submitted in step 1.
865
+		//passes EE_Single_Page_Checkout, and it's posted data
866
+		do_action('AHEE__EE_Single_Page_Checkout__process_attendee_information__end', $this, $valid_data);
867
+		return true;
868
+	}
869
+
870
+
871
+	/**
872
+	 *    _process_registrations
873
+	 *
874
+	 * @param EE_Registration[] $registrations
875
+	 * @param array             $valid_data
876
+	 * @return bool|int
877
+	 * @throws \EventEspresso\core\exceptions\EntityNotFoundException
878
+	 * @throws EE_Error
879
+	 * @throws InvalidArgumentException
880
+	 * @throws ReflectionException
881
+	 * @throws RuntimeException
882
+	 * @throws \EventEspresso\core\exceptions\InvalidDataTypeException
883
+	 * @throws \EventEspresso\core\exceptions\InvalidInterfaceException
884
+	 */
885
+	private function _process_registrations($registrations = array(), $valid_data = array())
886
+	{
887
+		// load resources and set some defaults
888
+		EE_Registry::instance()->load_model('Attendee');
889
+		// holder for primary registrant attendee object
890
+		$this->checkout->primary_attendee_obj = null;
891
+		// array for tracking reg form data for the primary registrant
892
+		$primary_registrant = array(
893
+			'line_item_id' => null,
894
+		);
895
+		$copy_primary       = false;
896
+		// reg form sections that do not contain inputs
897
+		$non_input_form_sections = array(
898
+			'primary_registrant',
899
+			'additional_attendee_reg_info',
900
+			'spco_copy_attendee_chk',
901
+		);
902
+		// attendee counter
903
+		$att_nmbr = 0;
904
+		// grab the saved registrations from the transaction
905
+		foreach ($registrations as $registration) {
906
+			// verify EE_Registration object
907
+			if (! $registration instanceof EE_Registration) {
908
+				EE_Error::add_error(
909
+					esc_html__(
910
+						'An invalid Registration object was discovered when attempting to process your registration information.',
911
+						'event_espresso'
912
+					),
913
+					__FILE__,
914
+					__FUNCTION__,
915
+					__LINE__
916
+				);
917
+				return false;
918
+			}
919
+			/** @var string $reg_url_link */
920
+			$reg_url_link = $registration->reg_url_link();
921
+			// reg_url_link exists ?
922
+			if (! empty($reg_url_link)) {
923
+				// should this registration be processed during this visit ?
924
+				if ($this->checkout->visit_allows_processing_of_this_registration($registration)) {
925
+					// if NOT revisiting, then let's save the registration now,
926
+					// so that we have a REG_ID to use when generating other objects
927
+					if (! $this->checkout->revisit) {
928
+						$registration->save();
929
+					}
930
+					/**
931
+					 * This allows plugins to trigger a fail on processing of a
932
+					 * registration for any conditions they may have for it to pass.
933
+					 *
934
+					 * @var bool   if true is returned by the plugin then the
935
+					 *            registration processing is halted.
936
+					 */
937
+					if (apply_filters(
938
+						'FHEE__EE_SPCO_Reg_Step_Attendee_Information___process_registrations__pre_registration_process',
939
+						false,
940
+						$att_nmbr,
941
+						$registration,
942
+						$registrations,
943
+						$valid_data,
944
+						$this
945
+					)) {
946
+						return false;
947
+					}
948
+
949
+					// Houston, we have a registration!
950
+					$att_nmbr++;
951
+					$this->_attendee_data[$reg_url_link] = array();
952
+					// grab any existing related answer objects
953
+					$this->_registration_answers = $registration->answers();
954
+					// unset( $valid_data[ $reg_url_link ]['additional_attendee_reg_info'] );
955
+					if (isset($valid_data[$reg_url_link])) {
956
+						// do we need to copy basic info from primary attendee ?
957
+						$copy_primary = isset($valid_data[$reg_url_link]['additional_attendee_reg_info'])
958
+										&& absint($valid_data[$reg_url_link]['additional_attendee_reg_info']) === 0
959
+							? true
960
+							: false;
961
+						// filter form input data for this registration
962
+						$valid_data[$reg_url_link] = (array)apply_filters(
963
+							'FHEE__EE_Single_Page_Checkout__process_attendee_information__valid_data_line_item',
964
+							$valid_data[$reg_url_link]
965
+						);
966
+						if (isset($valid_data['primary_attendee'])) {
967
+							$primary_registrant['line_item_id'] = ! empty($valid_data['primary_attendee'])
968
+								? $valid_data['primary_attendee']
969
+								: false;
970
+							unset($valid_data['primary_attendee']);
971
+						}
972
+						// now loop through our array of valid post data && process attendee reg forms
973
+						foreach ($valid_data[$reg_url_link] as $form_section => $form_inputs) {
974
+							if (! in_array($form_section, $non_input_form_sections)) {
975
+								foreach ($form_inputs as $form_input => $input_value) {
976
+									// \EEH_Debug_Tools::printr( $input_value, $form_input, __FILE__, __LINE__ );
977
+									// check for critical inputs
978
+									if (! $this->_verify_critical_attendee_details_are_set_and_validate_email(
979
+										$form_input,
980
+										$input_value
981
+									)
982
+									) {
983
+										return false;
984
+									}
985
+									// store a bit of data about the primary attendee
986
+									if ($att_nmbr === 1
987
+										&& ! empty($input_value)
988
+										&& $reg_url_link === $primary_registrant['line_item_id']
989
+									) {
990
+										$primary_registrant[$form_input] = $input_value;
991
+									} elseif ($copy_primary
992
+										&& $input_value === null
993
+										&& isset($primary_registrant[$form_input])
994
+									) {
995
+										$input_value = $primary_registrant[$form_input];
996
+									}
997
+									// now attempt to save the input data
998
+									if (! $this->_save_registration_form_input(
999
+										$registration,
1000
+										$form_input,
1001
+										$input_value
1002
+									)
1003
+									) {
1004
+										EE_Error::add_error(
1005
+											sprintf(
1006
+												esc_html__(
1007
+													'Unable to save registration form data for the form input: "%1$s" with the submitted value: "%2$s"',
1008
+													'event_espresso'
1009
+												),
1010
+												$form_input,
1011
+												$input_value
1012
+											),
1013
+											__FILE__,
1014
+											__FUNCTION__,
1015
+											__LINE__
1016
+										);
1017
+										return false;
1018
+									}
1019
+								}
1020
+							}
1021
+						}  // end of foreach ( $valid_data[ $reg_url_link ] as $form_section => $form_inputs )
1022
+					}
1023
+					//EEH_Debug_Tools::printr( $this->_attendee_data, '$this->_attendee_data', __FILE__, __LINE__ );
1024
+					// this registration does not require additional attendee information ?
1025
+					if ($copy_primary
1026
+						&& $att_nmbr > 1
1027
+						&& $this->checkout->primary_attendee_obj instanceof EE_Attendee
1028
+					) {
1029
+						// just copy the primary registrant
1030
+						$attendee = $this->checkout->primary_attendee_obj;
1031
+					} else {
1032
+						// ensure critical details are set for additional attendees
1033
+						$this->_attendee_data[$reg_url_link] = $att_nmbr > 1
1034
+							? $this->_copy_critical_attendee_details_from_primary_registrant(
1035
+								$this->_attendee_data[$reg_url_link]
1036
+							)
1037
+							: $this->_attendee_data[$reg_url_link];
1038
+						// execute create attendee command (which may return an existing attendee)
1039
+						$attendee = EE_Registry::instance()->BUS->execute(
1040
+							new CreateAttendeeCommand(
1041
+								$this->_attendee_data[$reg_url_link],
1042
+								$registration
1043
+							)
1044
+						);
1045
+						// who's #1 ?
1046
+						if ($att_nmbr === 1) {
1047
+							$this->checkout->primary_attendee_obj = $attendee;
1048
+						}
1049
+					}
1050
+					// EEH_Debug_Tools::printr( $attendee, '$attendee', __FILE__, __LINE__ );
1051
+					// add relation to registration, set attendee ID, and cache attendee
1052
+					$this->_associate_attendee_with_registration($registration, $attendee);
1053
+					// \EEH_Debug_Tools::printr( $registration, '$registration', __FILE__, __LINE__ );
1054
+					if (! $registration->attendee() instanceof EE_Attendee) {
1055
+						EE_Error::add_error(
1056
+							sprintf(
1057
+								esc_html__(
1058
+									'Registration %s has an invalid or missing Attendee object.',
1059
+									'event_espresso'
1060
+								),
1061
+								$reg_url_link
1062
+							),
1063
+							__FILE__,
1064
+							__FUNCTION__,
1065
+							__LINE__
1066
+						);
1067
+						return false;
1068
+					}
1069
+					/** @type EE_Registration_Processor $registration_processor */
1070
+					$registration_processor = EE_Registry::instance()->load_class('Registration_Processor');
1071
+					// at this point, we should have enough details about the registrant to consider the registration
1072
+					// NOT incomplete
1073
+					$registration_processor->toggle_incomplete_registration_status_to_default(
1074
+						$registration,
1075
+						false,
1076
+						new Context(
1077
+							'spco_reg_step_attendee_information_process_registrations',
1078
+							esc_html__(
1079
+								'Finished populating registration with details from the registration form after submitting the Attendee Information Reg Step.',
1080
+								'event_espresso'
1081
+							)
1082
+						)
1083
+					);
1084
+					// we can also consider the TXN to not have been failed, so temporarily upgrade it's status to
1085
+					// abandoned
1086
+					$this->checkout->transaction->toggle_failed_transaction_status();
1087
+					// if we've gotten this far, then let's save what we have
1088
+					$registration->save();
1089
+					// add relation between TXN and registration
1090
+					$this->_associate_registration_with_transaction($registration);
1091
+				}
1092
+			} else {
1093
+				EE_Error::add_error(
1094
+					esc_html__(
1095
+						'An invalid or missing line item ID was encountered while attempting to process the registration form.',
1096
+						'event_espresso'
1097
+					),
1098
+					__FILE__,
1099
+					__FUNCTION__,
1100
+					__LINE__
1101
+				);
1102
+				// remove malformed data
1103
+				unset($valid_data[$reg_url_link]);
1104
+				return false;
1105
+			}
1106
+
1107
+		} // end of foreach ( $this->checkout->transaction->registrations()  as $registration )
1108
+		return $att_nmbr;
1109
+	}
1110
+
1111
+
1112
+	/**
1113
+	 *    _save_registration_form_input
1114
+	 *
1115
+	 * @param EE_Registration $registration
1116
+	 * @param string          $form_input
1117
+	 * @param string          $input_value
1118
+	 * @return bool
1119
+	 * @throws EE_Error
1120
+	 * @throws InvalidArgumentException
1121
+	 * @throws \EventEspresso\core\exceptions\InvalidDataTypeException
1122
+	 * @throws \EventEspresso\core\exceptions\InvalidInterfaceException
1123
+	 */
1124
+	private function _save_registration_form_input(
1125
+		EE_Registration $registration,
1126
+		$form_input = '',
1127
+		$input_value = ''
1128
+	) {
1129
+		// \EEH_Debug_Tools::printr( __FUNCTION__, __CLASS__, __FILE__, __LINE__, 2 );
1130
+		// \EEH_Debug_Tools::printr( $form_input, '$form_input', __FILE__, __LINE__ );
1131
+		// \EEH_Debug_Tools::printr( $input_value, '$input_value', __FILE__, __LINE__ );
1132
+		// allow for plugins to hook in and do their own processing of the form input.
1133
+		// For plugins to bypass normal processing here, they just need to return a boolean value.
1134
+		if (apply_filters(
1135
+			'FHEE__EE_SPCO_Reg_Step_Attendee_Information___save_registration_form_input',
1136
+			false,
1137
+			$registration,
1138
+			$form_input,
1139
+			$input_value,
1140
+			$this
1141
+		)) {
1142
+			return true;
1143
+		}
1144
+		/*
1145 1145
          * $answer_cache_id is the key used to find the EE_Answer we want
1146 1146
          * @see https://events.codebasehq.com/projects/event-espresso/tickets/10477
1147 1147
          */
1148
-        $answer_cache_id = $this->checkout->reg_url_link
1149
-            ? $form_input . '-' . $registration->reg_url_link()
1150
-            : $form_input;
1151
-        $answer_is_obj   = isset($this->_registration_answers[$answer_cache_id])
1152
-                           && $this->_registration_answers[$answer_cache_id] instanceof EE_Answer
1153
-            ? true
1154
-            : false;
1155
-        //rename form_inputs if they are EE_Attendee properties
1156
-        switch ((string) $form_input) {
1157
-            case 'state':
1158
-            case 'STA_ID':
1159
-                $attendee_property = true;
1160
-                $form_input        = 'STA_ID';
1161
-                break;
1162
-
1163
-            case 'country':
1164
-            case 'CNT_ISO':
1165
-                $attendee_property = true;
1166
-                $form_input        = 'CNT_ISO';
1167
-                break;
1168
-
1169
-            default:
1170
-                $ATT_input = 'ATT_' . $form_input;
1171
-                //EEH_Debug_Tools::printr( $ATT_input, '$ATT_input', __FILE__, __LINE__ );
1172
-                $attendee_property = EEM_Attendee::instance()->has_field($ATT_input) ? true : false;
1173
-                $form_input        = $attendee_property ? 'ATT_' . $form_input : $form_input;
1174
-        }
1175
-        // EEH_Debug_Tools::printr( $answer_cache_id, '$answer_cache_id', __FILE__, __LINE__ );
1176
-        // EEH_Debug_Tools::printr( $attendee_property, '$attendee_property', __FILE__, __LINE__ );
1177
-        // EEH_Debug_Tools::printr( $answer_is_obj, '$answer_is_obj', __FILE__, __LINE__ );
1178
-        // if this form input has a corresponding attendee property
1179
-        if ($attendee_property) {
1180
-            $this->_attendee_data[$registration->reg_url_link()][$form_input] = $input_value;
1181
-            if ($answer_is_obj) {
1182
-                // and delete the corresponding answer since we won't be storing this data in that object
1183
-                $registration->_remove_relation_to($this->_registration_answers[$answer_cache_id], 'Answer');
1184
-                $this->_registration_answers[$answer_cache_id]->delete_permanently();
1185
-            }
1186
-            return true;
1187
-        } elseif ($answer_is_obj) {
1188
-            // save this data to the answer object
1189
-            $this->_registration_answers[$answer_cache_id]->set_value($input_value);
1190
-            $result = $this->_registration_answers[$answer_cache_id]->save();
1191
-            return $result !== false ? true : false;
1192
-        } else {
1193
-            foreach ($this->_registration_answers as $answer) {
1194
-                if ($answer instanceof EE_Answer && $answer->question_ID() === $answer_cache_id) {
1195
-                    $answer->set_value($input_value);
1196
-                    $result = $answer->save();
1197
-                    return $result !== false ? true : false;
1198
-                }
1199
-            }
1200
-        }
1201
-        return false;
1202
-    }
1203
-
1204
-
1205
-    /**
1206
-     *    _verify_critical_attendee_details_are_set
1207
-     *
1208
-     * @param string $form_input
1209
-     * @param string $input_value
1210
-     * @return boolean
1211
-     */
1212
-    private function _verify_critical_attendee_details_are_set_and_validate_email(
1213
-        $form_input = '',
1214
-        $input_value = ''
1215
-    ) {
1216
-        if (empty($input_value)) {
1217
-            // if the form input isn't marked as being required, then just return
1218
-            if (! isset($this->_required_questions[$form_input]) || ! $this->_required_questions[$form_input]) {
1219
-                return true;
1220
-            }
1221
-            switch ($form_input) {
1222
-                case 'fname':
1223
-                    EE_Error::add_error(
1224
-                        esc_html__('First Name is a required value.', 'event_espresso'),
1225
-                        __FILE__,
1226
-                        __FUNCTION__,
1227
-                        __LINE__
1228
-                    );
1229
-                    return false;
1230
-                    break;
1231
-                case 'lname':
1232
-                    EE_Error::add_error(
1233
-                        esc_html__('Last Name is a required value.', 'event_espresso'),
1234
-                        __FILE__,
1235
-                        __FUNCTION__,
1236
-                        __LINE__
1237
-                    );
1238
-                    return false;
1239
-                    break;
1240
-                case 'email':
1241
-                    EE_Error::add_error(
1242
-                        esc_html__('Please enter a valid email address.', 'event_espresso'),
1243
-                        __FILE__,
1244
-                        __FUNCTION__,
1245
-                        __LINE__
1246
-                    );
1247
-                    return false;
1248
-                    break;
1249
-            }
1250
-        }
1251
-        return true;
1252
-    }
1253
-
1254
-
1255
-    /**
1256
-     *    _associate_attendee_with_registration
1257
-     *
1258
-     * @param EE_Registration $registration
1259
-     * @param EE_Attendee     $attendee
1260
-     * @return void
1261
-     * @throws EE_Error
1262
-     * @throws RuntimeException
1263
-     */
1264
-    private function _associate_attendee_with_registration(EE_Registration $registration, EE_Attendee $attendee)
1265
-    {
1266
-        // add relation to attendee
1267
-        $registration->_add_relation_to($attendee, 'Attendee');
1268
-        $registration->set_attendee_id($attendee->ID());
1269
-        $registration->update_cache_after_object_save('Attendee', $attendee);
1270
-    }
1271
-
1272
-
1273
-    /**
1274
-     *    _associate_registration_with_transaction
1275
-     *
1276
-     * @param EE_Registration $registration
1277
-     * @return void
1278
-     * @throws \EE_Error
1279
-     */
1280
-    private function _associate_registration_with_transaction(EE_Registration $registration)
1281
-    {
1282
-        // add relation to registration
1283
-        $this->checkout->transaction->_add_relation_to($registration, 'Registration');
1284
-        $this->checkout->transaction->update_cache_after_object_save('Registration', $registration);
1285
-    }
1286
-
1287
-
1288
-    /**
1289
-     *    _copy_critical_attendee_details_from_primary_registrant
1290
-     *    ensures that all attendees at least have data for first name, last name, and email address
1291
-     *
1292
-     * @param array $attendee_data
1293
-     * @return array
1294
-     * @throws \EE_Error
1295
-     */
1296
-    private function _copy_critical_attendee_details_from_primary_registrant($attendee_data = array())
1297
-    {
1298
-        // bare minimum critical details include first name, last name, email address
1299
-        $critical_attendee_details = array('ATT_fname', 'ATT_lname', 'ATT_email');
1300
-        // add address info to critical details?
1301
-        if (apply_filters(
1302
-            'FHEE__EE_SPCO_Reg_Step_Attendee_Information__merge_address_details_with_critical_attendee_details',
1303
-            false
1304
-        )) {
1305
-            $address_details           = array(
1306
-                'ATT_address',
1307
-                'ATT_address2',
1308
-                'ATT_city',
1309
-                'STA_ID',
1310
-                'CNT_ISO',
1311
-                'ATT_zip',
1312
-                'ATT_phone',
1313
-            );
1314
-            $critical_attendee_details = array_merge($critical_attendee_details, $address_details);
1315
-        }
1316
-        foreach ($critical_attendee_details as $critical_attendee_detail) {
1317
-            if (! isset($attendee_data[$critical_attendee_detail])
1318
-                || empty($attendee_data[$critical_attendee_detail])
1319
-            ) {
1320
-                $attendee_data[$critical_attendee_detail] = $this->checkout->primary_attendee_obj->get(
1321
-                    $critical_attendee_detail
1322
-                );
1323
-            }
1324
-        }
1325
-        return $attendee_data;
1326
-    }
1327
-
1328
-
1329
-    /**
1330
-     *    update_reg_step
1331
-     *    this is the final step after a user  revisits the site to edit their attendee information
1332
-     *    this gets called AFTER the process_reg_step() method above
1333
-     *
1334
-     * @return bool
1335
-     * @throws EE_Error
1336
-     * @throws InvalidArgumentException
1337
-     * @throws ReflectionException
1338
-     * @throws RuntimeException
1339
-     * @throws \EventEspresso\core\exceptions\InvalidDataTypeException
1340
-     * @throws \EventEspresso\core\exceptions\InvalidInterfaceException
1341
-     */
1342
-    public function update_reg_step()
1343
-    {
1344
-        // save everything
1345
-        if ($this->process_reg_step()) {
1346
-            $this->checkout->redirect     = true;
1347
-            $this->checkout->redirect_url = add_query_arg(
1348
-                array(
1349
-                    'e_reg_url_link' => $this->checkout->reg_url_link,
1350
-                    'revisit'        => true,
1351
-                ),
1352
-                $this->checkout->thank_you_page_url
1353
-            );
1354
-            $this->checkout->json_response->set_redirect_url($this->checkout->redirect_url);
1355
-            return true;
1356
-        }
1357
-        return false;
1358
-    }
1148
+		$answer_cache_id = $this->checkout->reg_url_link
1149
+			? $form_input . '-' . $registration->reg_url_link()
1150
+			: $form_input;
1151
+		$answer_is_obj   = isset($this->_registration_answers[$answer_cache_id])
1152
+						   && $this->_registration_answers[$answer_cache_id] instanceof EE_Answer
1153
+			? true
1154
+			: false;
1155
+		//rename form_inputs if they are EE_Attendee properties
1156
+		switch ((string) $form_input) {
1157
+			case 'state':
1158
+			case 'STA_ID':
1159
+				$attendee_property = true;
1160
+				$form_input        = 'STA_ID';
1161
+				break;
1162
+
1163
+			case 'country':
1164
+			case 'CNT_ISO':
1165
+				$attendee_property = true;
1166
+				$form_input        = 'CNT_ISO';
1167
+				break;
1168
+
1169
+			default:
1170
+				$ATT_input = 'ATT_' . $form_input;
1171
+				//EEH_Debug_Tools::printr( $ATT_input, '$ATT_input', __FILE__, __LINE__ );
1172
+				$attendee_property = EEM_Attendee::instance()->has_field($ATT_input) ? true : false;
1173
+				$form_input        = $attendee_property ? 'ATT_' . $form_input : $form_input;
1174
+		}
1175
+		// EEH_Debug_Tools::printr( $answer_cache_id, '$answer_cache_id', __FILE__, __LINE__ );
1176
+		// EEH_Debug_Tools::printr( $attendee_property, '$attendee_property', __FILE__, __LINE__ );
1177
+		// EEH_Debug_Tools::printr( $answer_is_obj, '$answer_is_obj', __FILE__, __LINE__ );
1178
+		// if this form input has a corresponding attendee property
1179
+		if ($attendee_property) {
1180
+			$this->_attendee_data[$registration->reg_url_link()][$form_input] = $input_value;
1181
+			if ($answer_is_obj) {
1182
+				// and delete the corresponding answer since we won't be storing this data in that object
1183
+				$registration->_remove_relation_to($this->_registration_answers[$answer_cache_id], 'Answer');
1184
+				$this->_registration_answers[$answer_cache_id]->delete_permanently();
1185
+			}
1186
+			return true;
1187
+		} elseif ($answer_is_obj) {
1188
+			// save this data to the answer object
1189
+			$this->_registration_answers[$answer_cache_id]->set_value($input_value);
1190
+			$result = $this->_registration_answers[$answer_cache_id]->save();
1191
+			return $result !== false ? true : false;
1192
+		} else {
1193
+			foreach ($this->_registration_answers as $answer) {
1194
+				if ($answer instanceof EE_Answer && $answer->question_ID() === $answer_cache_id) {
1195
+					$answer->set_value($input_value);
1196
+					$result = $answer->save();
1197
+					return $result !== false ? true : false;
1198
+				}
1199
+			}
1200
+		}
1201
+		return false;
1202
+	}
1203
+
1204
+
1205
+	/**
1206
+	 *    _verify_critical_attendee_details_are_set
1207
+	 *
1208
+	 * @param string $form_input
1209
+	 * @param string $input_value
1210
+	 * @return boolean
1211
+	 */
1212
+	private function _verify_critical_attendee_details_are_set_and_validate_email(
1213
+		$form_input = '',
1214
+		$input_value = ''
1215
+	) {
1216
+		if (empty($input_value)) {
1217
+			// if the form input isn't marked as being required, then just return
1218
+			if (! isset($this->_required_questions[$form_input]) || ! $this->_required_questions[$form_input]) {
1219
+				return true;
1220
+			}
1221
+			switch ($form_input) {
1222
+				case 'fname':
1223
+					EE_Error::add_error(
1224
+						esc_html__('First Name is a required value.', 'event_espresso'),
1225
+						__FILE__,
1226
+						__FUNCTION__,
1227
+						__LINE__
1228
+					);
1229
+					return false;
1230
+					break;
1231
+				case 'lname':
1232
+					EE_Error::add_error(
1233
+						esc_html__('Last Name is a required value.', 'event_espresso'),
1234
+						__FILE__,
1235
+						__FUNCTION__,
1236
+						__LINE__
1237
+					);
1238
+					return false;
1239
+					break;
1240
+				case 'email':
1241
+					EE_Error::add_error(
1242
+						esc_html__('Please enter a valid email address.', 'event_espresso'),
1243
+						__FILE__,
1244
+						__FUNCTION__,
1245
+						__LINE__
1246
+					);
1247
+					return false;
1248
+					break;
1249
+			}
1250
+		}
1251
+		return true;
1252
+	}
1253
+
1254
+
1255
+	/**
1256
+	 *    _associate_attendee_with_registration
1257
+	 *
1258
+	 * @param EE_Registration $registration
1259
+	 * @param EE_Attendee     $attendee
1260
+	 * @return void
1261
+	 * @throws EE_Error
1262
+	 * @throws RuntimeException
1263
+	 */
1264
+	private function _associate_attendee_with_registration(EE_Registration $registration, EE_Attendee $attendee)
1265
+	{
1266
+		// add relation to attendee
1267
+		$registration->_add_relation_to($attendee, 'Attendee');
1268
+		$registration->set_attendee_id($attendee->ID());
1269
+		$registration->update_cache_after_object_save('Attendee', $attendee);
1270
+	}
1271
+
1272
+
1273
+	/**
1274
+	 *    _associate_registration_with_transaction
1275
+	 *
1276
+	 * @param EE_Registration $registration
1277
+	 * @return void
1278
+	 * @throws \EE_Error
1279
+	 */
1280
+	private function _associate_registration_with_transaction(EE_Registration $registration)
1281
+	{
1282
+		// add relation to registration
1283
+		$this->checkout->transaction->_add_relation_to($registration, 'Registration');
1284
+		$this->checkout->transaction->update_cache_after_object_save('Registration', $registration);
1285
+	}
1286
+
1287
+
1288
+	/**
1289
+	 *    _copy_critical_attendee_details_from_primary_registrant
1290
+	 *    ensures that all attendees at least have data for first name, last name, and email address
1291
+	 *
1292
+	 * @param array $attendee_data
1293
+	 * @return array
1294
+	 * @throws \EE_Error
1295
+	 */
1296
+	private function _copy_critical_attendee_details_from_primary_registrant($attendee_data = array())
1297
+	{
1298
+		// bare minimum critical details include first name, last name, email address
1299
+		$critical_attendee_details = array('ATT_fname', 'ATT_lname', 'ATT_email');
1300
+		// add address info to critical details?
1301
+		if (apply_filters(
1302
+			'FHEE__EE_SPCO_Reg_Step_Attendee_Information__merge_address_details_with_critical_attendee_details',
1303
+			false
1304
+		)) {
1305
+			$address_details           = array(
1306
+				'ATT_address',
1307
+				'ATT_address2',
1308
+				'ATT_city',
1309
+				'STA_ID',
1310
+				'CNT_ISO',
1311
+				'ATT_zip',
1312
+				'ATT_phone',
1313
+			);
1314
+			$critical_attendee_details = array_merge($critical_attendee_details, $address_details);
1315
+		}
1316
+		foreach ($critical_attendee_details as $critical_attendee_detail) {
1317
+			if (! isset($attendee_data[$critical_attendee_detail])
1318
+				|| empty($attendee_data[$critical_attendee_detail])
1319
+			) {
1320
+				$attendee_data[$critical_attendee_detail] = $this->checkout->primary_attendee_obj->get(
1321
+					$critical_attendee_detail
1322
+				);
1323
+			}
1324
+		}
1325
+		return $attendee_data;
1326
+	}
1327
+
1328
+
1329
+	/**
1330
+	 *    update_reg_step
1331
+	 *    this is the final step after a user  revisits the site to edit their attendee information
1332
+	 *    this gets called AFTER the process_reg_step() method above
1333
+	 *
1334
+	 * @return bool
1335
+	 * @throws EE_Error
1336
+	 * @throws InvalidArgumentException
1337
+	 * @throws ReflectionException
1338
+	 * @throws RuntimeException
1339
+	 * @throws \EventEspresso\core\exceptions\InvalidDataTypeException
1340
+	 * @throws \EventEspresso\core\exceptions\InvalidInterfaceException
1341
+	 */
1342
+	public function update_reg_step()
1343
+	{
1344
+		// save everything
1345
+		if ($this->process_reg_step()) {
1346
+			$this->checkout->redirect     = true;
1347
+			$this->checkout->redirect_url = add_query_arg(
1348
+				array(
1349
+					'e_reg_url_link' => $this->checkout->reg_url_link,
1350
+					'revisit'        => true,
1351
+				),
1352
+				$this->checkout->thank_you_page_url
1353
+			);
1354
+			$this->checkout->json_response->set_redirect_url($this->checkout->redirect_url);
1355
+			return true;
1356
+		}
1357
+		return false;
1358
+	}
1359 1359
 }
Please login to merge, or discard this patch.
Spacing   +51 added lines, -52 removed lines patch added patch discarded remove patch
@@ -48,7 +48,7 @@  discard block
 block discarded – undo
48 48
     {
49 49
         $this->_slug     = 'attendee_information';
50 50
         $this->_name     = esc_html__('Attendee Information', 'event_espresso');
51
-        $this->_template = SPCO_REG_STEPS_PATH . $this->_slug . DS . 'attendee_info_main.template.php';
51
+        $this->_template = SPCO_REG_STEPS_PATH.$this->_slug.DS.'attendee_info_main.template.php';
52 52
         $this->checkout  = $checkout;
53 53
         $this->_reset_success_message();
54 54
         $this->set_instructions(
@@ -59,11 +59,11 @@  discard block
 block discarded – undo
59 59
 
60 60
     public function translate_js_strings()
61 61
     {
62
-        EE_Registry::$i18n_js_strings['required_field']            = esc_html__(
62
+        EE_Registry::$i18n_js_strings['required_field'] = esc_html__(
63 63
             ' is a required question.',
64 64
             'event_espresso'
65 65
         );
66
-        EE_Registry::$i18n_js_strings['required_multi_field']      = esc_html__(
66
+        EE_Registry::$i18n_js_strings['required_multi_field'] = esc_html__(
67 67
             ' is a required question. Please enter a value for at least one of the options.',
68 68
             'event_espresso'
69 69
         );
@@ -71,18 +71,18 @@  discard block
 block discarded – undo
71 71
             'Please answer all required questions correctly before proceeding.',
72 72
             'event_espresso'
73 73
         );
74
-        EE_Registry::$i18n_js_strings['attendee_info_copied']      = sprintf(
74
+        EE_Registry::$i18n_js_strings['attendee_info_copied'] = sprintf(
75 75
             esc_html__(
76 76
                 'The attendee information was successfully copied.%sPlease ensure the rest of the registration form is completed before proceeding.',
77 77
                 'event_espresso'
78 78
             ),
79 79
             '<br/>'
80 80
         );
81
-        EE_Registry::$i18n_js_strings['attendee_info_copy_error']  = esc_html__(
81
+        EE_Registry::$i18n_js_strings['attendee_info_copy_error'] = esc_html__(
82 82
             'An unknown error occurred on the server while attempting to copy the attendee information. Please refresh the page and try again.',
83 83
             'event_espresso'
84 84
         );
85
-        EE_Registry::$i18n_js_strings['enter_valid_email']         = esc_html__(
85
+        EE_Registry::$i18n_js_strings['enter_valid_email'] = esc_html__(
86 86
             'You must enter a valid email address.',
87 87
             'event_espresso'
88 88
         );
@@ -145,7 +145,7 @@  discard block
 block discarded – undo
145 145
                     && $this->checkout->visit_allows_processing_of_this_registration($registration)
146 146
                 ) {
147 147
                     $subsections[$registration->reg_url_link()] = $this->_registrations_reg_form($registration);
148
-                    if (! $this->checkout->admin_request) {
148
+                    if ( ! $this->checkout->admin_request) {
149 149
                         $template_args['registrations'][$registration->reg_url_link()]    = $registration;
150 150
                         $template_args['ticket_count'][$registration->ticket()->ID()]     = isset(
151 151
                             $template_args['ticket_count'][$registration->ticket()->ID()]
@@ -194,8 +194,7 @@  discard block
 block discarded – undo
194 194
                 'html_id'         => $this->reg_form_name(),
195 195
                 'subsections'     => $subsections,
196 196
                 'layout_strategy' => $this->checkout->admin_request ?
197
-                    new EE_Div_Per_Section_Layout() :
198
-                    new EE_Template_Layout(
197
+                    new EE_Div_Per_Section_Layout() : new EE_Template_Layout(
199 198
                         array(
200 199
                             'layout_template_file' => $this->_template, // layout_template
201 200
                             'template_args'        => $template_args,
@@ -238,7 +237,7 @@  discard block
 block discarded – undo
238 237
             if ($question_groups) {
239 238
                 // array of params to pass to parent constructor
240 239
                 $form_args = array(
241
-                    'html_id'         => 'ee-registration-' . $registration->reg_url_link(),
240
+                    'html_id'         => 'ee-registration-'.$registration->reg_url_link(),
242 241
                     'html_class'      => 'ee-reg-form-attendee-dv',
243 242
                     'html_style'      => $this->checkout->admin_request
244 243
                         ? 'padding:0em 2em 1em; margin:3em 0 0; border:1px solid #ddd;'
@@ -294,7 +293,7 @@  discard block
 block discarded – undo
294 293
         // generate hidden input
295 294
         return new EE_Hidden_Input(
296 295
             array(
297
-                'html_id' => 'additional-attendee-reg-info-' . $registration->reg_url_link(),
296
+                'html_id' => 'additional-attendee-reg-info-'.$registration->reg_url_link(),
298 297
                 'default' => $additional_attendee_reg_info,
299 298
             )
300 299
         );
@@ -314,11 +313,11 @@  discard block
 block discarded – undo
314 313
     {
315 314
         // array of params to pass to parent constructor
316 315
         $form_args = array(
317
-            'html_id'         => 'ee-reg-form-qstn-grp-' . $question_group->identifier() . '-' . $registration->ID(),
316
+            'html_id'         => 'ee-reg-form-qstn-grp-'.$question_group->identifier().'-'.$registration->ID(),
318 317
             'html_class'      => $this->checkout->admin_request
319 318
                 ? 'form-table ee-reg-form-qstn-grp-dv'
320 319
                 : 'ee-reg-form-qstn-grp-dv',
321
-            'html_label_id'   => 'ee-reg-form-qstn-grp-' . $question_group->identifier() .  '-' . $registration->ID() . '-lbl',
320
+            'html_label_id'   => 'ee-reg-form-qstn-grp-'.$question_group->identifier().'-'.$registration->ID().'-lbl',
322 321
             'subsections'     => array(
323 322
                 'reg_form_qstn_grp_hdr' => $this->_question_group_header($question_group),
324 323
             ),
@@ -329,7 +328,7 @@  discard block
 block discarded – undo
329 328
         // where params
330 329
         $query_params = array('QST_deleted' => 0);
331 330
         // don't load admin only questions on the frontend
332
-        if (! $this->checkout->admin_request) {
331
+        if ( ! $this->checkout->admin_request) {
333 332
             $query_params['QST_admin_only'] = array('!=', true);
334 333
         }
335 334
         $questions = $question_group->get_many_related(
@@ -473,7 +472,7 @@  discard block
 block discarded – undo
473 472
     {
474 473
         return new EE_Form_Section_HTML(
475 474
             EEH_Template::locate_template(
476
-                SPCO_REG_STEPS_PATH . $this->_slug . DS . '_auto_copy_attendee_info.template.php',
475
+                SPCO_REG_STEPS_PATH.$this->_slug.DS.'_auto_copy_attendee_info.template.php',
477 476
                 apply_filters(
478 477
                     'FHEE__EE_SPCO_Reg_Step_Attendee_Information__auto_copy_attendee_info__template_args',
479 478
                     array()
@@ -505,16 +504,16 @@  discard block
 block discarded – undo
505 504
                 if ($registration->ticket()->ID() !== $prev_ticket) {
506 505
                     $item_name = $registration->ticket()->name();
507 506
                     $item_name .= $registration->ticket()->description() !== ''
508
-                        ? ' - ' . $registration->ticket()->description()
507
+                        ? ' - '.$registration->ticket()->description()
509 508
                         : '';
510
-                    $copy_attendee_info_inputs['spco_copy_attendee_chk[ticket-' . $registration->ticket()->ID() . ']'] =
509
+                    $copy_attendee_info_inputs['spco_copy_attendee_chk[ticket-'.$registration->ticket()->ID().']'] =
511 510
                         new EE_Form_Section_HTML(
512
-                            '<h6 class="spco-copy-attendee-event-hdr">' . $item_name . '</h6>'
511
+                            '<h6 class="spco-copy-attendee-event-hdr">'.$item_name.'</h6>'
513 512
                         );
514 513
                     $prev_ticket = $registration->ticket()->ID();
515 514
                 }
516 515
 
517
-                $copy_attendee_info_inputs['spco_copy_attendee_chk[' . $registration->ID() . ']'] =
516
+                $copy_attendee_info_inputs['spco_copy_attendee_chk['.$registration->ID().']'] =
518 517
                     new EE_Checkbox_Multi_Input(
519 518
                         array(
520 519
                             $registration->ID() => sprintf(
@@ -523,7 +522,7 @@  discard block
 block discarded – undo
523 522
                             ),
524 523
                         ),
525 524
                         array(
526
-                            'html_id'                 => 'spco-copy-attendee-chk-' . $registration->reg_url_link(),
525
+                            'html_id'                 => 'spco-copy-attendee-chk-'.$registration->reg_url_link(),
527 526
                             'html_class'              => 'spco-copy-attendee-chk ee-do-not-validate',
528 527
                             'display_html_label_text' => false,
529 528
                         )
@@ -572,7 +571,7 @@  discard block
 block discarded – undo
572 571
             $registration,
573 572
             $question->system_ID()
574 573
         );
575
-        $answer       = $answer_value === null
574
+        $answer = $answer_value === null
576 575
             ? EEM_Answer::instance()->get_one(
577 576
                 array(array('QST_ID' => $question->ID(), 'REG_ID' => $registration->ID()))
578 577
             )
@@ -589,14 +588,14 @@  discard block
 block discarded – undo
589 588
         }
590 589
         // verify instance
591 590
         if ($answer instanceof EE_Answer) {
592
-            if (! empty($answer_value)) {
591
+            if ( ! empty($answer_value)) {
593 592
                 $answer->set('ANS_value', $answer_value);
594 593
             }
595 594
             $answer->cache('Question', $question);
596 595
             //remember system ID had a bug where sometimes it could be null
597 596
             $answer_cache_id = $question->is_system_question()
598
-                ? $question->system_ID() . '-' . $registration->reg_url_link()
599
-                : $question->ID() . '-' . $registration->reg_url_link();
597
+                ? $question->system_ID().'-'.$registration->reg_url_link()
598
+                : $question->ID().'-'.$registration->reg_url_link();
600 599
             $registration->cache('Answer', $answer, $answer_cache_id);
601 600
         }
602 601
         return $this->_generate_question_input($registration, $question, $answer);
@@ -628,18 +627,18 @@  discard block
 block discarded – undo
628 627
             10,
629 628
             4
630 629
         );
631
-        $input_constructor_args                  = array(
632
-            'html_name'        => 'ee_reg_qstn[' . $registration->ID() . '][' . $identifier . ']',
633
-            'html_id'          => 'ee_reg_qstn-' . $registration->ID() . '-' . $identifier,
634
-            'html_class'       => 'ee-reg-qstn ee-reg-qstn-' . $identifier,
635
-            'html_label_id'    => 'ee_reg_qstn-' . $registration->ID() . '-' . $identifier,
630
+        $input_constructor_args = array(
631
+            'html_name'        => 'ee_reg_qstn['.$registration->ID().']['.$identifier.']',
632
+            'html_id'          => 'ee_reg_qstn-'.$registration->ID().'-'.$identifier,
633
+            'html_class'       => 'ee-reg-qstn ee-reg-qstn-'.$identifier,
634
+            'html_label_id'    => 'ee_reg_qstn-'.$registration->ID().'-'.$identifier,
636 635
             'html_label_class' => 'ee-reg-qstn',
637 636
         );
638 637
         $input_constructor_args['html_label_id'] .= '-lbl';
639 638
         if ($answer instanceof EE_Answer && $answer->ID()) {
640
-            $input_constructor_args['html_name']     .= '[' . $answer->ID() . ']';
641
-            $input_constructor_args['html_id']       .= '-' . $answer->ID();
642
-            $input_constructor_args['html_label_id'] .= '-' . $answer->ID();
639
+            $input_constructor_args['html_name']     .= '['.$answer->ID().']';
640
+            $input_constructor_args['html_id']       .= '-'.$answer->ID();
641
+            $input_constructor_args['html_label_id'] .= '-'.$answer->ID();
643 642
         }
644 643
         $form_input = $question->generate_form_input(
645 644
             $registration,
@@ -682,7 +681,7 @@  discard block
 block discarded – undo
682 681
         $countries = $this->checkout->action === 'process_reg_step'
683 682
             ? EEM_Country::instance()->get_all_countries()
684 683
             : EEM_Country::instance()->get_all_active_countries();
685
-        if (! empty($countries)) {
684
+        if ( ! empty($countries)) {
686 685
             foreach ($countries as $country) {
687 686
                 if ($country instanceof EE_Country) {
688 687
                     $country_options[$country->ID()] = $country->name();
@@ -732,7 +731,7 @@  discard block
 block discarded – undo
732 731
         $states        = $this->checkout->action === 'process_reg_step'
733 732
             ? EEM_State::instance()->get_all_states()
734 733
             : EEM_State::instance()->get_all_active_states();
735
-        if (! empty($states)) {
734
+        if ( ! empty($states)) {
736 735
             foreach ($states as $state) {
737 736
                 if ($state instanceof EE_State) {
738 737
                     $state_options[$state->country()->name()][$state->ID()] = $state->name();
@@ -784,7 +783,7 @@  discard block
 block discarded – undo
784 783
             );
785 784
             return false;
786 785
         }
787
-        if (! $this->checkout->transaction instanceof EE_Transaction || ! $this->checkout->continue_reg) {
786
+        if ( ! $this->checkout->transaction instanceof EE_Transaction || ! $this->checkout->continue_reg) {
788 787
             EE_Error::add_error(
789 788
                 esc_html__(
790 789
                     'A valid transaction could not be initiated for processing your registrations.',
@@ -801,10 +800,10 @@  discard block
 block discarded – undo
801 800
         // verify we got the goods
802 801
         if (empty($registrations)) {
803 802
             //combine the old translated string with a new one, in order to not break translations
804
-            $error_message = esc_html__( 'Your form data could not be applied to any valid registrations.', 'event_espresso' )
803
+            $error_message = esc_html__('Your form data could not be applied to any valid registrations.', 'event_espresso')
805 804
                              . sprintf(
806 805
                                  esc_html__('%3$sThis can sometimes happen if too much time has been taken to complete the registration process.%3$sPlease return to the %1$sEvent List%2$s and reselect your tickets. If the problem continues, please contact the site administrator.', 'event_espresso'),
807
-                                 '<a href="' . get_post_type_archive_link('espresso_events') . '" >',
806
+                                 '<a href="'.get_post_type_archive_link('espresso_events').'" >',
808 807
                                  '</a>',
809 808
                                  '<br />'
810 809
                              );
@@ -823,7 +822,7 @@  discard block
 block discarded – undo
823 822
         if ($registrations_processed === false) {
824 823
             // but return immediately if the previous step exited early due to errors
825 824
             return false;
826
-        } elseif (! $this->checkout->revisit && $registrations_processed !== $this->checkout->total_ticket_count) {
825
+        } elseif ( ! $this->checkout->revisit && $registrations_processed !== $this->checkout->total_ticket_count) {
827 826
             // generate a correctly translated string for all possible singular/plural combinations
828 827
             if ($this->checkout->total_ticket_count === 1 && $registrations_processed !== 1) {
829 828
                 $error_msg = sprintf(
@@ -904,7 +903,7 @@  discard block
 block discarded – undo
904 903
         // grab the saved registrations from the transaction
905 904
         foreach ($registrations as $registration) {
906 905
             // verify EE_Registration object
907
-            if (! $registration instanceof EE_Registration) {
906
+            if ( ! $registration instanceof EE_Registration) {
908 907
                 EE_Error::add_error(
909 908
                     esc_html__(
910 909
                         'An invalid Registration object was discovered when attempting to process your registration information.',
@@ -919,12 +918,12 @@  discard block
 block discarded – undo
919 918
             /** @var string $reg_url_link */
920 919
             $reg_url_link = $registration->reg_url_link();
921 920
             // reg_url_link exists ?
922
-            if (! empty($reg_url_link)) {
921
+            if ( ! empty($reg_url_link)) {
923 922
                 // should this registration be processed during this visit ?
924 923
                 if ($this->checkout->visit_allows_processing_of_this_registration($registration)) {
925 924
                     // if NOT revisiting, then let's save the registration now,
926 925
                     // so that we have a REG_ID to use when generating other objects
927
-                    if (! $this->checkout->revisit) {
926
+                    if ( ! $this->checkout->revisit) {
928 927
                         $registration->save();
929 928
                     }
930 929
                     /**
@@ -959,7 +958,7 @@  discard block
 block discarded – undo
959 958
                             ? true
960 959
                             : false;
961 960
                         // filter form input data for this registration
962
-                        $valid_data[$reg_url_link] = (array)apply_filters(
961
+                        $valid_data[$reg_url_link] = (array) apply_filters(
963 962
                             'FHEE__EE_Single_Page_Checkout__process_attendee_information__valid_data_line_item',
964 963
                             $valid_data[$reg_url_link]
965 964
                         );
@@ -971,11 +970,11 @@  discard block
 block discarded – undo
971 970
                         }
972 971
                         // now loop through our array of valid post data && process attendee reg forms
973 972
                         foreach ($valid_data[$reg_url_link] as $form_section => $form_inputs) {
974
-                            if (! in_array($form_section, $non_input_form_sections)) {
973
+                            if ( ! in_array($form_section, $non_input_form_sections)) {
975 974
                                 foreach ($form_inputs as $form_input => $input_value) {
976 975
                                     // \EEH_Debug_Tools::printr( $input_value, $form_input, __FILE__, __LINE__ );
977 976
                                     // check for critical inputs
978
-                                    if (! $this->_verify_critical_attendee_details_are_set_and_validate_email(
977
+                                    if ( ! $this->_verify_critical_attendee_details_are_set_and_validate_email(
979 978
                                         $form_input,
980 979
                                         $input_value
981 980
                                     )
@@ -995,7 +994,7 @@  discard block
 block discarded – undo
995 994
                                         $input_value = $primary_registrant[$form_input];
996 995
                                     }
997 996
                                     // now attempt to save the input data
998
-                                    if (! $this->_save_registration_form_input(
997
+                                    if ( ! $this->_save_registration_form_input(
999 998
                                         $registration,
1000 999
                                         $form_input,
1001 1000
                                         $input_value
@@ -1051,7 +1050,7 @@  discard block
 block discarded – undo
1051 1050
                     // add relation to registration, set attendee ID, and cache attendee
1052 1051
                     $this->_associate_attendee_with_registration($registration, $attendee);
1053 1052
                     // \EEH_Debug_Tools::printr( $registration, '$registration', __FILE__, __LINE__ );
1054
-                    if (! $registration->attendee() instanceof EE_Attendee) {
1053
+                    if ( ! $registration->attendee() instanceof EE_Attendee) {
1055 1054
                         EE_Error::add_error(
1056 1055
                             sprintf(
1057 1056
                                 esc_html__(
@@ -1146,7 +1145,7 @@  discard block
 block discarded – undo
1146 1145
          * @see https://events.codebasehq.com/projects/event-espresso/tickets/10477
1147 1146
          */
1148 1147
         $answer_cache_id = $this->checkout->reg_url_link
1149
-            ? $form_input . '-' . $registration->reg_url_link()
1148
+            ? $form_input.'-'.$registration->reg_url_link()
1150 1149
             : $form_input;
1151 1150
         $answer_is_obj   = isset($this->_registration_answers[$answer_cache_id])
1152 1151
                            && $this->_registration_answers[$answer_cache_id] instanceof EE_Answer
@@ -1167,10 +1166,10 @@  discard block
 block discarded – undo
1167 1166
                 break;
1168 1167
 
1169 1168
             default:
1170
-                $ATT_input = 'ATT_' . $form_input;
1169
+                $ATT_input = 'ATT_'.$form_input;
1171 1170
                 //EEH_Debug_Tools::printr( $ATT_input, '$ATT_input', __FILE__, __LINE__ );
1172 1171
                 $attendee_property = EEM_Attendee::instance()->has_field($ATT_input) ? true : false;
1173
-                $form_input        = $attendee_property ? 'ATT_' . $form_input : $form_input;
1172
+                $form_input        = $attendee_property ? 'ATT_'.$form_input : $form_input;
1174 1173
         }
1175 1174
         // EEH_Debug_Tools::printr( $answer_cache_id, '$answer_cache_id', __FILE__, __LINE__ );
1176 1175
         // EEH_Debug_Tools::printr( $attendee_property, '$attendee_property', __FILE__, __LINE__ );
@@ -1215,7 +1214,7 @@  discard block
 block discarded – undo
1215 1214
     ) {
1216 1215
         if (empty($input_value)) {
1217 1216
             // if the form input isn't marked as being required, then just return
1218
-            if (! isset($this->_required_questions[$form_input]) || ! $this->_required_questions[$form_input]) {
1217
+            if ( ! isset($this->_required_questions[$form_input]) || ! $this->_required_questions[$form_input]) {
1219 1218
                 return true;
1220 1219
             }
1221 1220
             switch ($form_input) {
@@ -1302,7 +1301,7 @@  discard block
 block discarded – undo
1302 1301
             'FHEE__EE_SPCO_Reg_Step_Attendee_Information__merge_address_details_with_critical_attendee_details',
1303 1302
             false
1304 1303
         )) {
1305
-            $address_details           = array(
1304
+            $address_details = array(
1306 1305
                 'ATT_address',
1307 1306
                 'ATT_address2',
1308 1307
                 'ATT_city',
@@ -1314,7 +1313,7 @@  discard block
 block discarded – undo
1314 1313
             $critical_attendee_details = array_merge($critical_attendee_details, $address_details);
1315 1314
         }
1316 1315
         foreach ($critical_attendee_details as $critical_attendee_detail) {
1317
-            if (! isset($attendee_data[$critical_attendee_detail])
1316
+            if ( ! isset($attendee_data[$critical_attendee_detail])
1318 1317
                 || empty($attendee_data[$critical_attendee_detail])
1319 1318
             ) {
1320 1319
                 $attendee_data[$critical_attendee_detail] = $this->checkout->primary_attendee_obj->get(
Please login to merge, or discard this patch.
core/services/request/middleware/RecommendedVersions.php 2 patches
Indentation   +175 added lines, -175 removed lines patch added patch discarded remove patch
@@ -23,186 +23,186 @@
 block discarded – undo
23 23
 class RecommendedVersions extends Middleware
24 24
 {
25 25
 
26
-    /**
27
-     * converts a Request to a Response
28
-     *
29
-     * @param RequestInterface $request
30
-     * @param ResponseInterface      $response
31
-     * @return ResponseInterface
32
-     * @throws InvalidDataTypeException
33
-     */
34
-    public function handleRequest(RequestInterface $request, ResponseInterface $response)
35
-    {
36
-        $this->request  = $request;
37
-        $this->response = $response;
38
-        // check required WP version
39
-        if (! $this->minimumWordPressVersionRequired()) {
40
-            $this->request->unSetRequestParam('activate', true);
41
-            add_action('admin_notices', array($this, 'minimum_wp_version_error'), 1);
42
-            $this->response->terminateRequest();
43
-            $this->response->deactivatePlugin();
44
-        }
45
-        // check recommended PHP version
46
-        if (! $this->minimumPhpVersionRecommended()) {
47
-            $this->displayMinimumRecommendedPhpVersionNotice();
48
-        }
49
-        //upcoming required version
50
-        if (! $this->upcomingRequiredPhpVersion()) {
51
-            $this->displayUpcomingRequiredVersion();
52
-        }
53
-        $this->response = $this->processRequestStack($this->request, $this->response);
54
-        return $this->response;
55
-    }
56
-
57
-
58
-    /**
59
-     * Helper method to assess installed wp version against given values.
60
-     * By default this compares the required minimum version of WP for EE against the installed version of WP
61
-     * Note, $wp_version is the first parameter sent into the PHP version_compare function (what is being checked
62
-     * against) so consider that when sending in your values.
63
-     *
64
-     * @param string $version_to_check
65
-     * @param string $operator
66
-     * @return bool
67
-     */
68
-    public static function compareWordPressVersion($version_to_check = EE_MIN_WP_VER_REQUIRED, $operator = '>=')
69
-    {
70
-        global $wp_version;
71
-        return version_compare(
72
-        // first account for wp_version being pre-release
73
-        // (like RC, beta etc) which are usually in the format like 4.7-RC3-39519
74
-            strpos($wp_version, '-') > 0
75
-                ? substr($wp_version, 0, strpos($wp_version, '-'))
76
-                : $wp_version,
77
-            $version_to_check,
78
-            $operator
79
-        );
80
-    }
81
-
82
-
83
-
84
-    /**
85
-     * @return boolean
86
-     */
87
-    private function minimumWordPressVersionRequired()
88
-    {
89
-        return RecommendedVersions::compareWordPressVersion();
90
-    }
91
-
92
-
93
-
94
-    /**
95
-     * @param string $min_version
96
-     * @return boolean
97
-     */
98
-    private function checkPhpVersion($min_version = EE_MIN_PHP_VER_RECOMMENDED)
99
-    {
100
-        return version_compare(PHP_VERSION, $min_version, '>=') ? true : false;
101
-    }
102
-
103
-
104
-
105
-    /**
106
-     * @return boolean
107
-     */
108
-    private function minimumPhpVersionRecommended()
109
-    {
110
-        return $this->checkPhpVersion();
111
-    }
112
-
113
-
114
-
115
-    /**
116
-     * @return void
117
-     */
118
-    public function minimumWpVersionError()
119
-    {
120
-        global $wp_version;
121
-        ?>
26
+	/**
27
+	 * converts a Request to a Response
28
+	 *
29
+	 * @param RequestInterface $request
30
+	 * @param ResponseInterface      $response
31
+	 * @return ResponseInterface
32
+	 * @throws InvalidDataTypeException
33
+	 */
34
+	public function handleRequest(RequestInterface $request, ResponseInterface $response)
35
+	{
36
+		$this->request  = $request;
37
+		$this->response = $response;
38
+		// check required WP version
39
+		if (! $this->minimumWordPressVersionRequired()) {
40
+			$this->request->unSetRequestParam('activate', true);
41
+			add_action('admin_notices', array($this, 'minimum_wp_version_error'), 1);
42
+			$this->response->terminateRequest();
43
+			$this->response->deactivatePlugin();
44
+		}
45
+		// check recommended PHP version
46
+		if (! $this->minimumPhpVersionRecommended()) {
47
+			$this->displayMinimumRecommendedPhpVersionNotice();
48
+		}
49
+		//upcoming required version
50
+		if (! $this->upcomingRequiredPhpVersion()) {
51
+			$this->displayUpcomingRequiredVersion();
52
+		}
53
+		$this->response = $this->processRequestStack($this->request, $this->response);
54
+		return $this->response;
55
+	}
56
+
57
+
58
+	/**
59
+	 * Helper method to assess installed wp version against given values.
60
+	 * By default this compares the required minimum version of WP for EE against the installed version of WP
61
+	 * Note, $wp_version is the first parameter sent into the PHP version_compare function (what is being checked
62
+	 * against) so consider that when sending in your values.
63
+	 *
64
+	 * @param string $version_to_check
65
+	 * @param string $operator
66
+	 * @return bool
67
+	 */
68
+	public static function compareWordPressVersion($version_to_check = EE_MIN_WP_VER_REQUIRED, $operator = '>=')
69
+	{
70
+		global $wp_version;
71
+		return version_compare(
72
+		// first account for wp_version being pre-release
73
+		// (like RC, beta etc) which are usually in the format like 4.7-RC3-39519
74
+			strpos($wp_version, '-') > 0
75
+				? substr($wp_version, 0, strpos($wp_version, '-'))
76
+				: $wp_version,
77
+			$version_to_check,
78
+			$operator
79
+		);
80
+	}
81
+
82
+
83
+
84
+	/**
85
+	 * @return boolean
86
+	 */
87
+	private function minimumWordPressVersionRequired()
88
+	{
89
+		return RecommendedVersions::compareWordPressVersion();
90
+	}
91
+
92
+
93
+
94
+	/**
95
+	 * @param string $min_version
96
+	 * @return boolean
97
+	 */
98
+	private function checkPhpVersion($min_version = EE_MIN_PHP_VER_RECOMMENDED)
99
+	{
100
+		return version_compare(PHP_VERSION, $min_version, '>=') ? true : false;
101
+	}
102
+
103
+
104
+
105
+	/**
106
+	 * @return boolean
107
+	 */
108
+	private function minimumPhpVersionRecommended()
109
+	{
110
+		return $this->checkPhpVersion();
111
+	}
112
+
113
+
114
+
115
+	/**
116
+	 * @return void
117
+	 */
118
+	public function minimumWpVersionError()
119
+	{
120
+		global $wp_version;
121
+		?>
122 122
         <div class="error">
123 123
             <p>
124 124
                 <?php
125
-                printf(
126
-                    __('We\'re sorry, but Event Espresso requires WordPress version %1$s or greater in order to operate. You are currently running version %2$s.%3$sFor information on how to update your version of WordPress, please go to %4$s.',
127
-                        'event_espresso'),
128
-                    EE_MIN_WP_VER_REQUIRED,
129
-                    $wp_version,
130
-                    '<br/>',
131
-                    '<a href="http://codex.wordpress.org/Updating_WordPress">http://codex.wordpress.org/Updating_WordPress</a>'
132
-                );
133
-                ?>
125
+				printf(
126
+					__('We\'re sorry, but Event Espresso requires WordPress version %1$s or greater in order to operate. You are currently running version %2$s.%3$sFor information on how to update your version of WordPress, please go to %4$s.',
127
+						'event_espresso'),
128
+					EE_MIN_WP_VER_REQUIRED,
129
+					$wp_version,
130
+					'<br/>',
131
+					'<a href="http://codex.wordpress.org/Updating_WordPress">http://codex.wordpress.org/Updating_WordPress</a>'
132
+				);
133
+				?>
134 134
             </p>
135 135
         </div>
136 136
         <?php
137
-    }
138
-
139
-
140
-
141
-    /**
142
-     *    _display_minimum_recommended_php_version_notice
143
-     *
144
-     * @access private
145
-     * @return void
146
-     * @throws InvalidDataTypeException
147
-     */
148
-    private function displayMinimumRecommendedPhpVersionNotice()
149
-    {
150
-        if ($this->request->isAdmin()) {
151
-            new PersistentAdminNotice(
152
-                'php_version_' . str_replace('.', '-', EE_MIN_PHP_VER_RECOMMENDED) . '_recommended',
153
-                sprintf(
154
-                    esc_html__(
155
-                        'Event Espresso recommends PHP version %1$s or greater for optimal performance. You are currently running version %2$s.%3$sIn order to update your version of PHP, you will need to contact your current hosting provider.%3$sFor information on stable PHP versions, please go to %4$s.',
156
-                        'event_espresso'
157
-                    ),
158
-                    EE_MIN_PHP_VER_RECOMMENDED,
159
-                    PHP_VERSION,
160
-                    '<br/>',
161
-                    '<a href="http://php.net/downloads.php">http://php.net/downloads.php</a>'
162
-                )
163
-            );
164
-        }
165
-    }
166
-
167
-
168
-    /**
169
-     * Returns whether the provided php version number is greater than the current version of php installed on the server.
170
-     *
171
-     * @param string $version_required
172
-     * @return bool
173
-     */
174
-    private function upcomingRequiredPhpVersion($version_required = '5.5')
175
-    {
176
-        return $this->checkPhpVersion($version_required);
177
-    }
178
-
179
-
180
-    /**
181
-     *  Sets a notice for an upcoming required version of PHP in the next update of EE core.
182
-     */
183
-    private function displayUpcomingRequiredVersion()
184
-    {
185
-        if ($this->request->isAdmin()
186
-            && apply_filters('FHEE__EE_Recommended_Versions__displayUpcomingRequiredVersion', true, $this->request)
187
-            && current_user_can('update_plugins')
188
-        ) {
189
-            add_action('admin_notices', function ()
190
-            {
191
-                echo '<div class="notice event-espresso-admin-notice notice-warning"><p>'
192
-                     . sprintf(
193
-                         esc_html__(
194
-                             'Please note: The next update of Event Espresso 4 will %1$srequire%2$s PHP 5.4.45 or greater.  Your web server\'s PHP version is %3$s.  You can contact your host and ask them to update your PHP version to at least PHP 5.6.  Please do not update to the new version of Event Espresso 4 until the PHP update is completed. Read about why keeping your server on the latest version of PHP is a good idea %4$shere%5$s',
195
-                             'event_espresso'
196
-                         ),
197
-                         '<strong>',
198
-                         '</strong>',
199
-                         PHP_VERSION,
200
-                         '<a href="https://wordpress.org/support/upgrade-php/">',
201
-                         '</a>'
202
-                     )
203
-                     . '</p></div>';
204
-            });
205
-        }
206
-    }
137
+	}
138
+
139
+
140
+
141
+	/**
142
+	 *    _display_minimum_recommended_php_version_notice
143
+	 *
144
+	 * @access private
145
+	 * @return void
146
+	 * @throws InvalidDataTypeException
147
+	 */
148
+	private function displayMinimumRecommendedPhpVersionNotice()
149
+	{
150
+		if ($this->request->isAdmin()) {
151
+			new PersistentAdminNotice(
152
+				'php_version_' . str_replace('.', '-', EE_MIN_PHP_VER_RECOMMENDED) . '_recommended',
153
+				sprintf(
154
+					esc_html__(
155
+						'Event Espresso recommends PHP version %1$s or greater for optimal performance. You are currently running version %2$s.%3$sIn order to update your version of PHP, you will need to contact your current hosting provider.%3$sFor information on stable PHP versions, please go to %4$s.',
156
+						'event_espresso'
157
+					),
158
+					EE_MIN_PHP_VER_RECOMMENDED,
159
+					PHP_VERSION,
160
+					'<br/>',
161
+					'<a href="http://php.net/downloads.php">http://php.net/downloads.php</a>'
162
+				)
163
+			);
164
+		}
165
+	}
166
+
167
+
168
+	/**
169
+	 * Returns whether the provided php version number is greater than the current version of php installed on the server.
170
+	 *
171
+	 * @param string $version_required
172
+	 * @return bool
173
+	 */
174
+	private function upcomingRequiredPhpVersion($version_required = '5.5')
175
+	{
176
+		return $this->checkPhpVersion($version_required);
177
+	}
178
+
179
+
180
+	/**
181
+	 *  Sets a notice for an upcoming required version of PHP in the next update of EE core.
182
+	 */
183
+	private function displayUpcomingRequiredVersion()
184
+	{
185
+		if ($this->request->isAdmin()
186
+			&& apply_filters('FHEE__EE_Recommended_Versions__displayUpcomingRequiredVersion', true, $this->request)
187
+			&& current_user_can('update_plugins')
188
+		) {
189
+			add_action('admin_notices', function ()
190
+			{
191
+				echo '<div class="notice event-espresso-admin-notice notice-warning"><p>'
192
+					 . sprintf(
193
+						 esc_html__(
194
+							 'Please note: The next update of Event Espresso 4 will %1$srequire%2$s PHP 5.4.45 or greater.  Your web server\'s PHP version is %3$s.  You can contact your host and ask them to update your PHP version to at least PHP 5.6.  Please do not update to the new version of Event Espresso 4 until the PHP update is completed. Read about why keeping your server on the latest version of PHP is a good idea %4$shere%5$s',
195
+							 'event_espresso'
196
+						 ),
197
+						 '<strong>',
198
+						 '</strong>',
199
+						 PHP_VERSION,
200
+						 '<a href="https://wordpress.org/support/upgrade-php/">',
201
+						 '</a>'
202
+					 )
203
+					 . '</p></div>';
204
+			});
205
+		}
206
+	}
207 207
 }
208 208
 // Location: RecommendedVersions.php
Please login to merge, or discard this patch.
Spacing   +5 added lines, -5 removed lines patch added patch discarded remove patch
@@ -36,18 +36,18 @@  discard block
 block discarded – undo
36 36
         $this->request  = $request;
37 37
         $this->response = $response;
38 38
         // check required WP version
39
-        if (! $this->minimumWordPressVersionRequired()) {
39
+        if ( ! $this->minimumWordPressVersionRequired()) {
40 40
             $this->request->unSetRequestParam('activate', true);
41 41
             add_action('admin_notices', array($this, 'minimum_wp_version_error'), 1);
42 42
             $this->response->terminateRequest();
43 43
             $this->response->deactivatePlugin();
44 44
         }
45 45
         // check recommended PHP version
46
-        if (! $this->minimumPhpVersionRecommended()) {
46
+        if ( ! $this->minimumPhpVersionRecommended()) {
47 47
             $this->displayMinimumRecommendedPhpVersionNotice();
48 48
         }
49 49
         //upcoming required version
50
-        if (! $this->upcomingRequiredPhpVersion()) {
50
+        if ( ! $this->upcomingRequiredPhpVersion()) {
51 51
             $this->displayUpcomingRequiredVersion();
52 52
         }
53 53
         $this->response = $this->processRequestStack($this->request, $this->response);
@@ -149,7 +149,7 @@  discard block
 block discarded – undo
149 149
     {
150 150
         if ($this->request->isAdmin()) {
151 151
             new PersistentAdminNotice(
152
-                'php_version_' . str_replace('.', '-', EE_MIN_PHP_VER_RECOMMENDED) . '_recommended',
152
+                'php_version_'.str_replace('.', '-', EE_MIN_PHP_VER_RECOMMENDED).'_recommended',
153 153
                 sprintf(
154 154
                     esc_html__(
155 155
                         'Event Espresso recommends PHP version %1$s or greater for optimal performance. You are currently running version %2$s.%3$sIn order to update your version of PHP, you will need to contact your current hosting provider.%3$sFor information on stable PHP versions, please go to %4$s.',
@@ -186,7 +186,7 @@  discard block
 block discarded – undo
186 186
             && apply_filters('FHEE__EE_Recommended_Versions__displayUpcomingRequiredVersion', true, $this->request)
187 187
             && current_user_can('update_plugins')
188 188
         ) {
189
-            add_action('admin_notices', function ()
189
+            add_action('admin_notices', function()
190 190
             {
191 191
                 echo '<div class="notice event-espresso-admin-notice notice-warning"><p>'
192 192
                      . sprintf(
Please login to merge, or discard this patch.