Completed
Branch master (7421d0)
by
unknown
11:25 queued 06:55
created
core/db_classes/EE_Price_Type.class.php 1 patch
Indentation   +272 added lines, -272 removed lines patch added patch discarded remove patch
@@ -12,276 +12,276 @@
 block discarded – undo
12 12
  */
13 13
 class EE_Price_Type extends EE_Soft_Delete_Base_Class
14 14
 {
15
-    /**
16
-     * @param array $props_n_values
17
-     * @return EE_Price_Type
18
-     * @throws EE_Error
19
-     * @throws InvalidArgumentException
20
-     * @throws ReflectionException
21
-     * @throws InvalidDataTypeException
22
-     * @throws InvalidInterfaceException
23
-     */
24
-    public static function new_instance($props_n_values = array())
25
-    {
26
-        $has_object = parent::_check_for_object($props_n_values, __CLASS__);
27
-        return $has_object ? $has_object : new self($props_n_values);
28
-    }
29
-
30
-
31
-    /**
32
-     * @param array $props_n_values
33
-     * @return EE_Price_Type
34
-     * @throws EE_Error
35
-     * @throws InvalidArgumentException
36
-     * @throws ReflectionException
37
-     * @throws InvalidDataTypeException
38
-     * @throws InvalidInterfaceException
39
-     */
40
-    public static function new_instance_from_db($props_n_values = array())
41
-    {
42
-        return new self($props_n_values, true);
43
-    }
44
-
45
-
46
-    /**
47
-     * Set Price Type Name
48
-     *
49
-     * @param string $PRT_name
50
-     * @throws EE_Error
51
-     * @throws InvalidArgumentException
52
-     * @throws ReflectionException
53
-     * @throws InvalidDataTypeException
54
-     * @throws InvalidInterfaceException
55
-     */
56
-    public function set_name(string $PRT_name = '')
57
-    {
58
-        $this->set('PRT_name', $PRT_name);
59
-    }
60
-
61
-
62
-    /**
63
-     * Set Price Type a percent
64
-     *
65
-     * @param bool $PRT_is_percent
66
-     * @throws EE_Error
67
-     * @throws InvalidArgumentException
68
-     * @throws ReflectionException
69
-     * @throws InvalidDataTypeException
70
-     * @throws InvalidInterfaceException
71
-     */
72
-    public function set_is_percent($PRT_is_percent = false)
73
-    {
74
-        $this->set('PRT_is_percent', $PRT_is_percent);
75
-    }
76
-
77
-
78
-    /**
79
-     * Set Price Type order
80
-     *
81
-     * @param int $PRT_order
82
-     * @throws EE_Error
83
-     * @throws InvalidArgumentException
84
-     * @throws ReflectionException
85
-     * @throws InvalidDataTypeException
86
-     * @throws InvalidInterfaceException
87
-     */
88
-    public function set_order($PRT_order = 0)
89
-    {
90
-        $this->set('PRT_order', $PRT_order);
91
-    }
92
-
93
-
94
-    /**
95
-     * @throws EE_Error
96
-     * @throws InvalidArgumentException
97
-     * @throws InvalidDataTypeException
98
-     * @throws InvalidInterfaceException
99
-     * @throws ReflectionException
100
-     */
101
-    public function move_to_trash()
102
-    {
103
-        $this->set('PRT_deleted', true);
104
-    }
105
-
106
-
107
-    /**
108
-     * @throws EE_Error
109
-     * @throws InvalidArgumentException
110
-     * @throws InvalidDataTypeException
111
-     * @throws InvalidInterfaceException
112
-     * @throws ReflectionException
113
-     */
114
-    public function restore_from_trash()
115
-    {
116
-        $this->set('PRT_deleted', false);
117
-    }
118
-
119
-
120
-    /**
121
-     * get Price Type Name
122
-     *
123
-     * @return string
124
-     * @throws EE_Error
125
-     * @throws InvalidArgumentException
126
-     * @throws InvalidDataTypeException
127
-     * @throws InvalidInterfaceException
128
-     * @throws ReflectionException
129
-     */
130
-    public function name(): string
131
-    {
132
-        return (string) $this->get('PRT_name');
133
-    }
134
-
135
-
136
-    /**
137
-     * get base Price Type
138
-     *
139
-     * @return int
140
-     * @throws EE_Error
141
-     * @throws InvalidArgumentException
142
-     * @throws InvalidDataTypeException
143
-     * @throws InvalidInterfaceException
144
-     * @throws ReflectionException
145
-     */
146
-    public function base_type(): int
147
-    {
148
-        return (int) $this->get('PBT_ID');
149
-    }
150
-
151
-
152
-    /**
153
-     * @return string
154
-     * @throws EE_Error
155
-     * @throws InvalidArgumentException
156
-     * @throws ReflectionException
157
-     * @throws InvalidDataTypeException
158
-     * @throws InvalidInterfaceException
159
-     */
160
-    public function base_type_name(): string
161
-    {
162
-        return (string) $this->get_pretty('PBT_ID');
163
-    }
164
-
165
-
166
-    /**
167
-     * get is Price Type a percent?
168
-     *
169
-     * @return bool
170
-     * @throws EE_Error
171
-     * @throws InvalidArgumentException
172
-     * @throws InvalidDataTypeException
173
-     * @throws InvalidInterfaceException
174
-     * @throws ReflectionException
175
-     */
176
-    public function is_base_price(): bool
177
-    {
178
-        return $this->get('PBT_ID') === EEM_Price_Type::base_type_base_price;
179
-    }
180
-
181
-
182
-    /**
183
-     * get is Price Type a percent?
184
-     *
185
-     * @return bool
186
-     * @throws EE_Error
187
-     * @throws InvalidArgumentException
188
-     * @throws InvalidDataTypeException
189
-     * @throws InvalidInterfaceException
190
-     * @throws ReflectionException
191
-     */
192
-    public function is_percent(): bool
193
-    {
194
-        return (bool) $this->get('PRT_is_percent');
195
-    }
196
-
197
-
198
-    /**
199
-     * @return bool
200
-     * @throws EE_Error
201
-     * @throws InvalidArgumentException
202
-     * @throws ReflectionException
203
-     * @throws InvalidDataTypeException
204
-     * @throws InvalidInterfaceException
205
-     */
206
-    public function is_discount(): bool
207
-    {
208
-        return $this->get('PBT_ID') === EEM_Price_Type::base_type_discount;
209
-    }
210
-
211
-
212
-    /**
213
-     * @return bool
214
-     * @throws EE_Error
215
-     * @throws InvalidArgumentException
216
-     * @throws ReflectionException
217
-     * @throws InvalidDataTypeException
218
-     * @throws InvalidInterfaceException
219
-     */
220
-    public function is_surcharge(): bool
221
-    {
222
-        return $this->get('PBT_ID') === EEM_Price_Type::base_type_surcharge;
223
-    }
224
-
225
-
226
-    /**
227
-     * @return bool
228
-     * @throws EE_Error
229
-     * @throws InvalidArgumentException
230
-     * @throws ReflectionException
231
-     * @throws InvalidDataTypeException
232
-     * @throws InvalidInterfaceException
233
-     */
234
-    public function is_tax(): bool
235
-    {
236
-        return $this->get('PBT_ID') === EEM_Price_Type::base_type_tax;
237
-    }
238
-
239
-
240
-    /**
241
-     * get the author of the price type.
242
-     *
243
-     * @return int
244
-     * @throws EE_Error
245
-     * @throws InvalidArgumentException
246
-     * @throws ReflectionException
247
-     * @throws InvalidDataTypeException
248
-     * @throws InvalidInterfaceException
249
-     * @since 4.5.0
250
-     */
251
-    public function wp_user(): int
252
-    {
253
-        return (int) $this->get('PRT_wp_user');
254
-    }
255
-
256
-
257
-    /**
258
-     * get Price Type order
259
-     *
260
-     * @return int
261
-     * @throws EE_Error
262
-     * @throws InvalidArgumentException
263
-     * @throws InvalidDataTypeException
264
-     * @throws InvalidInterfaceException
265
-     * @throws ReflectionException
266
-     */
267
-    public function order(): int
268
-    {
269
-        return (int) $this->get('PRT_order');
270
-    }
271
-
272
-
273
-    /**
274
-     * get  is Price Type deleted ?
275
-     *
276
-     * @return bool
277
-     * @throws EE_Error
278
-     * @throws InvalidArgumentException
279
-     * @throws InvalidDataTypeException
280
-     * @throws InvalidInterfaceException
281
-     * @throws ReflectionException
282
-     */
283
-    public function deleted(): bool
284
-    {
285
-        return (bool) $this->get('PRT_deleted');
286
-    }
15
+	/**
16
+	 * @param array $props_n_values
17
+	 * @return EE_Price_Type
18
+	 * @throws EE_Error
19
+	 * @throws InvalidArgumentException
20
+	 * @throws ReflectionException
21
+	 * @throws InvalidDataTypeException
22
+	 * @throws InvalidInterfaceException
23
+	 */
24
+	public static function new_instance($props_n_values = array())
25
+	{
26
+		$has_object = parent::_check_for_object($props_n_values, __CLASS__);
27
+		return $has_object ? $has_object : new self($props_n_values);
28
+	}
29
+
30
+
31
+	/**
32
+	 * @param array $props_n_values
33
+	 * @return EE_Price_Type
34
+	 * @throws EE_Error
35
+	 * @throws InvalidArgumentException
36
+	 * @throws ReflectionException
37
+	 * @throws InvalidDataTypeException
38
+	 * @throws InvalidInterfaceException
39
+	 */
40
+	public static function new_instance_from_db($props_n_values = array())
41
+	{
42
+		return new self($props_n_values, true);
43
+	}
44
+
45
+
46
+	/**
47
+	 * Set Price Type Name
48
+	 *
49
+	 * @param string $PRT_name
50
+	 * @throws EE_Error
51
+	 * @throws InvalidArgumentException
52
+	 * @throws ReflectionException
53
+	 * @throws InvalidDataTypeException
54
+	 * @throws InvalidInterfaceException
55
+	 */
56
+	public function set_name(string $PRT_name = '')
57
+	{
58
+		$this->set('PRT_name', $PRT_name);
59
+	}
60
+
61
+
62
+	/**
63
+	 * Set Price Type a percent
64
+	 *
65
+	 * @param bool $PRT_is_percent
66
+	 * @throws EE_Error
67
+	 * @throws InvalidArgumentException
68
+	 * @throws ReflectionException
69
+	 * @throws InvalidDataTypeException
70
+	 * @throws InvalidInterfaceException
71
+	 */
72
+	public function set_is_percent($PRT_is_percent = false)
73
+	{
74
+		$this->set('PRT_is_percent', $PRT_is_percent);
75
+	}
76
+
77
+
78
+	/**
79
+	 * Set Price Type order
80
+	 *
81
+	 * @param int $PRT_order
82
+	 * @throws EE_Error
83
+	 * @throws InvalidArgumentException
84
+	 * @throws ReflectionException
85
+	 * @throws InvalidDataTypeException
86
+	 * @throws InvalidInterfaceException
87
+	 */
88
+	public function set_order($PRT_order = 0)
89
+	{
90
+		$this->set('PRT_order', $PRT_order);
91
+	}
92
+
93
+
94
+	/**
95
+	 * @throws EE_Error
96
+	 * @throws InvalidArgumentException
97
+	 * @throws InvalidDataTypeException
98
+	 * @throws InvalidInterfaceException
99
+	 * @throws ReflectionException
100
+	 */
101
+	public function move_to_trash()
102
+	{
103
+		$this->set('PRT_deleted', true);
104
+	}
105
+
106
+
107
+	/**
108
+	 * @throws EE_Error
109
+	 * @throws InvalidArgumentException
110
+	 * @throws InvalidDataTypeException
111
+	 * @throws InvalidInterfaceException
112
+	 * @throws ReflectionException
113
+	 */
114
+	public function restore_from_trash()
115
+	{
116
+		$this->set('PRT_deleted', false);
117
+	}
118
+
119
+
120
+	/**
121
+	 * get Price Type Name
122
+	 *
123
+	 * @return string
124
+	 * @throws EE_Error
125
+	 * @throws InvalidArgumentException
126
+	 * @throws InvalidDataTypeException
127
+	 * @throws InvalidInterfaceException
128
+	 * @throws ReflectionException
129
+	 */
130
+	public function name(): string
131
+	{
132
+		return (string) $this->get('PRT_name');
133
+	}
134
+
135
+
136
+	/**
137
+	 * get base Price Type
138
+	 *
139
+	 * @return int
140
+	 * @throws EE_Error
141
+	 * @throws InvalidArgumentException
142
+	 * @throws InvalidDataTypeException
143
+	 * @throws InvalidInterfaceException
144
+	 * @throws ReflectionException
145
+	 */
146
+	public function base_type(): int
147
+	{
148
+		return (int) $this->get('PBT_ID');
149
+	}
150
+
151
+
152
+	/**
153
+	 * @return string
154
+	 * @throws EE_Error
155
+	 * @throws InvalidArgumentException
156
+	 * @throws ReflectionException
157
+	 * @throws InvalidDataTypeException
158
+	 * @throws InvalidInterfaceException
159
+	 */
160
+	public function base_type_name(): string
161
+	{
162
+		return (string) $this->get_pretty('PBT_ID');
163
+	}
164
+
165
+
166
+	/**
167
+	 * get is Price Type a percent?
168
+	 *
169
+	 * @return bool
170
+	 * @throws EE_Error
171
+	 * @throws InvalidArgumentException
172
+	 * @throws InvalidDataTypeException
173
+	 * @throws InvalidInterfaceException
174
+	 * @throws ReflectionException
175
+	 */
176
+	public function is_base_price(): bool
177
+	{
178
+		return $this->get('PBT_ID') === EEM_Price_Type::base_type_base_price;
179
+	}
180
+
181
+
182
+	/**
183
+	 * get is Price Type a percent?
184
+	 *
185
+	 * @return bool
186
+	 * @throws EE_Error
187
+	 * @throws InvalidArgumentException
188
+	 * @throws InvalidDataTypeException
189
+	 * @throws InvalidInterfaceException
190
+	 * @throws ReflectionException
191
+	 */
192
+	public function is_percent(): bool
193
+	{
194
+		return (bool) $this->get('PRT_is_percent');
195
+	}
196
+
197
+
198
+	/**
199
+	 * @return bool
200
+	 * @throws EE_Error
201
+	 * @throws InvalidArgumentException
202
+	 * @throws ReflectionException
203
+	 * @throws InvalidDataTypeException
204
+	 * @throws InvalidInterfaceException
205
+	 */
206
+	public function is_discount(): bool
207
+	{
208
+		return $this->get('PBT_ID') === EEM_Price_Type::base_type_discount;
209
+	}
210
+
211
+
212
+	/**
213
+	 * @return bool
214
+	 * @throws EE_Error
215
+	 * @throws InvalidArgumentException
216
+	 * @throws ReflectionException
217
+	 * @throws InvalidDataTypeException
218
+	 * @throws InvalidInterfaceException
219
+	 */
220
+	public function is_surcharge(): bool
221
+	{
222
+		return $this->get('PBT_ID') === EEM_Price_Type::base_type_surcharge;
223
+	}
224
+
225
+
226
+	/**
227
+	 * @return bool
228
+	 * @throws EE_Error
229
+	 * @throws InvalidArgumentException
230
+	 * @throws ReflectionException
231
+	 * @throws InvalidDataTypeException
232
+	 * @throws InvalidInterfaceException
233
+	 */
234
+	public function is_tax(): bool
235
+	{
236
+		return $this->get('PBT_ID') === EEM_Price_Type::base_type_tax;
237
+	}
238
+
239
+
240
+	/**
241
+	 * get the author of the price type.
242
+	 *
243
+	 * @return int
244
+	 * @throws EE_Error
245
+	 * @throws InvalidArgumentException
246
+	 * @throws ReflectionException
247
+	 * @throws InvalidDataTypeException
248
+	 * @throws InvalidInterfaceException
249
+	 * @since 4.5.0
250
+	 */
251
+	public function wp_user(): int
252
+	{
253
+		return (int) $this->get('PRT_wp_user');
254
+	}
255
+
256
+
257
+	/**
258
+	 * get Price Type order
259
+	 *
260
+	 * @return int
261
+	 * @throws EE_Error
262
+	 * @throws InvalidArgumentException
263
+	 * @throws InvalidDataTypeException
264
+	 * @throws InvalidInterfaceException
265
+	 * @throws ReflectionException
266
+	 */
267
+	public function order(): int
268
+	{
269
+		return (int) $this->get('PRT_order');
270
+	}
271
+
272
+
273
+	/**
274
+	 * get  is Price Type deleted ?
275
+	 *
276
+	 * @return bool
277
+	 * @throws EE_Error
278
+	 * @throws InvalidArgumentException
279
+	 * @throws InvalidDataTypeException
280
+	 * @throws InvalidInterfaceException
281
+	 * @throws ReflectionException
282
+	 */
283
+	public function deleted(): bool
284
+	{
285
+		return (bool) $this->get('PRT_deleted');
286
+	}
287 287
 }
Please login to merge, or discard this patch.
core/EE_System.core.php 2 patches
Indentation   +1225 added lines, -1225 removed lines patch added patch discarded remove patch
@@ -30,1230 +30,1230 @@
 block discarded – undo
30 30
  */
31 31
 final class EE_System implements ResettableInterface
32 32
 {
33
+	/**
34
+	 * indicates this is a 'normal' request. Ie, not activation, nor upgrade, nor activation.
35
+	 * So examples of this would be a normal GET request on the frontend or backend, or a POST, etc
36
+	 */
37
+	const req_type_normal = 0;
38
+
39
+	/**
40
+	 * Indicates this is a brand new installation of EE so we should install
41
+	 * tables and default data etc
42
+	 */
43
+	const req_type_new_activation = 1;
44
+
45
+	/**
46
+	 * we've detected that EE has been reactivated (or EE was activated during maintenance mode,
47
+	 * and we just exited maintenance mode). We MUST check the database is setup properly
48
+	 * and that default data is setup too
49
+	 */
50
+	const req_type_reactivation = 2;
51
+
52
+	/**
53
+	 * indicates that EE has been upgraded since its previous request.
54
+	 * We may have data migration scripts to call and will want to trigger maintenance mode
55
+	 */
56
+	const req_type_upgrade = 3;
57
+
58
+	/**
59
+	 * TODO  will detect that EE has been DOWNGRADED. We probably don't want to run in this case...
60
+	 */
61
+	const req_type_downgrade = 4;
62
+
63
+	/**
64
+	 * @deprecated since version 4.6.0.dev.006
65
+	 * Now whenever a new_activation is detected the request type is still just
66
+	 * new_activation (same for reactivation, upgrade, downgrade etc), but if we're in maintenance mode
67
+	 * EE_System::initialize_db_if_no_migrations_required and EE_Addon::initialize_db_if_no_migrations_required
68
+	 * will instead enqueue that EE plugin's db initialization for when we're taken out of maintenance mode.
69
+	 * (Specifically, when the migration manager indicates migrations are finished
70
+	 * EE_Data_Migration_Manager::initialize_db_for_enqueued_ee_plugins() will be called)
71
+	 */
72
+	const req_type_activation_but_not_installed = 5;
73
+
74
+	/**
75
+	 * option prefix for recording the activation history (like core's "espresso_db_update") of addons
76
+	 */
77
+	const addon_activation_history_option_prefix = 'ee_addon_activation_history_';
78
+
79
+	private static ?EE_System $_instance = null;
80
+
81
+	private ?LoaderInterface $loader;
82
+
83
+	private ?EE_Maintenance_Mode $maintenance_mode;
84
+
85
+	private ?EE_Registry $registry;
86
+
87
+	private ?RequestInterface $request;
88
+
89
+	private Router $router;
90
+
91
+	private ?AddonManager $addon_manager = null;
92
+
93
+	private ?EE_Capabilities $capabilities = null;
94
+
95
+	protected ?FeatureFlags $feature = null;
96
+
97
+	private ?RegisterCustomPostTypes $register_custom_post_types = null;
98
+
99
+	private ?RegisterCustomTaxonomies $register_custom_taxonomies = null;
100
+
101
+	private ?RegisterCustomTaxonomyTerms $register_custom_taxonomy_terms = null;
102
+
103
+	/**
104
+	 * Stores which type of request this is, options being one of the constants on EE_System starting with req_type_*.
105
+	 * It can be a brand-new activation, a reactivation, an upgrade, a downgrade, or a normal request.
106
+	 */
107
+	private ?int $_req_type = null;
108
+
109
+	/**
110
+	 * Whether or not there was a non-micro version change in EE core version during this request
111
+	 */
112
+	private bool $_major_version_change = false;
113
+
114
+
115
+	/**
116
+	 * @singleton method used to instantiate class object
117
+	 * @param LoaderInterface|null     $loader
118
+	 * @param EE_Maintenance_Mode|null $maintenance_mode
119
+	 * @param EE_Registry|null         $registry
120
+	 * @param RequestInterface|null    $request
121
+	 * @param Router|null              $router
122
+	 * @param FeatureFlags|null        $feature
123
+	 * @return EE_System
124
+	 */
125
+	public static function instance(
126
+		?LoaderInterface $loader = null,
127
+		?EE_Maintenance_Mode $maintenance_mode = null,
128
+		?EE_Registry $registry = null,
129
+		?RequestInterface $request = null,
130
+		?Router $router = null,
131
+		?FeatureFlags $feature = null
132
+	): EE_System {
133
+		// check if class object is instantiated
134
+		if (! self::$_instance instanceof EE_System) {
135
+			self::$_instance = new self($loader, $maintenance_mode, $registry, $request, $router, $feature);
136
+		}
137
+		return self::$_instance;
138
+	}
139
+
140
+
141
+	/**
142
+	 * resets the instance and returns it
143
+	 *
144
+	 * @return EE_System
145
+	 */
146
+	public static function reset(): EE_System
147
+	{
148
+		self::$_instance->_req_type = null;
149
+		// make sure none of the old hooks are left hanging around
150
+		remove_all_actions('AHEE__EE_System__perform_activations_upgrades_and_migrations');
151
+		// we need to reset the migration manager in order for it to detect DMSs properly
152
+		EE_Data_Migration_Manager::reset();
153
+		self::instance()->detect_activations_or_upgrades();
154
+		self::instance()->perform_activations_upgrades_and_migrations();
155
+		return self::instance();
156
+	}
157
+
158
+
159
+	/**
160
+	 * sets hooks for running rest of system
161
+	 * provides "AHEE__EE_System__construct__complete" hook for EE Addons to use as their starting point
162
+	 * starting EE Addons from any other point may lead to problems
163
+	 *
164
+	 * @param LoaderInterface     $loader
165
+	 * @param EE_Maintenance_Mode $maintenance_mode
166
+	 * @param EE_Registry         $registry
167
+	 * @param RequestInterface    $request
168
+	 * @param Router              $router
169
+	 * @param FeatureFlags        $feature
170
+	 */
171
+	private function __construct(
172
+		LoaderInterface $loader,
173
+		EE_Maintenance_Mode $maintenance_mode,
174
+		EE_Registry $registry,
175
+		RequestInterface $request,
176
+		Router $router,
177
+		FeatureFlags $feature
178
+	) {
179
+		$this->registry         = $registry;
180
+		$this->loader           = $loader;
181
+		$this->request          = $request;
182
+		$this->router           = $router;
183
+		$this->maintenance_mode = $maintenance_mode;
184
+		$this->feature          = $feature;
185
+		do_action('AHEE__EE_System__construct__begin', $this);
186
+		add_action(
187
+			'AHEE__EE_Bootstrap__load_espresso_addons',
188
+			[$this, 'loadWpGraphQL'],
189
+			3
190
+		);
191
+		add_action(
192
+			'AHEE__EE_Bootstrap__load_espresso_addons',
193
+			[$this, 'loadCapabilities'],
194
+			5
195
+		);
196
+		add_action(
197
+			'AHEE__EE_Bootstrap__load_espresso_addons',
198
+			[$this, 'loadCommandBus'],
199
+			7
200
+		);
201
+		add_action(
202
+			'AHEE__EE_Bootstrap__load_espresso_addons',
203
+			[$this, 'loadPluginApi'],
204
+			9
205
+		);
206
+		// give caff stuff a chance to play during the activation process too.
207
+		add_action(
208
+			'AHEE__EE_Bootstrap__load_espresso_addons',
209
+			[$this, 'brewCaffeinated'],
210
+			9
211
+		);
212
+		// allow addons to load first so that they can register autoloaders, set hooks for running DMS's, etc
213
+		add_action(
214
+			'AHEE__EE_Bootstrap__load_espresso_addons',
215
+			[$this, 'load_espresso_addons']
216
+		);
217
+		// when an ee addon is activated, we want to call the core hook(s) again
218
+		// because the newly-activated addon didn't get a chance to run at all
219
+		add_action('activate_plugin', [$this, 'load_espresso_addons'], 1);
220
+		// detect whether install or upgrade
221
+		add_action(
222
+			'AHEE__EE_Bootstrap__detect_activations_or_upgrades',
223
+			[$this, 'detect_activations_or_upgrades'],
224
+			3
225
+		);
226
+		// load EE_Config, EE_Textdomain, etc
227
+		add_action(
228
+			'AHEE__EE_Bootstrap__load_core_configuration',
229
+			[$this, 'load_core_configuration'],
230
+			5
231
+		);
232
+		// load specifications for matching routes to current request
233
+		add_action(
234
+			'AHEE__EE_Bootstrap__load_core_configuration',
235
+			[$this, 'loadRouteMatchSpecifications']
236
+		);
237
+		// load specifications for custom post types
238
+		add_action(
239
+			'AHEE__EE_Bootstrap__load_core_configuration',
240
+			[$this, 'loadCustomPostTypes']
241
+		);
242
+		// load specifications for custom post types
243
+		add_action(
244
+			'AHEE__EE_Bootstrap__load_core_configuration',
245
+			[$this, 'loadCustomPostTypes']
246
+		);
247
+		// load EE_Config, EE_Textdomain, etc
248
+		add_action(
249
+			'AHEE__EE_Bootstrap__register_shortcodes_modules_and_widgets',
250
+			[$this, 'register_shortcodes_modules_and_widgets'],
251
+			7
252
+		);
253
+		// you wanna get going? I wanna get going... let's get going!
254
+		add_action(
255
+			'AHEE__EE_Bootstrap__brew_espresso',
256
+			[$this, 'brew_espresso'],
257
+			9
258
+		);
259
+		// other housekeeping
260
+		// exclude EE critical pages from wp_list_pages
261
+		add_filter(
262
+			'wp_list_pages_excludes',
263
+			[$this, 'remove_pages_from_wp_list_pages'],
264
+			10
265
+		);
266
+		// ALL EE Addons should use the following hook point to attach their initial setup too
267
+		// it's extremely important for EE Addons to register any class autoloaders so that they can be available when the EE_Config loads
268
+		do_action('AHEE__EE_System__construct__complete', $this);
269
+	}
270
+
271
+
272
+	/**
273
+	 * load and setup EE_Capabilities
274
+	 *
275
+	 * @return void
276
+	 */
277
+	public function loadWpGraphQL()
278
+	{
279
+		espressoLoadWpGraphQL();
280
+	}
281
+
282
+
283
+	/**
284
+	 * load and setup EE_Capabilities
285
+	 *
286
+	 * @return void
287
+	 */
288
+	public function loadCapabilities()
289
+	{
290
+		$this->capabilities = $this->loader->getShared('EE_Capabilities');
291
+	}
292
+
293
+
294
+	/**
295
+	 * create and cache the CommandBus, and also add middleware
296
+	 * The CapChecker middleware requires the use of EE_Capabilities
297
+	 * which is why we need to load the CommandBus after Caps are set up
298
+	 * CommandBus middleware operate FIFO - First In First Out
299
+	 * so LocateMovedCommands will run first in order to return any new commands
300
+	 *
301
+	 * @return void
302
+	 */
303
+	public function loadCommandBus()
304
+	{
305
+		$this->loader->getShared(
306
+			'CommandBusInterface',
307
+			[
308
+				null,
309
+				apply_filters(
310
+					'FHEE__EE_Load_Espresso_Core__handle_request__CommandBus_middleware',
311
+					[
312
+						$this->loader->getShared('EventEspresso\core\services\commands\middleware\LocateMovedCommands'),
313
+						$this->loader->getShared('EventEspresso\core\services\commands\middleware\CapChecker'),
314
+						$this->loader->getShared('EventEspresso\core\services\commands\middleware\AddActionHook'),
315
+					]
316
+				),
317
+			]
318
+		);
319
+	}
320
+
321
+
322
+	/**
323
+	 * @return void
324
+	 * @throws Exception
325
+	 */
326
+	public function loadPluginApi()
327
+	{
328
+		$this->addon_manager = $this->loader->getShared(AddonManager::class);
329
+		$this->addon_manager->initialize();
330
+		$this->loader->getShared('EE_Request_Handler');
331
+	}
332
+
333
+
334
+	/**
335
+	 * The purpose of this method is to simply check for a file named "caffeinated/brewing_regular.php" for any hooks
336
+	 * that need to be setup before our EE_System launches.
337
+	 *
338
+	 * @return void
339
+	 * @throws DomainException
340
+	 * @throws InvalidArgumentException
341
+	 * @throws InvalidDataTypeException
342
+	 * @throws InvalidInterfaceException
343
+	 * @throws InvalidClassException
344
+	 * @throws InvalidFilePathException
345
+	 * @throws EE_Error
346
+	 */
347
+	public function brewCaffeinated()
348
+	{
349
+		static $brew;
350
+		/** @var Domain $domain */
351
+		$domain = DomainFactory::getEventEspressoCoreDomain();
352
+		if ($domain->isCaffeinated() && ! $brew instanceof EE_Brewing_Regular) {
353
+			require_once EE_CAFF_PATH . 'brewing_regular.php';
354
+			/** @var EE_Brewing_Regular $brew */
355
+			$brew = LoaderFactory::getLoader()->getShared(EE_Brewing_Regular::class);
356
+			if (! $this->feature->allowed('use_edd_plugin_licensing')) {
357
+				$brew->initializePUE();
358
+			}
359
+			add_action(
360
+				'AHEE__EE_System__load_core_configuration__begin',
361
+				[$brew, 'caffeinated']
362
+			);
363
+		}
364
+	}
365
+
366
+
367
+	/**
368
+	 * load_espresso_addons
369
+	 * allow addons to load first so that they can set hooks for running DMS's, etc
370
+	 * this is hooked into both:
371
+	 *    'AHEE__EE_Bootstrap__load_core_configuration'
372
+	 *        which runs during the WP 'plugins_loaded' action at priority 5
373
+	 *    and the WP 'activate_plugin' hook point
374
+	 *
375
+	 * @return void
376
+	 * @throws Exception
377
+	 * @throws Throwable
378
+	 */
379
+	public function load_espresso_addons()
380
+	{
381
+		if ($this->feature->allowed('use_edd_plugin_licensing')) {
382
+			new EventEspresso\core\services\licensing\PluginLicense(
383
+				EVENT_ESPRESSO_MAIN_FILE,
384
+				0,
385
+				'Event Espresso Core',
386
+				'event_espresso_core',
387
+				espresso_version()
388
+			);
389
+		}
390
+		// looking for hooks? they've been moved into the AddonManager to maintain compatibility
391
+		$this->addon_manager->loadAddons();
392
+	}
393
+
394
+
395
+	/**
396
+	 * detect_activations_or_upgrades
397
+	 * Checks for activation or upgrade of core first;
398
+	 * then also checks if any registered addons have been activated or upgraded
399
+	 * This is hooked into 'AHEE__EE_Bootstrap__detect_activations_or_upgrades'
400
+	 * which runs during the WP 'plugins_loaded' action at priority 3
401
+	 *
402
+	 * @access public
403
+	 * @return void
404
+	 */
405
+	public function detect_activations_or_upgrades()
406
+	{
407
+		// first off: let's make sure to handle core
408
+		$this->detect_if_activation_or_upgrade();
409
+		foreach ($this->registry->addons as $addon) {
410
+			if ($addon instanceof EE_Addon) {
411
+				// detect teh request type for that addon
412
+				$addon->detect_req_type();
413
+			}
414
+		}
415
+	}
416
+
417
+
418
+	/**
419
+	 * detect_if_activation_or_upgrade
420
+	 * Takes care of detecting whether this is a brand new install or code upgrade,
421
+	 * and either setting up the DB or setting up maintenance mode etc.
422
+	 *
423
+	 * @access public
424
+	 * @return void
425
+	 */
426
+	public function detect_if_activation_or_upgrade()
427
+	{
428
+		do_action('AHEE__EE_System___detect_if_activation_or_upgrade__begin');
429
+		// check if db has been updated, or if its a brand-new installation
430
+		$espresso_db_update = $this->fix_espresso_db_upgrade_option();
431
+		$request_type       = $this->detect_req_type($espresso_db_update);
432
+		switch ($request_type) {
433
+			case EE_System::req_type_new_activation:
434
+				do_action('AHEE__EE_System__detect_if_activation_or_upgrade__new_activation');
435
+				$this->_handle_core_version_change($espresso_db_update);
436
+				break;
437
+			case EE_System::req_type_reactivation:
438
+				do_action('AHEE__EE_System__detect_if_activation_or_upgrade__reactivation');
439
+				$this->_handle_core_version_change($espresso_db_update);
440
+				break;
441
+			case EE_System::req_type_upgrade:
442
+				do_action('AHEE__EE_System__detect_if_activation_or_upgrade__upgrade');
443
+				// migrations may be required now that we've upgraded
444
+				$this->maintenance_mode->set_maintenance_mode_if_db_old();
445
+				$this->_handle_core_version_change($espresso_db_update);
446
+				break;
447
+			case EE_System::req_type_downgrade:
448
+				do_action('AHEE__EE_System__detect_if_activation_or_upgrade__downgrade');
449
+				// its possible migrations are no longer required
450
+				$this->maintenance_mode->set_maintenance_mode_if_db_old();
451
+				$this->_handle_core_version_change($espresso_db_update);
452
+				break;
453
+			case EE_System::req_type_normal:
454
+			default:
455
+				break;
456
+		}
457
+		do_action('AHEE__EE_System__detect_if_activation_or_upgrade__complete');
458
+	}
459
+
460
+
461
+	/**
462
+	 * Updates the list of installed versions and sets hooks for
463
+	 * initializing the database later during the request
464
+	 *
465
+	 * @param array $espresso_db_update
466
+	 */
467
+	private function _handle_core_version_change(array $espresso_db_update)
468
+	{
469
+		$this->update_list_of_installed_versions($espresso_db_update);
470
+		// get ready to verify the DB is ok (provided we aren't in maintenance mode, of course)
471
+		add_action(
472
+			'AHEE__EE_System__perform_activations_upgrades_and_migrations',
473
+			[$this, 'initialize_db_if_no_migrations_required']
474
+		);
475
+	}
476
+
477
+
478
+	/**
479
+	 * standardizes the wp option 'espresso_db_upgrade' which actually stores
480
+	 * information about what versions of EE have been installed and activated,
481
+	 * NOT necessarily the state of the database
482
+	 *
483
+	 * @param mixed $espresso_db_update           the value of the WordPress option.
484
+	 *                                            If not supplied, fetches it from the options table
485
+	 * @return array the correct value of 'espresso_db_upgrade', after saving it, if it needed correction
486
+	 */
487
+	private function fix_espresso_db_upgrade_option($espresso_db_update = null): array
488
+	{
489
+		do_action('FHEE__EE_System__manage_fix_espresso_db_upgrade_option__begin', $espresso_db_update);
490
+		if (! $espresso_db_update) {
491
+			$espresso_db_update = get_option('espresso_db_update');
492
+		}
493
+		// check that option is an array
494
+		if (! is_array($espresso_db_update)) {
495
+			// if option is FALSE, then it never existed
496
+			if ($espresso_db_update === false) {
497
+				// make $espresso_db_update an array and save option with autoload OFF
498
+				$espresso_db_update = [];
499
+				add_option('espresso_db_update', $espresso_db_update, '', 'no');
500
+			} else {
501
+				// option is NOT FALSE but also is NOT an array, so make it an array and save it
502
+				$espresso_db_update = [$espresso_db_update => []];
503
+				update_option('espresso_db_update', $espresso_db_update);
504
+			}
505
+		} else {
506
+			$corrected_db_update = [];
507
+			// if IS an array, but is it an array where KEYS are version numbers, and values are arrays?
508
+			foreach ($espresso_db_update as $should_be_version_string => $should_be_array) {
509
+				if (is_int($should_be_version_string) && ! is_array($should_be_array)) {
510
+					// the key is an int, and the value IS NOT an array
511
+					// so it must be numerically-indexed, where values are versions installed...
512
+					// fix it!
513
+					$version_string                         = $should_be_array;
514
+					$corrected_db_update[ $version_string ] = ['unknown-date'];
515
+				} else {
516
+					// ok it checks out
517
+					$corrected_db_update[ $should_be_version_string ] = $should_be_array;
518
+				}
519
+			}
520
+			$espresso_db_update = $corrected_db_update;
521
+			update_option('espresso_db_update', $espresso_db_update);
522
+		}
523
+		do_action('FHEE__EE_System__manage_fix_espresso_db_upgrade_option__complete', $espresso_db_update);
524
+		return ! empty($espresso_db_update)
525
+			? $espresso_db_update
526
+			: [];
527
+	}
528
+
529
+
530
+	/**
531
+	 * Does the traditional work of setting up the plugin's database and adding default data.
532
+	 * If migration script/process did not exist, this is what would happen on every activation/reactivation/upgrade.
533
+	 * NOTE: if we're in maintenance mode (which would be the case if we detect there are data
534
+	 * migration scripts that need to be run and a version change happens), enqueues core for database initialization,
535
+	 * so that it will be done when migrations are finished
536
+	 *
537
+	 * @param boolean $initialize_addons_too if true, we double-check addons' database tables etc too;
538
+	 * @param boolean $verify_schema         if true will re-check the database tables have the correct schema.
539
+	 *                                       This is a resource-intensive job
540
+	 *                                       so we prefer to only do it when necessary
541
+	 * @return void
542
+	 * @throws EE_Error
543
+	 * @throws ReflectionException
544
+	 */
545
+	public function initialize_db_if_no_migrations_required($initialize_addons_too = false, $verify_schema = true)
546
+	{
547
+		$request_type = $this->detect_req_type();
548
+		// only initialize system if we're not in maintenance mode.
549
+		if (! MaintenanceStatus::isFullSite()) {
550
+			/** @var EventEspresso\core\domain\services\custom_post_types\RewriteRules $rewrite_rules */
551
+			$rewrite_rules = $this->loader->getShared(
552
+				'EventEspresso\core\domain\services\custom_post_types\RewriteRules'
553
+			);
554
+			$rewrite_rules->flush();
555
+			if ($verify_schema) {
556
+				EEH_Activation::initialize_db_and_folders();
557
+			}
558
+			EEH_Activation::initialize_db_content();
559
+			EEH_Activation::system_initialization();
560
+			if ($initialize_addons_too) {
561
+				$this->initialize_addons();
562
+			}
563
+		} else {
564
+			EE_Data_Migration_Manager::instance()->enqueue_db_initialization_for('Core');
565
+		}
566
+		if (
567
+			$request_type === EE_System::req_type_new_activation
568
+			|| $request_type === EE_System::req_type_reactivation
569
+			|| (
570
+				$request_type === EE_System::req_type_upgrade
571
+				&& $this->is_major_version_change()
572
+			)
573
+		) {
574
+			add_action('AHEE__EE_System__initialize_last', [$this, 'redirect_to_about_ee'], 9);
575
+		}
576
+	}
577
+
578
+
579
+	/**
580
+	 * Initializes the db for all registered addons
581
+	 *
582
+	 * @throws EE_Error
583
+	 * @throws ReflectionException
584
+	 */
585
+	public function initialize_addons()
586
+	{
587
+		// foreach registered addon, make sure its db is up-to-date too
588
+		foreach ($this->registry->addons as $addon) {
589
+			if ($addon instanceof EE_Addon) {
590
+				$addon->initialize_db_if_no_migrations_required();
591
+			}
592
+		}
593
+	}
594
+
595
+
596
+	/**
597
+	 * Adds the current code version to the saved wp option which stores a list of all ee versions ever installed.
598
+	 *
599
+	 * @param array  $version_history
600
+	 * @param string $current_version_to_add version to be added to the version history
601
+	 * @return    boolean success as to whether or not this option was changed
602
+	 */
603
+	public function update_list_of_installed_versions($version_history = null, $current_version_to_add = null): bool
604
+	{
605
+		if (! $version_history) {
606
+			$version_history = $this->fix_espresso_db_upgrade_option($version_history);
607
+		}
608
+		if ($current_version_to_add === null) {
609
+			$current_version_to_add = espresso_version();
610
+		}
611
+		$version_history[ $current_version_to_add ][] = date('Y-m-d H:i:s', time());
612
+		// re-save
613
+		return update_option('espresso_db_update', $version_history);
614
+	}
615
+
616
+
617
+	/**
618
+	 * Detects if the current version indicated in the has existed in the list of
619
+	 * previously-installed versions of EE (espresso_db_update). Does NOT modify it (ie, no side-effect)
620
+	 *
621
+	 * @param array|null $espresso_db_update array from the wp option stored under the name 'espresso_db_update'.
622
+	 *                                       If not supplied, fetches it from the options table.
623
+	 *                                       Also, caches its result so later parts of the code can also know whether
624
+	 *                                       there's been an update or not. This way we can add the current version to
625
+	 *                                       espresso_db_update, but still know if this is a new install or not
626
+	 * @return int one of the constants on EE_System::req_type_
627
+	 */
628
+	public function detect_req_type(?array $espresso_db_update = null): int
629
+	{
630
+		if ($this->_req_type === null) {
631
+			$espresso_db_update          = ! empty($espresso_db_update)
632
+				? $espresso_db_update
633
+				: $this->fix_espresso_db_upgrade_option();
634
+			$this->_req_type             = EE_System::detect_req_type_given_activation_history(
635
+				$espresso_db_update,
636
+				'ee_espresso_activation',
637
+				espresso_version()
638
+			);
639
+			$this->_major_version_change = $this->_detect_major_version_change($espresso_db_update);
640
+			$this->request->setIsActivation($this->_req_type !== EE_System::req_type_normal);
641
+		}
642
+		return $this->_req_type;
643
+	}
644
+
645
+
646
+	/**
647
+	 * Returns whether or not there was a non-micro version change (ie, change in either
648
+	 * the first or second number in the version. Eg 4.9.0.rc.001 to 4.10.0.rc.000,
649
+	 * but not 4.9.0.rc.0001 to 4.9.1.rc.0001
650
+	 *
651
+	 * @param $activation_history
652
+	 * @return bool
653
+	 */
654
+	private function _detect_major_version_change($activation_history): bool
655
+	{
656
+		$previous_version       = EE_System::getMostRecentlyActiveVersion($activation_history);
657
+		$previous_version_parts = explode('.', $previous_version);
658
+		$current_version_parts  = explode('.', espresso_version());
659
+		return isset(
660
+				   $previous_version_parts[0],
661
+				   $previous_version_parts[1],
662
+				   $current_version_parts[0],
663
+				   $current_version_parts[1]
664
+			   ) && (
665
+				   $previous_version_parts[0] !== $current_version_parts[0]
666
+				   || $previous_version_parts[1] !== $current_version_parts[1]
667
+			   );
668
+	}
669
+
670
+
671
+	/**
672
+	 * Returns true if either the major or minor version of EE changed during this request.
673
+	 * Eg 4.9.0.rc.001 to 4.10.0.rc.000, but not 4.9.0.rc.0001 to 4.9.1.rc.0001
674
+	 *
675
+	 * @return bool
676
+	 */
677
+	public function is_major_version_change(): bool
678
+	{
679
+		return $this->_major_version_change;
680
+	}
681
+
682
+
683
+	/**
684
+	 * Determines the request type for any ee addon, given three piece of info: the current array of activation
685
+	 * histories (for core that' 'espresso_db_update' wp option); the name of the WordPress option which is temporarily
686
+	 * set upon activation of the plugin (for core it's 'ee_espresso_activation'); and the version that this plugin was
687
+	 * just activated to (for core that will always be espresso_version())
688
+	 *
689
+	 * @param array|null $activation_history               the option's value which stores the activation history for
690
+	 *                                                     this
691
+	 *                                                     ee plugin. for core that's 'espresso_db_update'
692
+	 * @param string     $activation_indicator_option_name the name of the WordPress option that is temporarily set to
693
+	 *                                                     indicate that this plugin was just activated
694
+	 * @param string     $current_version                  the version that was just upgraded to (for core that will be
695
+	 *                                                     espresso_version())
696
+	 * @return int one of the constants on EE_System::req_type_
697
+	 */
698
+	public static function detect_req_type_given_activation_history(
699
+		array $activation_history,
700
+		string $activation_indicator_option_name,
701
+		string $current_version
702
+	): int {
703
+		$version_change = self::compareVersionWithPrevious($activation_history, $current_version);
704
+		$is_activation  = get_option($activation_indicator_option_name, false);
705
+		$req_type       = self::getRequestType($activation_history, $version_change, $is_activation);
706
+		if ($is_activation) {
707
+			// cleanup in aisle 6
708
+			delete_option($activation_indicator_option_name);
709
+		}
710
+		return $req_type;
711
+	}
712
+
713
+
714
+	/**
715
+	 * @param array $activation_history
716
+	 * @param int   $version_change
717
+	 * @param bool  $is_activation
718
+	 * @return int
719
+	 * @since 5.0.0.p
720
+	 */
721
+	private static function getRequestType(array $activation_history, int $version_change, bool $is_activation): int
722
+	{
723
+		// if no previous activation history exists, then this is a brand new install
724
+		if (empty($activation_history)) {
725
+			return EE_System::req_type_new_activation;
726
+		}
727
+		// current version is higher than previous version, so it's an upgrade
728
+		if ($version_change === 1) {
729
+			return EE_System::req_type_upgrade;
730
+		}
731
+		// current version is lower than previous version, so it's a downgrade
732
+		if ($version_change === -1) {
733
+			return EE_System::req_type_downgrade;
734
+		}
735
+		// version hasn't changed since last version so check if the activation indicator is set
736
+		// to determine if it's a reactivation, or just a normal request
737
+		return $is_activation
738
+			? EE_System::req_type_reactivation
739
+			: EE_System::req_type_normal;
740
+	}
741
+
742
+
743
+	/**
744
+	 * Detects if the $version_to_upgrade_to is higher than the most recent version in
745
+	 * the $activation_history_for_addon
746
+	 *
747
+	 * @param array  $activation_history    array where keys are versions,
748
+	 *                                      values are arrays of times activated (sometimes 'unknown-date')
749
+	 * @param string $current_version
750
+	 * @return int results of version_compare( $version_to_upgrade_to, $most_recently_active_version ).
751
+	 *                                      -1 if $version_to_upgrade_to is LOWER (downgrade);
752
+	 *                                      0 if $version_to_upgrade_to MATCHES (reactivation or normal request);
753
+	 *                                      1 if $version_to_upgrade_to is HIGHER (upgrade) ;
754
+	 */
755
+	private static function compareVersionWithPrevious(array $activation_history, string $current_version): int
756
+	{
757
+		// find the most recently-activated version
758
+		$most_recently_active_version = EE_System::getMostRecentlyActiveVersion($activation_history);
759
+		return version_compare($current_version, $most_recently_active_version);
760
+	}
761
+
762
+
763
+	/**
764
+	 * Gets the most recently active version listed in the activation history,
765
+	 * and if none are found (ie, it's a brand new install) returns '0.0.0.dev.000'.
766
+	 *
767
+	 * @param array|null $activation_history (keys are versions, values are arrays of times activated,
768
+	 *                                       sometimes containing 'unknown-date'
769
+	 * @return string
770
+	 */
771
+	private static function getMostRecentlyActiveVersion(?array $activation_history): string
772
+	{
773
+		$most_recent_activation_date  = '1970-01-01 00:00:00';
774
+		$most_recently_active_version = '0.0.0.dev.000';
775
+		if (is_array($activation_history)) {
776
+			foreach ($activation_history as $version => $activation_dates) {
777
+				// check there is a record of when this version was activated.
778
+				// Otherwise, mark it as unknown
779
+				if (! $activation_dates) {
780
+					$activation_dates = ['unknown-date'];
781
+				}
782
+				$activation_dates = is_string($activation_dates)
783
+					? [$activation_dates]
784
+					: $activation_dates;
785
+				foreach ($activation_dates as $activation_date) {
786
+					if ($activation_date !== 'unknown-date' && $activation_date > $most_recent_activation_date) {
787
+						$most_recently_active_version = $version;
788
+						$most_recent_activation_date  = $activation_date;
789
+					}
790
+				}
791
+			}
792
+		}
793
+		return $most_recently_active_version;
794
+	}
795
+
796
+
797
+	/**
798
+	 * This redirects to the about EE page after activation
799
+	 *
800
+	 * @return void
801
+	 */
802
+	public function redirect_to_about_ee()
803
+	{
804
+		$notices = EE_Error::get_notices(false);
805
+		// if current user is an admin and it's not an ajax or rest request
806
+		if (
807
+			! isset($notices['errors'])
808
+			&& $this->request->isAdmin()
809
+			&& apply_filters(
810
+				'FHEE__EE_System__redirect_to_about_ee__do_redirect',
811
+				$this->capabilities->current_user_can('manage_options', 'espresso_about_default')
812
+			)
813
+		) {
814
+			$query_params = ['page' => 'espresso_about'];
815
+			if (EE_System::instance()->detect_req_type() === EE_System::req_type_new_activation) {
816
+				$query_params['new_activation'] = true;
817
+			}
818
+			if (EE_System::instance()->detect_req_type() === EE_System::req_type_reactivation) {
819
+				$query_params['reactivation'] = true;
820
+			}
821
+			$url = add_query_arg($query_params, admin_url('admin.php'));
822
+			EEH_URL::safeRedirectAndExit($url);
823
+		}
824
+	}
825
+
826
+
827
+	/**
828
+	 * load_core_configuration
829
+	 * this is hooked into 'AHEE__EE_Bootstrap__load_core_configuration'
830
+	 * which runs during the WP 'plugins_loaded' action at priority 5
831
+	 *
832
+	 * @return void
833
+	 * @throws ReflectionException
834
+	 * @throws Exception
835
+	 */
836
+	public function load_core_configuration()
837
+	{
838
+		do_action('AHEE__EE_System__load_core_configuration__begin', $this);
839
+		$this->loader->getShared('EE_Load_Textdomain');
840
+		// load textdomain
841
+		EE_Load_Textdomain::load_textdomain();
842
+		// load and setup EE_Config and EE_Network_Config
843
+		$config = $this->loader->getShared('EE_Config');
844
+		$this->loader->getShared('EE_Network_Config');
845
+		// setup autoloaders
846
+		// enable logging?
847
+		$this->loader->getShared('EventEspresso\core\services\orm\TrashLogger');
848
+		if ($config->admin->use_remote_logging) {
849
+			$this->loader->getShared('EE_Log');
850
+		}
851
+		// check for activation errors
852
+		$activation_errors = get_option('ee_plugin_activation_errors', false);
853
+		if ($activation_errors) {
854
+			EE_Error::add_error($activation_errors, __FILE__, __FUNCTION__, __LINE__);
855
+			update_option('ee_plugin_activation_errors', false);
856
+		}
857
+		// get model names
858
+		$this->_parse_model_names();
859
+		// configure custom post type definitions
860
+		$this->loader->getShared('EventEspresso\core\domain\entities\custom_post_types\CustomTaxonomyDefinitions');
861
+		$this->loader->getShared('EventEspresso\core\domain\entities\custom_post_types\CustomPostTypeDefinitions');
862
+		do_action('AHEE__EE_System__load_core_configuration__complete', $this);
863
+	}
864
+
865
+
866
+	/**
867
+	 * cycles through all of the models/*.model.php files, and assembles an array of model names
868
+	 *
869
+	 * @return void
870
+	 * @throws ReflectionException
871
+	 */
872
+	private function _parse_model_names()
873
+	{
874
+		// get all the files in the EE_MODELS folder that end in .model.php
875
+		$models                 = glob(EE_MODELS . '*.model.php');
876
+		$model_names            = [];
877
+		$non_abstract_db_models = [];
878
+		foreach ($models as $model) {
879
+			// get model classname
880
+			$classname       = EEH_File::get_classname_from_filepath_with_standard_filename($model);
881
+			$short_name      = str_replace('EEM_', '', $classname);
882
+			$reflectionClass = new ReflectionClass($classname);
883
+			if ($reflectionClass->isSubclassOf('EEM_Base') && ! $reflectionClass->isAbstract()) {
884
+				$non_abstract_db_models[ $short_name ] = $classname;
885
+			}
886
+			$model_names[ $short_name ] = $classname;
887
+		}
888
+		$this->registry->models                 = apply_filters('FHEE__EE_System__parse_model_names', $model_names);
889
+		$this->registry->non_abstract_db_models = apply_filters(
890
+			'FHEE__EE_System__parse_implemented_model_names',
891
+			$non_abstract_db_models
892
+		);
893
+	}
894
+
895
+
896
+	/**
897
+	 * @throws Exception
898
+	 * @since 4.9.71.p
899
+	 */
900
+	public function loadRouteMatchSpecifications()
901
+	{
902
+		try {
903
+			$this->loader->getShared('EventEspresso\core\services\routing\RouteMatchSpecificationManager');
904
+			$this->loader->getShared('EventEspresso\core\services\routing\RouteCollection');
905
+			$this->router->loadPrimaryRoutes();
906
+		} catch (Exception $exception) {
907
+			new ExceptionStackTraceDisplay($exception);
908
+		}
909
+		do_action('AHEE__EE_System__loadRouteMatchSpecifications');
910
+	}
911
+
912
+
913
+	/**
914
+	 * loading CPT related classes earlier so that their definitions are available
915
+	 * but not performing any actual registration with WP core until load_CPTs_and_session() is called
916
+	 *
917
+	 * @since   4.10.21.p
918
+	 */
919
+	public function loadCustomPostTypes()
920
+	{
921
+		$this->register_custom_taxonomies     = $this->loader->getShared(
922
+			'EventEspresso\core\domain\services\custom_post_types\RegisterCustomTaxonomies'
923
+		);
924
+		$this->register_custom_post_types     = $this->loader->getShared(
925
+			'EventEspresso\core\domain\services\custom_post_types\RegisterCustomPostTypes'
926
+		);
927
+		$this->register_custom_taxonomy_terms = $this->loader->getShared(
928
+			'EventEspresso\core\domain\services\custom_post_types\RegisterCustomTaxonomyTerms'
929
+		);
930
+		// integrate WP_Query with the EE models
931
+		$this->loader->getShared('EE_CPT_Strategy');
932
+		// load legacy EE_Request_Handler in case add-ons still need it
933
+		$this->loader->getShared('EE_Request_Handler');
934
+	}
935
+
936
+
937
+	/**
938
+	 * register_shortcodes_modules_and_widgets
939
+	 * generate lists of shortcodes and modules, then verify paths and classes
940
+	 * This is hooked into 'AHEE__EE_Bootstrap__register_shortcodes_modules_and_widgets'
941
+	 * which runs during the WP 'plugins_loaded' action at priority 7
942
+	 *
943
+	 * @access public
944
+	 * @return void
945
+	 * @throws Exception
946
+	 */
947
+	public function register_shortcodes_modules_and_widgets()
948
+	{
949
+		$this->router->registerShortcodesModulesAndWidgets();
950
+		do_action('AHEE__EE_System__register_shortcodes_modules_and_widgets');
951
+		// check for addons using old hook point
952
+		if (has_action('AHEE__EE_System__register_shortcodes_modules_and_addons')) {
953
+			$this->_incompatible_addon_error();
954
+		}
955
+	}
956
+
957
+
958
+	/**
959
+	 * _incompatible_addon_error
960
+	 *
961
+	 * @access public
962
+	 * @return void
963
+	 */
964
+	private function _incompatible_addon_error()
965
+	{
966
+		// get array of classes hooking into here
967
+		$class_names = WordPressHooks::getClassNamesForAllCallbacksOnHook(
968
+			'AHEE__EE_System__register_shortcodes_modules_and_addons'
969
+		);
970
+		if (! empty($class_names)) {
971
+			$msg = esc_html__(
972
+				'The following plugins, addons, or modules appear to be incompatible with this version of Event Espresso and were automatically deactivated to avoid fatal errors:',
973
+				'event_espresso'
974
+			);
975
+			$msg .= '<ul>';
976
+			foreach ($class_names as $class_name) {
977
+				$msg .= '<li><b>Event Espresso - '
978
+						. str_replace(
979
+							['EE_', 'EEM_', 'EED_', 'EES_', 'EEW_'],
980
+							'',
981
+							$class_name
982
+						) . '</b></li>';
983
+			}
984
+			$msg .= '</ul>';
985
+			$msg .= esc_html__(
986
+				'Compatibility issues can be avoided and/or resolved by keeping addons and plugins updated to the latest version.',
987
+				'event_espresso'
988
+			);
989
+			// save list of incompatible addons to wp-options for later use
990
+			add_option('ee_incompatible_addons', $class_names, '', 'no');
991
+			if (is_admin()) {
992
+				EE_Error::add_error($msg, __FILE__, __FUNCTION__, __LINE__);
993
+			}
994
+		}
995
+	}
996
+
997
+
998
+	/**
999
+	 * brew_espresso
1000
+	 * begins the process of setting hooks for initializing EE in the correct order
1001
+	 * This is happening on the 'AHEE__EE_Bootstrap__brew_espresso' hook point
1002
+	 * which runs during the WP 'plugins_loaded' action at priority 9
1003
+	 *
1004
+	 * @return void
1005
+	 * @throws Exception
1006
+	 */
1007
+	public function brew_espresso()
1008
+	{
1009
+		do_action('AHEE__EE_System__brew_espresso__begin', $this);
1010
+		// load some final core systems
1011
+		add_action('init', [$this, 'set_hooks_for_core'], 1);
1012
+		add_action('init', [$this, 'perform_activations_upgrades_and_migrations'], 3);
1013
+		add_action('init', [$this, 'load_CPTs_and_session'], 5);
1014
+		add_action('init', [$this, 'load_controllers'], 7);
1015
+		add_action('init', [$this, 'core_loaded_and_ready'], 9);
1016
+		add_action('init', [$this, 'initialize'], 10);
1017
+		add_action('init', [$this, 'initialize_last'], 100);
1018
+		$this->router->brewEspresso();
1019
+		$this->loader->getShared('EventEspresso\PaymentMethods\Manager');
1020
+		$this->loader->getShared('EE_Payment_Method_Manager');
1021
+		do_action('AHEE__EE_System__brew_espresso__complete', $this);
1022
+	}
1023
+
1024
+
1025
+	/**
33 1026
     /**
34
-     * indicates this is a 'normal' request. Ie, not activation, nor upgrade, nor activation.
35
-     * So examples of this would be a normal GET request on the frontend or backend, or a POST, etc
36
-     */
37
-    const req_type_normal = 0;
38
-
39
-    /**
40
-     * Indicates this is a brand new installation of EE so we should install
41
-     * tables and default data etc
42
-     */
43
-    const req_type_new_activation = 1;
44
-
45
-    /**
46
-     * we've detected that EE has been reactivated (or EE was activated during maintenance mode,
47
-     * and we just exited maintenance mode). We MUST check the database is setup properly
48
-     * and that default data is setup too
49
-     */
50
-    const req_type_reactivation = 2;
51
-
52
-    /**
53
-     * indicates that EE has been upgraded since its previous request.
54
-     * We may have data migration scripts to call and will want to trigger maintenance mode
55
-     */
56
-    const req_type_upgrade = 3;
57
-
58
-    /**
59
-     * TODO  will detect that EE has been DOWNGRADED. We probably don't want to run in this case...
60
-     */
61
-    const req_type_downgrade = 4;
62
-
63
-    /**
64
-     * @deprecated since version 4.6.0.dev.006
65
-     * Now whenever a new_activation is detected the request type is still just
66
-     * new_activation (same for reactivation, upgrade, downgrade etc), but if we're in maintenance mode
67
-     * EE_System::initialize_db_if_no_migrations_required and EE_Addon::initialize_db_if_no_migrations_required
68
-     * will instead enqueue that EE plugin's db initialization for when we're taken out of maintenance mode.
69
-     * (Specifically, when the migration manager indicates migrations are finished
70
-     * EE_Data_Migration_Manager::initialize_db_for_enqueued_ee_plugins() will be called)
71
-     */
72
-    const req_type_activation_but_not_installed = 5;
73
-
74
-    /**
75
-     * option prefix for recording the activation history (like core's "espresso_db_update") of addons
76
-     */
77
-    const addon_activation_history_option_prefix = 'ee_addon_activation_history_';
78
-
79
-    private static ?EE_System $_instance = null;
80
-
81
-    private ?LoaderInterface $loader;
82
-
83
-    private ?EE_Maintenance_Mode $maintenance_mode;
84
-
85
-    private ?EE_Registry $registry;
86
-
87
-    private ?RequestInterface $request;
88
-
89
-    private Router $router;
90
-
91
-    private ?AddonManager $addon_manager = null;
92
-
93
-    private ?EE_Capabilities $capabilities = null;
94
-
95
-    protected ?FeatureFlags $feature = null;
96
-
97
-    private ?RegisterCustomPostTypes $register_custom_post_types = null;
98
-
99
-    private ?RegisterCustomTaxonomies $register_custom_taxonomies = null;
100
-
101
-    private ?RegisterCustomTaxonomyTerms $register_custom_taxonomy_terms = null;
102
-
103
-    /**
104
-     * Stores which type of request this is, options being one of the constants on EE_System starting with req_type_*.
105
-     * It can be a brand-new activation, a reactivation, an upgrade, a downgrade, or a normal request.
106
-     */
107
-    private ?int $_req_type = null;
108
-
109
-    /**
110
-     * Whether or not there was a non-micro version change in EE core version during this request
111
-     */
112
-    private bool $_major_version_change = false;
113
-
114
-
115
-    /**
116
-     * @singleton method used to instantiate class object
117
-     * @param LoaderInterface|null     $loader
118
-     * @param EE_Maintenance_Mode|null $maintenance_mode
119
-     * @param EE_Registry|null         $registry
120
-     * @param RequestInterface|null    $request
121
-     * @param Router|null              $router
122
-     * @param FeatureFlags|null        $feature
123
-     * @return EE_System
124
-     */
125
-    public static function instance(
126
-        ?LoaderInterface $loader = null,
127
-        ?EE_Maintenance_Mode $maintenance_mode = null,
128
-        ?EE_Registry $registry = null,
129
-        ?RequestInterface $request = null,
130
-        ?Router $router = null,
131
-        ?FeatureFlags $feature = null
132
-    ): EE_System {
133
-        // check if class object is instantiated
134
-        if (! self::$_instance instanceof EE_System) {
135
-            self::$_instance = new self($loader, $maintenance_mode, $registry, $request, $router, $feature);
136
-        }
137
-        return self::$_instance;
138
-    }
139
-
140
-
141
-    /**
142
-     * resets the instance and returns it
143
-     *
144
-     * @return EE_System
145
-     */
146
-    public static function reset(): EE_System
147
-    {
148
-        self::$_instance->_req_type = null;
149
-        // make sure none of the old hooks are left hanging around
150
-        remove_all_actions('AHEE__EE_System__perform_activations_upgrades_and_migrations');
151
-        // we need to reset the migration manager in order for it to detect DMSs properly
152
-        EE_Data_Migration_Manager::reset();
153
-        self::instance()->detect_activations_or_upgrades();
154
-        self::instance()->perform_activations_upgrades_and_migrations();
155
-        return self::instance();
156
-    }
157
-
158
-
159
-    /**
160
-     * sets hooks for running rest of system
161
-     * provides "AHEE__EE_System__construct__complete" hook for EE Addons to use as their starting point
162
-     * starting EE Addons from any other point may lead to problems
163
-     *
164
-     * @param LoaderInterface     $loader
165
-     * @param EE_Maintenance_Mode $maintenance_mode
166
-     * @param EE_Registry         $registry
167
-     * @param RequestInterface    $request
168
-     * @param Router              $router
169
-     * @param FeatureFlags        $feature
170
-     */
171
-    private function __construct(
172
-        LoaderInterface $loader,
173
-        EE_Maintenance_Mode $maintenance_mode,
174
-        EE_Registry $registry,
175
-        RequestInterface $request,
176
-        Router $router,
177
-        FeatureFlags $feature
178
-    ) {
179
-        $this->registry         = $registry;
180
-        $this->loader           = $loader;
181
-        $this->request          = $request;
182
-        $this->router           = $router;
183
-        $this->maintenance_mode = $maintenance_mode;
184
-        $this->feature          = $feature;
185
-        do_action('AHEE__EE_System__construct__begin', $this);
186
-        add_action(
187
-            'AHEE__EE_Bootstrap__load_espresso_addons',
188
-            [$this, 'loadWpGraphQL'],
189
-            3
190
-        );
191
-        add_action(
192
-            'AHEE__EE_Bootstrap__load_espresso_addons',
193
-            [$this, 'loadCapabilities'],
194
-            5
195
-        );
196
-        add_action(
197
-            'AHEE__EE_Bootstrap__load_espresso_addons',
198
-            [$this, 'loadCommandBus'],
199
-            7
200
-        );
201
-        add_action(
202
-            'AHEE__EE_Bootstrap__load_espresso_addons',
203
-            [$this, 'loadPluginApi'],
204
-            9
205
-        );
206
-        // give caff stuff a chance to play during the activation process too.
207
-        add_action(
208
-            'AHEE__EE_Bootstrap__load_espresso_addons',
209
-            [$this, 'brewCaffeinated'],
210
-            9
211
-        );
212
-        // allow addons to load first so that they can register autoloaders, set hooks for running DMS's, etc
213
-        add_action(
214
-            'AHEE__EE_Bootstrap__load_espresso_addons',
215
-            [$this, 'load_espresso_addons']
216
-        );
217
-        // when an ee addon is activated, we want to call the core hook(s) again
218
-        // because the newly-activated addon didn't get a chance to run at all
219
-        add_action('activate_plugin', [$this, 'load_espresso_addons'], 1);
220
-        // detect whether install or upgrade
221
-        add_action(
222
-            'AHEE__EE_Bootstrap__detect_activations_or_upgrades',
223
-            [$this, 'detect_activations_or_upgrades'],
224
-            3
225
-        );
226
-        // load EE_Config, EE_Textdomain, etc
227
-        add_action(
228
-            'AHEE__EE_Bootstrap__load_core_configuration',
229
-            [$this, 'load_core_configuration'],
230
-            5
231
-        );
232
-        // load specifications for matching routes to current request
233
-        add_action(
234
-            'AHEE__EE_Bootstrap__load_core_configuration',
235
-            [$this, 'loadRouteMatchSpecifications']
236
-        );
237
-        // load specifications for custom post types
238
-        add_action(
239
-            'AHEE__EE_Bootstrap__load_core_configuration',
240
-            [$this, 'loadCustomPostTypes']
241
-        );
242
-        // load specifications for custom post types
243
-        add_action(
244
-            'AHEE__EE_Bootstrap__load_core_configuration',
245
-            [$this, 'loadCustomPostTypes']
246
-        );
247
-        // load EE_Config, EE_Textdomain, etc
248
-        add_action(
249
-            'AHEE__EE_Bootstrap__register_shortcodes_modules_and_widgets',
250
-            [$this, 'register_shortcodes_modules_and_widgets'],
251
-            7
252
-        );
253
-        // you wanna get going? I wanna get going... let's get going!
254
-        add_action(
255
-            'AHEE__EE_Bootstrap__brew_espresso',
256
-            [$this, 'brew_espresso'],
257
-            9
258
-        );
259
-        // other housekeeping
260
-        // exclude EE critical pages from wp_list_pages
261
-        add_filter(
262
-            'wp_list_pages_excludes',
263
-            [$this, 'remove_pages_from_wp_list_pages'],
264
-            10
265
-        );
266
-        // ALL EE Addons should use the following hook point to attach their initial setup too
267
-        // it's extremely important for EE Addons to register any class autoloaders so that they can be available when the EE_Config loads
268
-        do_action('AHEE__EE_System__construct__complete', $this);
269
-    }
270
-
271
-
272
-    /**
273
-     * load and setup EE_Capabilities
274
-     *
275
-     * @return void
276
-     */
277
-    public function loadWpGraphQL()
278
-    {
279
-        espressoLoadWpGraphQL();
280
-    }
281
-
282
-
283
-    /**
284
-     * load and setup EE_Capabilities
285
-     *
286
-     * @return void
287
-     */
288
-    public function loadCapabilities()
289
-    {
290
-        $this->capabilities = $this->loader->getShared('EE_Capabilities');
291
-    }
292
-
293
-
294
-    /**
295
-     * create and cache the CommandBus, and also add middleware
296
-     * The CapChecker middleware requires the use of EE_Capabilities
297
-     * which is why we need to load the CommandBus after Caps are set up
298
-     * CommandBus middleware operate FIFO - First In First Out
299
-     * so LocateMovedCommands will run first in order to return any new commands
300
-     *
301
-     * @return void
302
-     */
303
-    public function loadCommandBus()
304
-    {
305
-        $this->loader->getShared(
306
-            'CommandBusInterface',
307
-            [
308
-                null,
309
-                apply_filters(
310
-                    'FHEE__EE_Load_Espresso_Core__handle_request__CommandBus_middleware',
311
-                    [
312
-                        $this->loader->getShared('EventEspresso\core\services\commands\middleware\LocateMovedCommands'),
313
-                        $this->loader->getShared('EventEspresso\core\services\commands\middleware\CapChecker'),
314
-                        $this->loader->getShared('EventEspresso\core\services\commands\middleware\AddActionHook'),
315
-                    ]
316
-                ),
317
-            ]
318
-        );
319
-    }
320
-
321
-
322
-    /**
323
-     * @return void
324
-     * @throws Exception
325
-     */
326
-    public function loadPluginApi()
327
-    {
328
-        $this->addon_manager = $this->loader->getShared(AddonManager::class);
329
-        $this->addon_manager->initialize();
330
-        $this->loader->getShared('EE_Request_Handler');
331
-    }
332
-
333
-
334
-    /**
335
-     * The purpose of this method is to simply check for a file named "caffeinated/brewing_regular.php" for any hooks
336
-     * that need to be setup before our EE_System launches.
337
-     *
338
-     * @return void
339
-     * @throws DomainException
340
-     * @throws InvalidArgumentException
341
-     * @throws InvalidDataTypeException
342
-     * @throws InvalidInterfaceException
343
-     * @throws InvalidClassException
344
-     * @throws InvalidFilePathException
345
-     * @throws EE_Error
346
-     */
347
-    public function brewCaffeinated()
348
-    {
349
-        static $brew;
350
-        /** @var Domain $domain */
351
-        $domain = DomainFactory::getEventEspressoCoreDomain();
352
-        if ($domain->isCaffeinated() && ! $brew instanceof EE_Brewing_Regular) {
353
-            require_once EE_CAFF_PATH . 'brewing_regular.php';
354
-            /** @var EE_Brewing_Regular $brew */
355
-            $brew = LoaderFactory::getLoader()->getShared(EE_Brewing_Regular::class);
356
-            if (! $this->feature->allowed('use_edd_plugin_licensing')) {
357
-                $brew->initializePUE();
358
-            }
359
-            add_action(
360
-                'AHEE__EE_System__load_core_configuration__begin',
361
-                [$brew, 'caffeinated']
362
-            );
363
-        }
364
-    }
365
-
366
-
367
-    /**
368
-     * load_espresso_addons
369
-     * allow addons to load first so that they can set hooks for running DMS's, etc
370
-     * this is hooked into both:
371
-     *    'AHEE__EE_Bootstrap__load_core_configuration'
372
-     *        which runs during the WP 'plugins_loaded' action at priority 5
373
-     *    and the WP 'activate_plugin' hook point
374
-     *
375
-     * @return void
376
-     * @throws Exception
377
-     * @throws Throwable
378
-     */
379
-    public function load_espresso_addons()
380
-    {
381
-        if ($this->feature->allowed('use_edd_plugin_licensing')) {
382
-            new EventEspresso\core\services\licensing\PluginLicense(
383
-                EVENT_ESPRESSO_MAIN_FILE,
384
-                0,
385
-                'Event Espresso Core',
386
-                'event_espresso_core',
387
-                espresso_version()
388
-            );
389
-        }
390
-        // looking for hooks? they've been moved into the AddonManager to maintain compatibility
391
-        $this->addon_manager->loadAddons();
392
-    }
393
-
394
-
395
-    /**
396
-     * detect_activations_or_upgrades
397
-     * Checks for activation or upgrade of core first;
398
-     * then also checks if any registered addons have been activated or upgraded
399
-     * This is hooked into 'AHEE__EE_Bootstrap__detect_activations_or_upgrades'
400
-     * which runs during the WP 'plugins_loaded' action at priority 3
401
-     *
402
-     * @access public
403
-     * @return void
404
-     */
405
-    public function detect_activations_or_upgrades()
406
-    {
407
-        // first off: let's make sure to handle core
408
-        $this->detect_if_activation_or_upgrade();
409
-        foreach ($this->registry->addons as $addon) {
410
-            if ($addon instanceof EE_Addon) {
411
-                // detect teh request type for that addon
412
-                $addon->detect_req_type();
413
-            }
414
-        }
415
-    }
416
-
417
-
418
-    /**
419
-     * detect_if_activation_or_upgrade
420
-     * Takes care of detecting whether this is a brand new install or code upgrade,
421
-     * and either setting up the DB or setting up maintenance mode etc.
422
-     *
423
-     * @access public
424
-     * @return void
425
-     */
426
-    public function detect_if_activation_or_upgrade()
427
-    {
428
-        do_action('AHEE__EE_System___detect_if_activation_or_upgrade__begin');
429
-        // check if db has been updated, or if its a brand-new installation
430
-        $espresso_db_update = $this->fix_espresso_db_upgrade_option();
431
-        $request_type       = $this->detect_req_type($espresso_db_update);
432
-        switch ($request_type) {
433
-            case EE_System::req_type_new_activation:
434
-                do_action('AHEE__EE_System__detect_if_activation_or_upgrade__new_activation');
435
-                $this->_handle_core_version_change($espresso_db_update);
436
-                break;
437
-            case EE_System::req_type_reactivation:
438
-                do_action('AHEE__EE_System__detect_if_activation_or_upgrade__reactivation');
439
-                $this->_handle_core_version_change($espresso_db_update);
440
-                break;
441
-            case EE_System::req_type_upgrade:
442
-                do_action('AHEE__EE_System__detect_if_activation_or_upgrade__upgrade');
443
-                // migrations may be required now that we've upgraded
444
-                $this->maintenance_mode->set_maintenance_mode_if_db_old();
445
-                $this->_handle_core_version_change($espresso_db_update);
446
-                break;
447
-            case EE_System::req_type_downgrade:
448
-                do_action('AHEE__EE_System__detect_if_activation_or_upgrade__downgrade');
449
-                // its possible migrations are no longer required
450
-                $this->maintenance_mode->set_maintenance_mode_if_db_old();
451
-                $this->_handle_core_version_change($espresso_db_update);
452
-                break;
453
-            case EE_System::req_type_normal:
454
-            default:
455
-                break;
456
-        }
457
-        do_action('AHEE__EE_System__detect_if_activation_or_upgrade__complete');
458
-    }
459
-
460
-
461
-    /**
462
-     * Updates the list of installed versions and sets hooks for
463
-     * initializing the database later during the request
464
-     *
465
-     * @param array $espresso_db_update
466
-     */
467
-    private function _handle_core_version_change(array $espresso_db_update)
468
-    {
469
-        $this->update_list_of_installed_versions($espresso_db_update);
470
-        // get ready to verify the DB is ok (provided we aren't in maintenance mode, of course)
471
-        add_action(
472
-            'AHEE__EE_System__perform_activations_upgrades_and_migrations',
473
-            [$this, 'initialize_db_if_no_migrations_required']
474
-        );
475
-    }
476
-
477
-
478
-    /**
479
-     * standardizes the wp option 'espresso_db_upgrade' which actually stores
480
-     * information about what versions of EE have been installed and activated,
481
-     * NOT necessarily the state of the database
482
-     *
483
-     * @param mixed $espresso_db_update           the value of the WordPress option.
484
-     *                                            If not supplied, fetches it from the options table
485
-     * @return array the correct value of 'espresso_db_upgrade', after saving it, if it needed correction
486
-     */
487
-    private function fix_espresso_db_upgrade_option($espresso_db_update = null): array
488
-    {
489
-        do_action('FHEE__EE_System__manage_fix_espresso_db_upgrade_option__begin', $espresso_db_update);
490
-        if (! $espresso_db_update) {
491
-            $espresso_db_update = get_option('espresso_db_update');
492
-        }
493
-        // check that option is an array
494
-        if (! is_array($espresso_db_update)) {
495
-            // if option is FALSE, then it never existed
496
-            if ($espresso_db_update === false) {
497
-                // make $espresso_db_update an array and save option with autoload OFF
498
-                $espresso_db_update = [];
499
-                add_option('espresso_db_update', $espresso_db_update, '', 'no');
500
-            } else {
501
-                // option is NOT FALSE but also is NOT an array, so make it an array and save it
502
-                $espresso_db_update = [$espresso_db_update => []];
503
-                update_option('espresso_db_update', $espresso_db_update);
504
-            }
505
-        } else {
506
-            $corrected_db_update = [];
507
-            // if IS an array, but is it an array where KEYS are version numbers, and values are arrays?
508
-            foreach ($espresso_db_update as $should_be_version_string => $should_be_array) {
509
-                if (is_int($should_be_version_string) && ! is_array($should_be_array)) {
510
-                    // the key is an int, and the value IS NOT an array
511
-                    // so it must be numerically-indexed, where values are versions installed...
512
-                    // fix it!
513
-                    $version_string                         = $should_be_array;
514
-                    $corrected_db_update[ $version_string ] = ['unknown-date'];
515
-                } else {
516
-                    // ok it checks out
517
-                    $corrected_db_update[ $should_be_version_string ] = $should_be_array;
518
-                }
519
-            }
520
-            $espresso_db_update = $corrected_db_update;
521
-            update_option('espresso_db_update', $espresso_db_update);
522
-        }
523
-        do_action('FHEE__EE_System__manage_fix_espresso_db_upgrade_option__complete', $espresso_db_update);
524
-        return ! empty($espresso_db_update)
525
-            ? $espresso_db_update
526
-            : [];
527
-    }
528
-
529
-
530
-    /**
531
-     * Does the traditional work of setting up the plugin's database and adding default data.
532
-     * If migration script/process did not exist, this is what would happen on every activation/reactivation/upgrade.
533
-     * NOTE: if we're in maintenance mode (which would be the case if we detect there are data
534
-     * migration scripts that need to be run and a version change happens), enqueues core for database initialization,
535
-     * so that it will be done when migrations are finished
536
-     *
537
-     * @param boolean $initialize_addons_too if true, we double-check addons' database tables etc too;
538
-     * @param boolean $verify_schema         if true will re-check the database tables have the correct schema.
539
-     *                                       This is a resource-intensive job
540
-     *                                       so we prefer to only do it when necessary
541
-     * @return void
542
-     * @throws EE_Error
543
-     * @throws ReflectionException
544
-     */
545
-    public function initialize_db_if_no_migrations_required($initialize_addons_too = false, $verify_schema = true)
546
-    {
547
-        $request_type = $this->detect_req_type();
548
-        // only initialize system if we're not in maintenance mode.
549
-        if (! MaintenanceStatus::isFullSite()) {
550
-            /** @var EventEspresso\core\domain\services\custom_post_types\RewriteRules $rewrite_rules */
551
-            $rewrite_rules = $this->loader->getShared(
552
-                'EventEspresso\core\domain\services\custom_post_types\RewriteRules'
553
-            );
554
-            $rewrite_rules->flush();
555
-            if ($verify_schema) {
556
-                EEH_Activation::initialize_db_and_folders();
557
-            }
558
-            EEH_Activation::initialize_db_content();
559
-            EEH_Activation::system_initialization();
560
-            if ($initialize_addons_too) {
561
-                $this->initialize_addons();
562
-            }
563
-        } else {
564
-            EE_Data_Migration_Manager::instance()->enqueue_db_initialization_for('Core');
565
-        }
566
-        if (
567
-            $request_type === EE_System::req_type_new_activation
568
-            || $request_type === EE_System::req_type_reactivation
569
-            || (
570
-                $request_type === EE_System::req_type_upgrade
571
-                && $this->is_major_version_change()
572
-            )
573
-        ) {
574
-            add_action('AHEE__EE_System__initialize_last', [$this, 'redirect_to_about_ee'], 9);
575
-        }
576
-    }
577
-
578
-
579
-    /**
580
-     * Initializes the db for all registered addons
581
-     *
582
-     * @throws EE_Error
583
-     * @throws ReflectionException
584
-     */
585
-    public function initialize_addons()
586
-    {
587
-        // foreach registered addon, make sure its db is up-to-date too
588
-        foreach ($this->registry->addons as $addon) {
589
-            if ($addon instanceof EE_Addon) {
590
-                $addon->initialize_db_if_no_migrations_required();
591
-            }
592
-        }
593
-    }
594
-
595
-
596
-    /**
597
-     * Adds the current code version to the saved wp option which stores a list of all ee versions ever installed.
598
-     *
599
-     * @param array  $version_history
600
-     * @param string $current_version_to_add version to be added to the version history
601
-     * @return    boolean success as to whether or not this option was changed
602
-     */
603
-    public function update_list_of_installed_versions($version_history = null, $current_version_to_add = null): bool
604
-    {
605
-        if (! $version_history) {
606
-            $version_history = $this->fix_espresso_db_upgrade_option($version_history);
607
-        }
608
-        if ($current_version_to_add === null) {
609
-            $current_version_to_add = espresso_version();
610
-        }
611
-        $version_history[ $current_version_to_add ][] = date('Y-m-d H:i:s', time());
612
-        // re-save
613
-        return update_option('espresso_db_update', $version_history);
614
-    }
615
-
616
-
617
-    /**
618
-     * Detects if the current version indicated in the has existed in the list of
619
-     * previously-installed versions of EE (espresso_db_update). Does NOT modify it (ie, no side-effect)
620
-     *
621
-     * @param array|null $espresso_db_update array from the wp option stored under the name 'espresso_db_update'.
622
-     *                                       If not supplied, fetches it from the options table.
623
-     *                                       Also, caches its result so later parts of the code can also know whether
624
-     *                                       there's been an update or not. This way we can add the current version to
625
-     *                                       espresso_db_update, but still know if this is a new install or not
626
-     * @return int one of the constants on EE_System::req_type_
627
-     */
628
-    public function detect_req_type(?array $espresso_db_update = null): int
629
-    {
630
-        if ($this->_req_type === null) {
631
-            $espresso_db_update          = ! empty($espresso_db_update)
632
-                ? $espresso_db_update
633
-                : $this->fix_espresso_db_upgrade_option();
634
-            $this->_req_type             = EE_System::detect_req_type_given_activation_history(
635
-                $espresso_db_update,
636
-                'ee_espresso_activation',
637
-                espresso_version()
638
-            );
639
-            $this->_major_version_change = $this->_detect_major_version_change($espresso_db_update);
640
-            $this->request->setIsActivation($this->_req_type !== EE_System::req_type_normal);
641
-        }
642
-        return $this->_req_type;
643
-    }
644
-
645
-
646
-    /**
647
-     * Returns whether or not there was a non-micro version change (ie, change in either
648
-     * the first or second number in the version. Eg 4.9.0.rc.001 to 4.10.0.rc.000,
649
-     * but not 4.9.0.rc.0001 to 4.9.1.rc.0001
650
-     *
651
-     * @param $activation_history
652
-     * @return bool
653
-     */
654
-    private function _detect_major_version_change($activation_history): bool
655
-    {
656
-        $previous_version       = EE_System::getMostRecentlyActiveVersion($activation_history);
657
-        $previous_version_parts = explode('.', $previous_version);
658
-        $current_version_parts  = explode('.', espresso_version());
659
-        return isset(
660
-                   $previous_version_parts[0],
661
-                   $previous_version_parts[1],
662
-                   $current_version_parts[0],
663
-                   $current_version_parts[1]
664
-               ) && (
665
-                   $previous_version_parts[0] !== $current_version_parts[0]
666
-                   || $previous_version_parts[1] !== $current_version_parts[1]
667
-               );
668
-    }
669
-
670
-
671
-    /**
672
-     * Returns true if either the major or minor version of EE changed during this request.
673
-     * Eg 4.9.0.rc.001 to 4.10.0.rc.000, but not 4.9.0.rc.0001 to 4.9.1.rc.0001
674
-     *
675
-     * @return bool
676
-     */
677
-    public function is_major_version_change(): bool
678
-    {
679
-        return $this->_major_version_change;
680
-    }
681
-
682
-
683
-    /**
684
-     * Determines the request type for any ee addon, given three piece of info: the current array of activation
685
-     * histories (for core that' 'espresso_db_update' wp option); the name of the WordPress option which is temporarily
686
-     * set upon activation of the plugin (for core it's 'ee_espresso_activation'); and the version that this plugin was
687
-     * just activated to (for core that will always be espresso_version())
688
-     *
689
-     * @param array|null $activation_history               the option's value which stores the activation history for
690
-     *                                                     this
691
-     *                                                     ee plugin. for core that's 'espresso_db_update'
692
-     * @param string     $activation_indicator_option_name the name of the WordPress option that is temporarily set to
693
-     *                                                     indicate that this plugin was just activated
694
-     * @param string     $current_version                  the version that was just upgraded to (for core that will be
695
-     *                                                     espresso_version())
696
-     * @return int one of the constants on EE_System::req_type_
697
-     */
698
-    public static function detect_req_type_given_activation_history(
699
-        array $activation_history,
700
-        string $activation_indicator_option_name,
701
-        string $current_version
702
-    ): int {
703
-        $version_change = self::compareVersionWithPrevious($activation_history, $current_version);
704
-        $is_activation  = get_option($activation_indicator_option_name, false);
705
-        $req_type       = self::getRequestType($activation_history, $version_change, $is_activation);
706
-        if ($is_activation) {
707
-            // cleanup in aisle 6
708
-            delete_option($activation_indicator_option_name);
709
-        }
710
-        return $req_type;
711
-    }
712
-
713
-
714
-    /**
715
-     * @param array $activation_history
716
-     * @param int   $version_change
717
-     * @param bool  $is_activation
718
-     * @return int
719
-     * @since 5.0.0.p
720
-     */
721
-    private static function getRequestType(array $activation_history, int $version_change, bool $is_activation): int
722
-    {
723
-        // if no previous activation history exists, then this is a brand new install
724
-        if (empty($activation_history)) {
725
-            return EE_System::req_type_new_activation;
726
-        }
727
-        // current version is higher than previous version, so it's an upgrade
728
-        if ($version_change === 1) {
729
-            return EE_System::req_type_upgrade;
730
-        }
731
-        // current version is lower than previous version, so it's a downgrade
732
-        if ($version_change === -1) {
733
-            return EE_System::req_type_downgrade;
734
-        }
735
-        // version hasn't changed since last version so check if the activation indicator is set
736
-        // to determine if it's a reactivation, or just a normal request
737
-        return $is_activation
738
-            ? EE_System::req_type_reactivation
739
-            : EE_System::req_type_normal;
740
-    }
741
-
742
-
743
-    /**
744
-     * Detects if the $version_to_upgrade_to is higher than the most recent version in
745
-     * the $activation_history_for_addon
746
-     *
747
-     * @param array  $activation_history    array where keys are versions,
748
-     *                                      values are arrays of times activated (sometimes 'unknown-date')
749
-     * @param string $current_version
750
-     * @return int results of version_compare( $version_to_upgrade_to, $most_recently_active_version ).
751
-     *                                      -1 if $version_to_upgrade_to is LOWER (downgrade);
752
-     *                                      0 if $version_to_upgrade_to MATCHES (reactivation or normal request);
753
-     *                                      1 if $version_to_upgrade_to is HIGHER (upgrade) ;
754
-     */
755
-    private static function compareVersionWithPrevious(array $activation_history, string $current_version): int
756
-    {
757
-        // find the most recently-activated version
758
-        $most_recently_active_version = EE_System::getMostRecentlyActiveVersion($activation_history);
759
-        return version_compare($current_version, $most_recently_active_version);
760
-    }
761
-
762
-
763
-    /**
764
-     * Gets the most recently active version listed in the activation history,
765
-     * and if none are found (ie, it's a brand new install) returns '0.0.0.dev.000'.
766
-     *
767
-     * @param array|null $activation_history (keys are versions, values are arrays of times activated,
768
-     *                                       sometimes containing 'unknown-date'
769
-     * @return string
770
-     */
771
-    private static function getMostRecentlyActiveVersion(?array $activation_history): string
772
-    {
773
-        $most_recent_activation_date  = '1970-01-01 00:00:00';
774
-        $most_recently_active_version = '0.0.0.dev.000';
775
-        if (is_array($activation_history)) {
776
-            foreach ($activation_history as $version => $activation_dates) {
777
-                // check there is a record of when this version was activated.
778
-                // Otherwise, mark it as unknown
779
-                if (! $activation_dates) {
780
-                    $activation_dates = ['unknown-date'];
781
-                }
782
-                $activation_dates = is_string($activation_dates)
783
-                    ? [$activation_dates]
784
-                    : $activation_dates;
785
-                foreach ($activation_dates as $activation_date) {
786
-                    if ($activation_date !== 'unknown-date' && $activation_date > $most_recent_activation_date) {
787
-                        $most_recently_active_version = $version;
788
-                        $most_recent_activation_date  = $activation_date;
789
-                    }
790
-                }
791
-            }
792
-        }
793
-        return $most_recently_active_version;
794
-    }
795
-
796
-
797
-    /**
798
-     * This redirects to the about EE page after activation
799
-     *
800
-     * @return void
801
-     */
802
-    public function redirect_to_about_ee()
803
-    {
804
-        $notices = EE_Error::get_notices(false);
805
-        // if current user is an admin and it's not an ajax or rest request
806
-        if (
807
-            ! isset($notices['errors'])
808
-            && $this->request->isAdmin()
809
-            && apply_filters(
810
-                'FHEE__EE_System__redirect_to_about_ee__do_redirect',
811
-                $this->capabilities->current_user_can('manage_options', 'espresso_about_default')
812
-            )
813
-        ) {
814
-            $query_params = ['page' => 'espresso_about'];
815
-            if (EE_System::instance()->detect_req_type() === EE_System::req_type_new_activation) {
816
-                $query_params['new_activation'] = true;
817
-            }
818
-            if (EE_System::instance()->detect_req_type() === EE_System::req_type_reactivation) {
819
-                $query_params['reactivation'] = true;
820
-            }
821
-            $url = add_query_arg($query_params, admin_url('admin.php'));
822
-            EEH_URL::safeRedirectAndExit($url);
823
-        }
824
-    }
825
-
826
-
827
-    /**
828
-     * load_core_configuration
829
-     * this is hooked into 'AHEE__EE_Bootstrap__load_core_configuration'
830
-     * which runs during the WP 'plugins_loaded' action at priority 5
831
-     *
832
-     * @return void
833
-     * @throws ReflectionException
834
-     * @throws Exception
835
-     */
836
-    public function load_core_configuration()
837
-    {
838
-        do_action('AHEE__EE_System__load_core_configuration__begin', $this);
839
-        $this->loader->getShared('EE_Load_Textdomain');
840
-        // load textdomain
841
-        EE_Load_Textdomain::load_textdomain();
842
-        // load and setup EE_Config and EE_Network_Config
843
-        $config = $this->loader->getShared('EE_Config');
844
-        $this->loader->getShared('EE_Network_Config');
845
-        // setup autoloaders
846
-        // enable logging?
847
-        $this->loader->getShared('EventEspresso\core\services\orm\TrashLogger');
848
-        if ($config->admin->use_remote_logging) {
849
-            $this->loader->getShared('EE_Log');
850
-        }
851
-        // check for activation errors
852
-        $activation_errors = get_option('ee_plugin_activation_errors', false);
853
-        if ($activation_errors) {
854
-            EE_Error::add_error($activation_errors, __FILE__, __FUNCTION__, __LINE__);
855
-            update_option('ee_plugin_activation_errors', false);
856
-        }
857
-        // get model names
858
-        $this->_parse_model_names();
859
-        // configure custom post type definitions
860
-        $this->loader->getShared('EventEspresso\core\domain\entities\custom_post_types\CustomTaxonomyDefinitions');
861
-        $this->loader->getShared('EventEspresso\core\domain\entities\custom_post_types\CustomPostTypeDefinitions');
862
-        do_action('AHEE__EE_System__load_core_configuration__complete', $this);
863
-    }
864
-
865
-
866
-    /**
867
-     * cycles through all of the models/*.model.php files, and assembles an array of model names
868
-     *
869
-     * @return void
870
-     * @throws ReflectionException
871
-     */
872
-    private function _parse_model_names()
873
-    {
874
-        // get all the files in the EE_MODELS folder that end in .model.php
875
-        $models                 = glob(EE_MODELS . '*.model.php');
876
-        $model_names            = [];
877
-        $non_abstract_db_models = [];
878
-        foreach ($models as $model) {
879
-            // get model classname
880
-            $classname       = EEH_File::get_classname_from_filepath_with_standard_filename($model);
881
-            $short_name      = str_replace('EEM_', '', $classname);
882
-            $reflectionClass = new ReflectionClass($classname);
883
-            if ($reflectionClass->isSubclassOf('EEM_Base') && ! $reflectionClass->isAbstract()) {
884
-                $non_abstract_db_models[ $short_name ] = $classname;
885
-            }
886
-            $model_names[ $short_name ] = $classname;
887
-        }
888
-        $this->registry->models                 = apply_filters('FHEE__EE_System__parse_model_names', $model_names);
889
-        $this->registry->non_abstract_db_models = apply_filters(
890
-            'FHEE__EE_System__parse_implemented_model_names',
891
-            $non_abstract_db_models
892
-        );
893
-    }
894
-
895
-
896
-    /**
897
-     * @throws Exception
898
-     * @since 4.9.71.p
899
-     */
900
-    public function loadRouteMatchSpecifications()
901
-    {
902
-        try {
903
-            $this->loader->getShared('EventEspresso\core\services\routing\RouteMatchSpecificationManager');
904
-            $this->loader->getShared('EventEspresso\core\services\routing\RouteCollection');
905
-            $this->router->loadPrimaryRoutes();
906
-        } catch (Exception $exception) {
907
-            new ExceptionStackTraceDisplay($exception);
908
-        }
909
-        do_action('AHEE__EE_System__loadRouteMatchSpecifications');
910
-    }
911
-
912
-
913
-    /**
914
-     * loading CPT related classes earlier so that their definitions are available
915
-     * but not performing any actual registration with WP core until load_CPTs_and_session() is called
916
-     *
917
-     * @since   4.10.21.p
918
-     */
919
-    public function loadCustomPostTypes()
920
-    {
921
-        $this->register_custom_taxonomies     = $this->loader->getShared(
922
-            'EventEspresso\core\domain\services\custom_post_types\RegisterCustomTaxonomies'
923
-        );
924
-        $this->register_custom_post_types     = $this->loader->getShared(
925
-            'EventEspresso\core\domain\services\custom_post_types\RegisterCustomPostTypes'
926
-        );
927
-        $this->register_custom_taxonomy_terms = $this->loader->getShared(
928
-            'EventEspresso\core\domain\services\custom_post_types\RegisterCustomTaxonomyTerms'
929
-        );
930
-        // integrate WP_Query with the EE models
931
-        $this->loader->getShared('EE_CPT_Strategy');
932
-        // load legacy EE_Request_Handler in case add-ons still need it
933
-        $this->loader->getShared('EE_Request_Handler');
934
-    }
935
-
936
-
937
-    /**
938
-     * register_shortcodes_modules_and_widgets
939
-     * generate lists of shortcodes and modules, then verify paths and classes
940
-     * This is hooked into 'AHEE__EE_Bootstrap__register_shortcodes_modules_and_widgets'
941
-     * which runs during the WP 'plugins_loaded' action at priority 7
942
-     *
943
-     * @access public
944
-     * @return void
945
-     * @throws Exception
946
-     */
947
-    public function register_shortcodes_modules_and_widgets()
948
-    {
949
-        $this->router->registerShortcodesModulesAndWidgets();
950
-        do_action('AHEE__EE_System__register_shortcodes_modules_and_widgets');
951
-        // check for addons using old hook point
952
-        if (has_action('AHEE__EE_System__register_shortcodes_modules_and_addons')) {
953
-            $this->_incompatible_addon_error();
954
-        }
955
-    }
956
-
957
-
958
-    /**
959
-     * _incompatible_addon_error
960
-     *
961
-     * @access public
962
-     * @return void
963
-     */
964
-    private function _incompatible_addon_error()
965
-    {
966
-        // get array of classes hooking into here
967
-        $class_names = WordPressHooks::getClassNamesForAllCallbacksOnHook(
968
-            'AHEE__EE_System__register_shortcodes_modules_and_addons'
969
-        );
970
-        if (! empty($class_names)) {
971
-            $msg = esc_html__(
972
-                'The following plugins, addons, or modules appear to be incompatible with this version of Event Espresso and were automatically deactivated to avoid fatal errors:',
973
-                'event_espresso'
974
-            );
975
-            $msg .= '<ul>';
976
-            foreach ($class_names as $class_name) {
977
-                $msg .= '<li><b>Event Espresso - '
978
-                        . str_replace(
979
-                            ['EE_', 'EEM_', 'EED_', 'EES_', 'EEW_'],
980
-                            '',
981
-                            $class_name
982
-                        ) . '</b></li>';
983
-            }
984
-            $msg .= '</ul>';
985
-            $msg .= esc_html__(
986
-                'Compatibility issues can be avoided and/or resolved by keeping addons and plugins updated to the latest version.',
987
-                'event_espresso'
988
-            );
989
-            // save list of incompatible addons to wp-options for later use
990
-            add_option('ee_incompatible_addons', $class_names, '', 'no');
991
-            if (is_admin()) {
992
-                EE_Error::add_error($msg, __FILE__, __FUNCTION__, __LINE__);
993
-            }
994
-        }
995
-    }
996
-
997
-
998
-    /**
999
-     * brew_espresso
1000
-     * begins the process of setting hooks for initializing EE in the correct order
1001
-     * This is happening on the 'AHEE__EE_Bootstrap__brew_espresso' hook point
1002
-     * which runs during the WP 'plugins_loaded' action at priority 9
1003
-     *
1004
-     * @return void
1005
-     * @throws Exception
1006
-     */
1007
-    public function brew_espresso()
1008
-    {
1009
-        do_action('AHEE__EE_System__brew_espresso__begin', $this);
1010
-        // load some final core systems
1011
-        add_action('init', [$this, 'set_hooks_for_core'], 1);
1012
-        add_action('init', [$this, 'perform_activations_upgrades_and_migrations'], 3);
1013
-        add_action('init', [$this, 'load_CPTs_and_session'], 5);
1014
-        add_action('init', [$this, 'load_controllers'], 7);
1015
-        add_action('init', [$this, 'core_loaded_and_ready'], 9);
1016
-        add_action('init', [$this, 'initialize'], 10);
1017
-        add_action('init', [$this, 'initialize_last'], 100);
1018
-        $this->router->brewEspresso();
1019
-        $this->loader->getShared('EventEspresso\PaymentMethods\Manager');
1020
-        $this->loader->getShared('EE_Payment_Method_Manager');
1021
-        do_action('AHEE__EE_System__brew_espresso__complete', $this);
1022
-    }
1023
-
1024
-
1025
-    /**
1026
-    /**
1027
-     *    set_hooks_for_core
1028
-     *
1029
-     * @access public
1030
-     * @return    void
1031
-     * @throws EE_Error
1032
-     */
1033
-    public function set_hooks_for_core()
1034
-    {
1035
-        $this->_deactivate_incompatible_addons();
1036
-        do_action('AHEE__EE_System__set_hooks_for_core');
1037
-        $this->loader->getShared('EventEspresso\core\domain\values\session\SessionLifespan');
1038
-        // caps need to be initialized on every request so that capability maps are set.
1039
-        // @see https://events.codebasehq.com/projects/event-espresso/tickets/8674
1040
-        $this->capabilities->init_caps();
1041
-    }
1042
-
1043
-
1044
-    /**
1045
-     * Using the information gathered in EE_System::_incompatible_addon_error,
1046
-     * deactivates any addons considered incompatible with the current version of EE
1047
-     */
1048
-    private function _deactivate_incompatible_addons()
1049
-    {
1050
-        $incompatible_addons = get_option('ee_incompatible_addons', []);
1051
-        if (! empty($incompatible_addons)) {
1052
-            $active_plugins = get_option('active_plugins', []);
1053
-            foreach ($active_plugins as $active_plugin) {
1054
-                foreach ($incompatible_addons as $incompatible_addon) {
1055
-                    if (strpos($active_plugin, $incompatible_addon) !== false) {
1056
-                        $this->request->unSetRequestParams(['activate'], true);
1057
-                        espresso_deactivate_plugin($active_plugin);
1058
-                    }
1059
-                }
1060
-            }
1061
-        }
1062
-    }
1063
-
1064
-
1065
-    /**
1066
-     *    perform_activations_upgrades_and_migrations
1067
-     *
1068
-     * @access public
1069
-     * @return    void
1070
-     */
1071
-    public function perform_activations_upgrades_and_migrations()
1072
-    {
1073
-        do_action('AHEE__EE_System__perform_activations_upgrades_and_migrations');
1074
-    }
1075
-
1076
-
1077
-    /**
1078
-     * @return void
1079
-     * @throws DomainException
1080
-     */
1081
-    public function load_CPTs_and_session()
1082
-    {
1083
-        do_action('AHEE__EE_System__load_CPTs_and_session__start');
1084
-        $this->register_custom_taxonomies->registerCustomTaxonomies();
1085
-        $this->register_custom_post_types->registerCustomPostTypes();
1086
-        $this->register_custom_taxonomy_terms->registerCustomTaxonomyTerms();
1087
-        do_action('AHEE__EE_System__load_CPTs_and_session__complete');
1088
-    }
1089
-
1090
-
1091
-    /**
1092
-     * load_controllers
1093
-     * this is the best place to load any additional controllers that needs access to EE core.
1094
-     * it is expected that all basic core EE systems, that are not dependant on the current request are loaded at this
1095
-     * time
1096
-     *
1097
-     * @access public
1098
-     * @return void
1099
-     * @throws Exception
1100
-     */
1101
-    public function load_controllers()
1102
-    {
1103
-        do_action('AHEE__EE_System__load_controllers__start');
1104
-        $this->router->loadControllers();
1105
-        do_action('AHEE__EE_System__load_controllers__complete');
1106
-    }
1107
-
1108
-
1109
-    /**
1110
-     * core_loaded_and_ready
1111
-     * all of the basic EE core should be loaded at this point and available regardless of M-Mode
1112
-     *
1113
-     * @access public
1114
-     * @return void
1115
-     * @throws Exception
1116
-     */
1117
-    public function core_loaded_and_ready()
1118
-    {
1119
-        $this->router->coreLoadedAndReady();
1120
-        do_action('AHEE__EE_System__core_loaded_and_ready');
1121
-        // always load template tags, because it's faster than checking if it's a front-end request, and many page
1122
-        // builders require these even on the front-end
1123
-        require_once EE_PUBLIC . 'template_tags.php';
1124
-        do_action('AHEE__EE_System__set_hooks_for_shortcodes_modules_and_addons');
1125
-    }
1126
-
1127
-
1128
-    /**
1129
-     * initialize
1130
-     * this is the best place to begin initializing client code
1131
-     *
1132
-     * @access public
1133
-     * @return void
1134
-     */
1135
-    public function initialize()
1136
-    {
1137
-        do_action('AHEE__EE_System__initialize');
1138
-        add_filter(
1139
-            'safe_style_css',
1140
-            function ($styles) {
1141
-                $styles[] = 'display';
1142
-                $styles[] = 'visibility';
1143
-                $styles[] = 'position';
1144
-                $styles[] = 'top';
1145
-                $styles[] = 'right';
1146
-                $styles[] = 'bottom';
1147
-                $styles[] = 'left';
1148
-                $styles[] = 'resize';
1149
-                $styles[] = 'max-width';
1150
-                $styles[] = 'max-height';
1151
-                return $styles;
1152
-            }
1153
-        );
1154
-    }
1155
-
1156
-
1157
-    /**
1158
-     * initialize_last
1159
-     * this is run really late during the WP init hook point, and ensures that mostly everything else that needs to
1160
-     * initialize has done so
1161
-     *
1162
-     * @access public
1163
-     * @return void
1164
-     * @throws Exception
1165
-     */
1166
-    public function initialize_last()
1167
-    {
1168
-        $this->router->initializeLast();
1169
-        do_action('AHEE__EE_System__initialize_last');
1170
-        /** @var EventEspresso\core\domain\services\custom_post_types\RewriteRules $rewrite_rules */
1171
-        $rewrite_rules = $this->loader->getShared(
1172
-            'EventEspresso\core\domain\services\custom_post_types\RewriteRules'
1173
-        );
1174
-        $rewrite_rules->flushRewriteRules();
1175
-        add_action('admin_bar_init', [$this, 'addEspressoToolbar']);
1176
-    }
1177
-
1178
-
1179
-    /**
1180
-     * @return void
1181
-     */
1182
-    public function addEspressoToolbar()
1183
-    {
1184
-        $this->loader->getShared(
1185
-            'EventEspresso\core\domain\services\admin\AdminToolBar',
1186
-            [$this->capabilities]
1187
-        );
1188
-    }
1189
-
1190
-
1191
-    /**
1192
-     * do_not_cache
1193
-     * sets no cache headers and defines no cache constants for WP plugins
1194
-     *
1195
-     * @access public
1196
-     * @return void
1197
-     */
1198
-    public static function do_not_cache()
1199
-    {
1200
-        // set no cache constants
1201
-        if (! defined('DONOTCACHEPAGE')) {
1202
-            define('DONOTCACHEPAGE', true);
1203
-        }
1204
-        if (! defined('DONOTCACHCEOBJECT')) {
1205
-            define('DONOTCACHCEOBJECT', true);
1206
-        }
1207
-        if (! defined('DONOTCACHEDB')) {
1208
-            define('DONOTCACHEDB', true);
1209
-        }
1210
-        // add no cache headers
1211
-        add_action('send_headers', ['EE_System', 'nocache_headers'], 10);
1212
-        // plus a little extra for nginx and Google Chrome
1213
-        add_filter('nocache_headers', ['EE_System', 'extra_nocache_headers'], 10, 1);
1214
-        // prevent browsers from prefetching of the rel='next' link, because it may contain content that interferes with the registration process
1215
-        remove_action('wp_head', 'adjacent_posts_rel_link_wp_head');
1216
-    }
1217
-
1218
-
1219
-    /**
1220
-     *    extra_nocache_headers
1221
-     *
1222
-     * @access    public
1223
-     * @param $headers
1224
-     * @return    array
1225
-     */
1226
-    public static function extra_nocache_headers($headers): array
1227
-    {
1228
-        // for NGINX
1229
-        $headers['X-Accel-Expires'] = 0;
1230
-        // plus extra for Google Chrome since it doesn't seem to respect "no-cache", but WILL respect "no-store"
1231
-        $headers['Cache-Control'] = 'no-store, no-cache, must-revalidate, max-age=0';
1232
-        return $headers;
1233
-    }
1234
-
1235
-
1236
-    /**
1237
-     *    nocache_headers
1238
-     *
1239
-     * @access    public
1240
-     * @return    void
1241
-     */
1242
-    public static function nocache_headers()
1243
-    {
1244
-        nocache_headers();
1245
-    }
1246
-
1247
-
1248
-    /**
1249
-     * simply hooks into "wp_list_pages_exclude" filter (for wp_list_pages method) and makes sure EE critical pages are
1250
-     * never returned with the function.
1251
-     *
1252
-     * @param array $exclude_array any existing pages being excluded are in this array.
1253
-     * @return array
1254
-     */
1255
-    public function remove_pages_from_wp_list_pages(array $exclude_array): array
1256
-    {
1257
-        return array_merge($exclude_array, $this->registry->CFG->core->get_critical_pages_array());
1258
-    }
1027
+	 *    set_hooks_for_core
1028
+	 *
1029
+	 * @access public
1030
+	 * @return    void
1031
+	 * @throws EE_Error
1032
+	 */
1033
+	public function set_hooks_for_core()
1034
+	{
1035
+		$this->_deactivate_incompatible_addons();
1036
+		do_action('AHEE__EE_System__set_hooks_for_core');
1037
+		$this->loader->getShared('EventEspresso\core\domain\values\session\SessionLifespan');
1038
+		// caps need to be initialized on every request so that capability maps are set.
1039
+		// @see https://events.codebasehq.com/projects/event-espresso/tickets/8674
1040
+		$this->capabilities->init_caps();
1041
+	}
1042
+
1043
+
1044
+	/**
1045
+	 * Using the information gathered in EE_System::_incompatible_addon_error,
1046
+	 * deactivates any addons considered incompatible with the current version of EE
1047
+	 */
1048
+	private function _deactivate_incompatible_addons()
1049
+	{
1050
+		$incompatible_addons = get_option('ee_incompatible_addons', []);
1051
+		if (! empty($incompatible_addons)) {
1052
+			$active_plugins = get_option('active_plugins', []);
1053
+			foreach ($active_plugins as $active_plugin) {
1054
+				foreach ($incompatible_addons as $incompatible_addon) {
1055
+					if (strpos($active_plugin, $incompatible_addon) !== false) {
1056
+						$this->request->unSetRequestParams(['activate'], true);
1057
+						espresso_deactivate_plugin($active_plugin);
1058
+					}
1059
+				}
1060
+			}
1061
+		}
1062
+	}
1063
+
1064
+
1065
+	/**
1066
+	 *    perform_activations_upgrades_and_migrations
1067
+	 *
1068
+	 * @access public
1069
+	 * @return    void
1070
+	 */
1071
+	public function perform_activations_upgrades_and_migrations()
1072
+	{
1073
+		do_action('AHEE__EE_System__perform_activations_upgrades_and_migrations');
1074
+	}
1075
+
1076
+
1077
+	/**
1078
+	 * @return void
1079
+	 * @throws DomainException
1080
+	 */
1081
+	public function load_CPTs_and_session()
1082
+	{
1083
+		do_action('AHEE__EE_System__load_CPTs_and_session__start');
1084
+		$this->register_custom_taxonomies->registerCustomTaxonomies();
1085
+		$this->register_custom_post_types->registerCustomPostTypes();
1086
+		$this->register_custom_taxonomy_terms->registerCustomTaxonomyTerms();
1087
+		do_action('AHEE__EE_System__load_CPTs_and_session__complete');
1088
+	}
1089
+
1090
+
1091
+	/**
1092
+	 * load_controllers
1093
+	 * this is the best place to load any additional controllers that needs access to EE core.
1094
+	 * it is expected that all basic core EE systems, that are not dependant on the current request are loaded at this
1095
+	 * time
1096
+	 *
1097
+	 * @access public
1098
+	 * @return void
1099
+	 * @throws Exception
1100
+	 */
1101
+	public function load_controllers()
1102
+	{
1103
+		do_action('AHEE__EE_System__load_controllers__start');
1104
+		$this->router->loadControllers();
1105
+		do_action('AHEE__EE_System__load_controllers__complete');
1106
+	}
1107
+
1108
+
1109
+	/**
1110
+	 * core_loaded_and_ready
1111
+	 * all of the basic EE core should be loaded at this point and available regardless of M-Mode
1112
+	 *
1113
+	 * @access public
1114
+	 * @return void
1115
+	 * @throws Exception
1116
+	 */
1117
+	public function core_loaded_and_ready()
1118
+	{
1119
+		$this->router->coreLoadedAndReady();
1120
+		do_action('AHEE__EE_System__core_loaded_and_ready');
1121
+		// always load template tags, because it's faster than checking if it's a front-end request, and many page
1122
+		// builders require these even on the front-end
1123
+		require_once EE_PUBLIC . 'template_tags.php';
1124
+		do_action('AHEE__EE_System__set_hooks_for_shortcodes_modules_and_addons');
1125
+	}
1126
+
1127
+
1128
+	/**
1129
+	 * initialize
1130
+	 * this is the best place to begin initializing client code
1131
+	 *
1132
+	 * @access public
1133
+	 * @return void
1134
+	 */
1135
+	public function initialize()
1136
+	{
1137
+		do_action('AHEE__EE_System__initialize');
1138
+		add_filter(
1139
+			'safe_style_css',
1140
+			function ($styles) {
1141
+				$styles[] = 'display';
1142
+				$styles[] = 'visibility';
1143
+				$styles[] = 'position';
1144
+				$styles[] = 'top';
1145
+				$styles[] = 'right';
1146
+				$styles[] = 'bottom';
1147
+				$styles[] = 'left';
1148
+				$styles[] = 'resize';
1149
+				$styles[] = 'max-width';
1150
+				$styles[] = 'max-height';
1151
+				return $styles;
1152
+			}
1153
+		);
1154
+	}
1155
+
1156
+
1157
+	/**
1158
+	 * initialize_last
1159
+	 * this is run really late during the WP init hook point, and ensures that mostly everything else that needs to
1160
+	 * initialize has done so
1161
+	 *
1162
+	 * @access public
1163
+	 * @return void
1164
+	 * @throws Exception
1165
+	 */
1166
+	public function initialize_last()
1167
+	{
1168
+		$this->router->initializeLast();
1169
+		do_action('AHEE__EE_System__initialize_last');
1170
+		/** @var EventEspresso\core\domain\services\custom_post_types\RewriteRules $rewrite_rules */
1171
+		$rewrite_rules = $this->loader->getShared(
1172
+			'EventEspresso\core\domain\services\custom_post_types\RewriteRules'
1173
+		);
1174
+		$rewrite_rules->flushRewriteRules();
1175
+		add_action('admin_bar_init', [$this, 'addEspressoToolbar']);
1176
+	}
1177
+
1178
+
1179
+	/**
1180
+	 * @return void
1181
+	 */
1182
+	public function addEspressoToolbar()
1183
+	{
1184
+		$this->loader->getShared(
1185
+			'EventEspresso\core\domain\services\admin\AdminToolBar',
1186
+			[$this->capabilities]
1187
+		);
1188
+	}
1189
+
1190
+
1191
+	/**
1192
+	 * do_not_cache
1193
+	 * sets no cache headers and defines no cache constants for WP plugins
1194
+	 *
1195
+	 * @access public
1196
+	 * @return void
1197
+	 */
1198
+	public static function do_not_cache()
1199
+	{
1200
+		// set no cache constants
1201
+		if (! defined('DONOTCACHEPAGE')) {
1202
+			define('DONOTCACHEPAGE', true);
1203
+		}
1204
+		if (! defined('DONOTCACHCEOBJECT')) {
1205
+			define('DONOTCACHCEOBJECT', true);
1206
+		}
1207
+		if (! defined('DONOTCACHEDB')) {
1208
+			define('DONOTCACHEDB', true);
1209
+		}
1210
+		// add no cache headers
1211
+		add_action('send_headers', ['EE_System', 'nocache_headers'], 10);
1212
+		// plus a little extra for nginx and Google Chrome
1213
+		add_filter('nocache_headers', ['EE_System', 'extra_nocache_headers'], 10, 1);
1214
+		// prevent browsers from prefetching of the rel='next' link, because it may contain content that interferes with the registration process
1215
+		remove_action('wp_head', 'adjacent_posts_rel_link_wp_head');
1216
+	}
1217
+
1218
+
1219
+	/**
1220
+	 *    extra_nocache_headers
1221
+	 *
1222
+	 * @access    public
1223
+	 * @param $headers
1224
+	 * @return    array
1225
+	 */
1226
+	public static function extra_nocache_headers($headers): array
1227
+	{
1228
+		// for NGINX
1229
+		$headers['X-Accel-Expires'] = 0;
1230
+		// plus extra for Google Chrome since it doesn't seem to respect "no-cache", but WILL respect "no-store"
1231
+		$headers['Cache-Control'] = 'no-store, no-cache, must-revalidate, max-age=0';
1232
+		return $headers;
1233
+	}
1234
+
1235
+
1236
+	/**
1237
+	 *    nocache_headers
1238
+	 *
1239
+	 * @access    public
1240
+	 * @return    void
1241
+	 */
1242
+	public static function nocache_headers()
1243
+	{
1244
+		nocache_headers();
1245
+	}
1246
+
1247
+
1248
+	/**
1249
+	 * simply hooks into "wp_list_pages_exclude" filter (for wp_list_pages method) and makes sure EE critical pages are
1250
+	 * never returned with the function.
1251
+	 *
1252
+	 * @param array $exclude_array any existing pages being excluded are in this array.
1253
+	 * @return array
1254
+	 */
1255
+	public function remove_pages_from_wp_list_pages(array $exclude_array): array
1256
+	{
1257
+		return array_merge($exclude_array, $this->registry->CFG->core->get_critical_pages_array());
1258
+	}
1259 1259
 }
Please login to merge, or discard this patch.
Spacing   +22 added lines, -22 removed lines patch added patch discarded remove patch
@@ -131,7 +131,7 @@  discard block
 block discarded – undo
131 131
         ?FeatureFlags $feature = null
132 132
     ): EE_System {
133 133
         // check if class object is instantiated
134
-        if (! self::$_instance instanceof EE_System) {
134
+        if ( ! self::$_instance instanceof EE_System) {
135 135
             self::$_instance = new self($loader, $maintenance_mode, $registry, $request, $router, $feature);
136 136
         }
137 137
         return self::$_instance;
@@ -350,10 +350,10 @@  discard block
 block discarded – undo
350 350
         /** @var Domain $domain */
351 351
         $domain = DomainFactory::getEventEspressoCoreDomain();
352 352
         if ($domain->isCaffeinated() && ! $brew instanceof EE_Brewing_Regular) {
353
-            require_once EE_CAFF_PATH . 'brewing_regular.php';
353
+            require_once EE_CAFF_PATH.'brewing_regular.php';
354 354
             /** @var EE_Brewing_Regular $brew */
355 355
             $brew = LoaderFactory::getLoader()->getShared(EE_Brewing_Regular::class);
356
-            if (! $this->feature->allowed('use_edd_plugin_licensing')) {
356
+            if ( ! $this->feature->allowed('use_edd_plugin_licensing')) {
357 357
                 $brew->initializePUE();
358 358
             }
359 359
             add_action(
@@ -487,11 +487,11 @@  discard block
 block discarded – undo
487 487
     private function fix_espresso_db_upgrade_option($espresso_db_update = null): array
488 488
     {
489 489
         do_action('FHEE__EE_System__manage_fix_espresso_db_upgrade_option__begin', $espresso_db_update);
490
-        if (! $espresso_db_update) {
490
+        if ( ! $espresso_db_update) {
491 491
             $espresso_db_update = get_option('espresso_db_update');
492 492
         }
493 493
         // check that option is an array
494
-        if (! is_array($espresso_db_update)) {
494
+        if ( ! is_array($espresso_db_update)) {
495 495
             // if option is FALSE, then it never existed
496 496
             if ($espresso_db_update === false) {
497 497
                 // make $espresso_db_update an array and save option with autoload OFF
@@ -511,10 +511,10 @@  discard block
 block discarded – undo
511 511
                     // so it must be numerically-indexed, where values are versions installed...
512 512
                     // fix it!
513 513
                     $version_string                         = $should_be_array;
514
-                    $corrected_db_update[ $version_string ] = ['unknown-date'];
514
+                    $corrected_db_update[$version_string] = ['unknown-date'];
515 515
                 } else {
516 516
                     // ok it checks out
517
-                    $corrected_db_update[ $should_be_version_string ] = $should_be_array;
517
+                    $corrected_db_update[$should_be_version_string] = $should_be_array;
518 518
                 }
519 519
             }
520 520
             $espresso_db_update = $corrected_db_update;
@@ -546,7 +546,7 @@  discard block
 block discarded – undo
546 546
     {
547 547
         $request_type = $this->detect_req_type();
548 548
         // only initialize system if we're not in maintenance mode.
549
-        if (! MaintenanceStatus::isFullSite()) {
549
+        if ( ! MaintenanceStatus::isFullSite()) {
550 550
             /** @var EventEspresso\core\domain\services\custom_post_types\RewriteRules $rewrite_rules */
551 551
             $rewrite_rules = $this->loader->getShared(
552 552
                 'EventEspresso\core\domain\services\custom_post_types\RewriteRules'
@@ -602,13 +602,13 @@  discard block
 block discarded – undo
602 602
      */
603 603
     public function update_list_of_installed_versions($version_history = null, $current_version_to_add = null): bool
604 604
     {
605
-        if (! $version_history) {
605
+        if ( ! $version_history) {
606 606
             $version_history = $this->fix_espresso_db_upgrade_option($version_history);
607 607
         }
608 608
         if ($current_version_to_add === null) {
609 609
             $current_version_to_add = espresso_version();
610 610
         }
611
-        $version_history[ $current_version_to_add ][] = date('Y-m-d H:i:s', time());
611
+        $version_history[$current_version_to_add][] = date('Y-m-d H:i:s', time());
612 612
         // re-save
613 613
         return update_option('espresso_db_update', $version_history);
614 614
     }
@@ -776,7 +776,7 @@  discard block
 block discarded – undo
776 776
             foreach ($activation_history as $version => $activation_dates) {
777 777
                 // check there is a record of when this version was activated.
778 778
                 // Otherwise, mark it as unknown
779
-                if (! $activation_dates) {
779
+                if ( ! $activation_dates) {
780 780
                     $activation_dates = ['unknown-date'];
781 781
                 }
782 782
                 $activation_dates = is_string($activation_dates)
@@ -872,7 +872,7 @@  discard block
 block discarded – undo
872 872
     private function _parse_model_names()
873 873
     {
874 874
         // get all the files in the EE_MODELS folder that end in .model.php
875
-        $models                 = glob(EE_MODELS . '*.model.php');
875
+        $models                 = glob(EE_MODELS.'*.model.php');
876 876
         $model_names            = [];
877 877
         $non_abstract_db_models = [];
878 878
         foreach ($models as $model) {
@@ -881,9 +881,9 @@  discard block
 block discarded – undo
881 881
             $short_name      = str_replace('EEM_', '', $classname);
882 882
             $reflectionClass = new ReflectionClass($classname);
883 883
             if ($reflectionClass->isSubclassOf('EEM_Base') && ! $reflectionClass->isAbstract()) {
884
-                $non_abstract_db_models[ $short_name ] = $classname;
884
+                $non_abstract_db_models[$short_name] = $classname;
885 885
             }
886
-            $model_names[ $short_name ] = $classname;
886
+            $model_names[$short_name] = $classname;
887 887
         }
888 888
         $this->registry->models                 = apply_filters('FHEE__EE_System__parse_model_names', $model_names);
889 889
         $this->registry->non_abstract_db_models = apply_filters(
@@ -967,7 +967,7 @@  discard block
 block discarded – undo
967 967
         $class_names = WordPressHooks::getClassNamesForAllCallbacksOnHook(
968 968
             'AHEE__EE_System__register_shortcodes_modules_and_addons'
969 969
         );
970
-        if (! empty($class_names)) {
970
+        if ( ! empty($class_names)) {
971 971
             $msg = esc_html__(
972 972
                 'The following plugins, addons, or modules appear to be incompatible with this version of Event Espresso and were automatically deactivated to avoid fatal errors:',
973 973
                 'event_espresso'
@@ -979,7 +979,7 @@  discard block
 block discarded – undo
979 979
                             ['EE_', 'EEM_', 'EED_', 'EES_', 'EEW_'],
980 980
                             '',
981 981
                             $class_name
982
-                        ) . '</b></li>';
982
+                        ).'</b></li>';
983 983
             }
984 984
             $msg .= '</ul>';
985 985
             $msg .= esc_html__(
@@ -1048,7 +1048,7 @@  discard block
 block discarded – undo
1048 1048
     private function _deactivate_incompatible_addons()
1049 1049
     {
1050 1050
         $incompatible_addons = get_option('ee_incompatible_addons', []);
1051
-        if (! empty($incompatible_addons)) {
1051
+        if ( ! empty($incompatible_addons)) {
1052 1052
             $active_plugins = get_option('active_plugins', []);
1053 1053
             foreach ($active_plugins as $active_plugin) {
1054 1054
                 foreach ($incompatible_addons as $incompatible_addon) {
@@ -1120,7 +1120,7 @@  discard block
 block discarded – undo
1120 1120
         do_action('AHEE__EE_System__core_loaded_and_ready');
1121 1121
         // always load template tags, because it's faster than checking if it's a front-end request, and many page
1122 1122
         // builders require these even on the front-end
1123
-        require_once EE_PUBLIC . 'template_tags.php';
1123
+        require_once EE_PUBLIC.'template_tags.php';
1124 1124
         do_action('AHEE__EE_System__set_hooks_for_shortcodes_modules_and_addons');
1125 1125
     }
1126 1126
 
@@ -1137,7 +1137,7 @@  discard block
 block discarded – undo
1137 1137
         do_action('AHEE__EE_System__initialize');
1138 1138
         add_filter(
1139 1139
             'safe_style_css',
1140
-            function ($styles) {
1140
+            function($styles) {
1141 1141
                 $styles[] = 'display';
1142 1142
                 $styles[] = 'visibility';
1143 1143
                 $styles[] = 'position';
@@ -1198,13 +1198,13 @@  discard block
 block discarded – undo
1198 1198
     public static function do_not_cache()
1199 1199
     {
1200 1200
         // set no cache constants
1201
-        if (! defined('DONOTCACHEPAGE')) {
1201
+        if ( ! defined('DONOTCACHEPAGE')) {
1202 1202
             define('DONOTCACHEPAGE', true);
1203 1203
         }
1204
-        if (! defined('DONOTCACHCEOBJECT')) {
1204
+        if ( ! defined('DONOTCACHCEOBJECT')) {
1205 1205
             define('DONOTCACHCEOBJECT', true);
1206 1206
         }
1207
-        if (! defined('DONOTCACHEDB')) {
1207
+        if ( ! defined('DONOTCACHEDB')) {
1208 1208
             define('DONOTCACHEDB', true);
1209 1209
         }
1210 1210
         // add no cache headers
Please login to merge, or discard this patch.
core/EE_Dependency_Map.core.php 1 patch
Indentation   +1160 added lines, -1160 removed lines patch added patch discarded remove patch
@@ -20,1164 +20,1164 @@
 block discarded – undo
20 20
  */
21 21
 class EE_Dependency_Map
22 22
 {
23
-    /**
24
-     * This means that the requested class dependency is not present in the dependency map
25
-     */
26
-    const not_registered = 0;
27
-
28
-    /**
29
-     * This instructs class loaders to ALWAYS return a newly instantiated object for the requested class.
30
-     */
31
-    const load_new_object = 1;
32
-
33
-    /**
34
-     * This instructs class loaders to return a previously instantiated and cached object for the requested class.
35
-     * IF a previously instantiated object does not exist, a new one will be created and added to the cache.
36
-     */
37
-    const load_from_cache = 2;
38
-
39
-    /**
40
-     * When registering a dependency,
41
-     * this indicates to keep any existing dependencies that already exist,
42
-     * and simply discard any new dependencies declared in the incoming data
43
-     */
44
-    const KEEP_EXISTING_DEPENDENCIES = 0;
45
-
46
-    /**
47
-     * When registering a dependency,
48
-     * this indicates to overwrite any existing dependencies that already exist using the incoming data
49
-     */
50
-    const OVERWRITE_DEPENDENCIES = 1;
51
-
52
-    protected static ?EE_Dependency_Map $_instance = null;
53
-
54
-    private ClassInterfaceCache $class_cache;
55
-
56
-    protected ?RequestInterface $request = null;
57
-
58
-    protected ?LegacyRequestInterface $legacy_request = null;
59
-
60
-    protected ?ResponseInterface $response = null;
61
-
62
-    protected ?LoaderInterface $loader = null;
63
-
64
-    protected array $_dependency_map = [];
65
-
66
-    protected array $_class_loaders = [];
67
-
68
-
69
-    /**
70
-     * EE_Dependency_Map constructor.
71
-     *
72
-     * @param ClassInterfaceCache $class_cache
73
-     */
74
-    protected function __construct(ClassInterfaceCache $class_cache)
75
-    {
76
-        $this->class_cache = $class_cache;
77
-        do_action('EE_Dependency_Map____construct', $this);
78
-    }
79
-
80
-
81
-    /**
82
-     * @return void
83
-     * @throws InvalidAliasException
84
-     */
85
-    public function initialize()
86
-    {
87
-        $this->_register_core_dependencies();
88
-        $this->_register_core_class_loaders();
89
-        $this->_register_core_aliases();
90
-    }
91
-
92
-
93
-    /**
94
-     * @singleton method used to instantiate class object
95
-     * @param ClassInterfaceCache|null $class_cache
96
-     * @return EE_Dependency_Map
97
-     */
98
-    public static function instance(ClassInterfaceCache $class_cache = null): EE_Dependency_Map
99
-    {
100
-        // check if class object is instantiated, and instantiated properly
101
-        if (
102
-            ! EE_Dependency_Map::$_instance instanceof EE_Dependency_Map
103
-            && $class_cache instanceof ClassInterfaceCache
104
-        ) {
105
-            EE_Dependency_Map::$_instance = new EE_Dependency_Map($class_cache);
106
-        }
107
-        return EE_Dependency_Map::$_instance;
108
-    }
109
-
110
-
111
-    /**
112
-     * @param RequestInterface $request
113
-     */
114
-    public function setRequest(RequestInterface $request)
115
-    {
116
-        $this->request = $request;
117
-    }
118
-
119
-
120
-    /**
121
-     * @param LegacyRequestInterface $legacy_request
122
-     */
123
-    public function setLegacyRequest(LegacyRequestInterface $legacy_request)
124
-    {
125
-        $this->legacy_request = $legacy_request;
126
-    }
127
-
128
-
129
-    /**
130
-     * @param ResponseInterface $response
131
-     */
132
-    public function setResponse(ResponseInterface $response)
133
-    {
134
-        $this->response = $response;
135
-    }
136
-
137
-
138
-    /**
139
-     * @param LoaderInterface $loader
140
-     */
141
-    public function setLoader(LoaderInterface $loader)
142
-    {
143
-        $this->loader = $loader;
144
-    }
145
-
146
-
147
-    /**
148
-     * @param string $class
149
-     * @param array  $dependencies
150
-     * @param int    $overwrite
151
-     * @return bool
152
-     */
153
-    public static function register_dependencies(
154
-        string $class,
155
-        array $dependencies,
156
-        int $overwrite = EE_Dependency_Map::KEEP_EXISTING_DEPENDENCIES
157
-    ): bool {
158
-        return EE_Dependency_Map::$_instance->registerDependencies($class, $dependencies, $overwrite);
159
-    }
160
-
161
-
162
-    /**
163
-     * Assigns an array of class names and corresponding load sources (new or cached)
164
-     * to the class specified by the first parameter.
165
-     * IMPORTANT !!!
166
-     * The order of elements in the incoming $dependencies array MUST match
167
-     * the order of the constructor parameters for the class in question.
168
-     * This is especially important when overriding any existing dependencies that are registered.
169
-     * the third parameter controls whether any duplicate dependencies are overwritten or not.
170
-     *
171
-     * @param string $class
172
-     * @param array  $dependencies
173
-     * @param int    $overwrite
174
-     * @return bool
175
-     */
176
-    public function registerDependencies(
177
-        string $class,
178
-        array $dependencies,
179
-        int $overwrite = EE_Dependency_Map::KEEP_EXISTING_DEPENDENCIES
180
-    ): bool {
181
-        if (empty($dependencies)) {
182
-            return false;
183
-        }
184
-        $class      = trim($class, '\\');
185
-        $registered = false;
186
-        if (empty(EE_Dependency_Map::$_instance->_dependency_map[ $class ])) {
187
-            EE_Dependency_Map::$_instance->_dependency_map[ $class ] = [];
188
-        }
189
-        // we need to make sure that any aliases used when registering a dependency
190
-        // get resolved to the correct class name
191
-        foreach ($dependencies as $dependency => $load_source) {
192
-            $alias = EE_Dependency_Map::$_instance->getFqnForAlias($dependency);
193
-            if (
194
-                $overwrite === EE_Dependency_Map::OVERWRITE_DEPENDENCIES
195
-                || ! isset(
196
-                    EE_Dependency_Map::$_instance->_dependency_map[ $class ][ $dependency ],
197
-                    EE_Dependency_Map::$_instance->_dependency_map[ $class ][ $alias ]
198
-                )
199
-            ) {
200
-                unset($dependencies[ $dependency ]);
201
-                $dependencies[ $alias ] = $load_source;
202
-                $registered             = true;
203
-            }
204
-        }
205
-        // now add our two lists of dependencies together.
206
-        // using Union (+=) favours the arrays in precedence from left to right,
207
-        // so $dependencies is NOT overwritten because it is listed first
208
-        // ie: with A = B + C, entries in B take precedence over duplicate entries in C
209
-        // Union is way faster than array_merge() but should be used with caution...
210
-        // especially with numerically indexed arrays
211
-        $dependencies += EE_Dependency_Map::$_instance->_dependency_map[ $class ];
212
-        // now we need to ensure that the resulting dependencies
213
-        // array only has the entries that are required for the class
214
-        // so first count how many dependencies were originally registered for the class
215
-        $dependency_count = count(EE_Dependency_Map::$_instance->_dependency_map[ $class ]);
216
-        // if that count is non-zero (meaning dependencies were already registered)
217
-        EE_Dependency_Map::$_instance->_dependency_map[ $class ] = $dependency_count
218
-            // then truncate the  final array to match that count
219
-            ? array_slice($dependencies, 0, $dependency_count)
220
-            // otherwise just take the incoming array because nothing previously existed
221
-            : $dependencies;
222
-        return $registered
223
-            || count(EE_Dependency_Map::$_instance->_dependency_map[ $class ]) === count($dependencies);
224
-    }
225
-
226
-
227
-    /**
228
-     * @param string          $class_name
229
-     * @param callable|string $loader
230
-     * @param bool            $overwrite
231
-     * @return bool
232
-     * @throws DomainException
233
-     */
234
-    public static function register_class_loader(
235
-        string $class_name,
236
-        $loader = 'load_core',
237
-        bool $overwrite = false
238
-    ): bool {
239
-        return EE_Dependency_Map::$_instance->registerClassLoader($class_name, $loader, $overwrite);
240
-    }
241
-
242
-
243
-    /**
244
-     * @param string         $class_name
245
-     * @param Closure|string $loader
246
-     * @param bool           $overwrite
247
-     * @return bool
248
-     * @throws DomainException
249
-     */
250
-    public function registerClassLoader(string $class_name, $loader = 'load_core', bool $overwrite = false): bool
251
-    {
252
-        if (! $loader instanceof Closure && strpos($class_name, '\\') !== false) {
253
-            throw new DomainException(
254
-                esc_html__('Don\'t use class loaders for FQCNs.', 'event_espresso')
255
-            );
256
-        }
257
-        // check that loader is callable or method starts with "load_" and exists in EE_Registry
258
-        if (
259
-            ! is_callable($loader)
260
-            && (
261
-                strpos($loader, 'load_') !== 0
262
-                || ! method_exists('EE_Registry', $loader)
263
-            )
264
-        ) {
265
-            throw new DomainException(
266
-                sprintf(
267
-                    esc_html__(
268
-                        '"%1$s" is not a valid loader method on EE_Registry.',
269
-                        'event_espresso'
270
-                    ),
271
-                    $loader
272
-                )
273
-            );
274
-        }
275
-        $class_name = EE_Dependency_Map::$_instance->getFqnForAlias($class_name);
276
-        if ($overwrite || ! isset(EE_Dependency_Map::$_instance->_class_loaders[ $class_name ])) {
277
-            EE_Dependency_Map::$_instance->_class_loaders[ $class_name ] = $loader;
278
-            return true;
279
-        }
280
-        return false;
281
-    }
282
-
283
-
284
-    /**
285
-     * @return array
286
-     */
287
-    public function dependency_map(): array
288
-    {
289
-        return $this->_dependency_map;
290
-    }
291
-
292
-
293
-    /**
294
-     * returns TRUE if dependency map contains a listing for the provided class name
295
-     *
296
-     * @param string $class_name
297
-     * @return boolean
298
-     */
299
-    public function has(string $class_name = ''): bool
300
-    {
301
-        // all legacy models have the same dependencies
302
-        if (strpos($class_name, 'EEM_') === 0) {
303
-            $class_name = 'LEGACY_MODELS';
304
-        }
305
-        return isset($this->_dependency_map[ $class_name ]);
306
-    }
307
-
308
-
309
-    /**
310
-     * returns TRUE if dependency map contains a listing for the provided class name AND dependency
311
-     *
312
-     * @param string $class_name
313
-     * @param string $dependency
314
-     * @return bool
315
-     */
316
-    public function has_dependency_for_class(string $class_name = '', string $dependency = ''): bool
317
-    {
318
-        // all legacy models have the same dependencies
319
-        if (strpos($class_name, 'EEM_') === 0) {
320
-            $class_name = 'LEGACY_MODELS';
321
-        }
322
-        $dependency = $this->getFqnForAlias($dependency, $class_name);
323
-        return isset($this->_dependency_map[ $class_name ][ $dependency ]);
324
-    }
325
-
326
-
327
-    /**
328
-     * returns loading strategy for whether a previously cached dependency should be loaded or a new instance returned
329
-     *
330
-     * @param string $class_name
331
-     * @param string $dependency
332
-     * @return int
333
-     */
334
-    public function loading_strategy_for_class_dependency(string $class_name = '', string $dependency = ''): int
335
-    {
336
-        // all legacy models have the same dependencies
337
-        if (strpos($class_name, 'EEM_') === 0) {
338
-            $class_name = 'LEGACY_MODELS';
339
-        }
340
-        $dependency = $this->getFqnForAlias($dependency);
341
-        return $this->has_dependency_for_class($class_name, $dependency)
342
-            ? $this->_dependency_map[ $class_name ][ $dependency ]
343
-            : EE_Dependency_Map::not_registered;
344
-    }
345
-
346
-
347
-    /**
348
-     * @param string $class_name
349
-     * @return string | Closure
350
-     */
351
-    public function class_loader(string $class_name)
352
-    {
353
-        // all legacy models use load_model()
354
-        if (strpos($class_name, 'EEM_') === 0) {
355
-            return 'load_model';
356
-        }
357
-        // EE_CPT_*_Strategy classes like EE_CPT_Event_Strategy, EE_CPT_Venue_Strategy, etc
358
-        // perform strpos() first to avoid loading regex every time we load a class
359
-        if (
360
-            strpos($class_name, 'EE_CPT_') === 0
361
-            && preg_match('/^EE_CPT_([a-zA-Z]+)_Strategy$/', $class_name)
362
-        ) {
363
-            return 'load_core';
364
-        }
365
-        $class_name = $this->getFqnForAlias($class_name);
366
-        return $this->_class_loaders[ $class_name ] ?? '';
367
-    }
368
-
369
-
370
-    /**
371
-     * @return array
372
-     */
373
-    public function class_loaders(): array
374
-    {
375
-        return $this->_class_loaders;
376
-    }
377
-
378
-
379
-    /**
380
-     * adds an alias for a classname
381
-     *
382
-     * @param string $fqcn      the class name that should be used (concrete class to replace interface)
383
-     * @param string $alias     the class name that would be type hinted for (abstract parent or interface)
384
-     * @param string $for_class the class that has the dependency (is type hinting for the interface)
385
-     * @throws InvalidAliasException
386
-     */
387
-    public function add_alias(string $fqcn, string $alias, string $for_class = '')
388
-    {
389
-        $this->class_cache->addAlias($fqcn, $alias, $for_class);
390
-    }
391
-
392
-
393
-    /**
394
-     * Returns TRUE if the provided fully qualified name IS an alias
395
-     * WHY?
396
-     * Because if a class is type hinting for a concretion,
397
-     * then why would we need to find another class to supply it?
398
-     * ie: if a class asks for `Fully/Qualified/Namespace/SpecificClassName`,
399
-     * then give it an instance of `Fully/Qualified/Namespace/SpecificClassName`.
400
-     * Don't go looking for some substitute.
401
-     * Whereas if a class is type hinting for an interface...
402
-     * then we need to find an actual class to use.
403
-     * So the interface IS the alias for some other FQN,
404
-     * and we need to find out if `Fully/Qualified/Namespace/SomeInterface`
405
-     * represents some other class.
406
-     *
407
-     * @param string $fqn
408
-     * @param string $for_class
409
-     * @return bool
410
-     */
411
-    public function isAlias(string $fqn = '', string $for_class = ''): bool
412
-    {
413
-        return $this->class_cache->isAlias($fqn, $for_class);
414
-    }
415
-
416
-
417
-    /**
418
-     * Returns a FQN for provided alias if one exists, otherwise returns the original $alias
419
-     * functions recursively, so that multiple aliases can be used to drill down to a FQN
420
-     *  for example:
421
-     *      if the following two entries were added to the _aliases array:
422
-     *          array(
423
-     *              'interface_alias'           => 'some\namespace\interface'
424
-     *              'some\namespace\interface'  => 'some\namespace\classname'
425
-     *          )
426
-     *      then one could use EE_Registry::instance()->create( 'interface_alias' )
427
-     *      to load an instance of 'some\namespace\classname'
428
-     *
429
-     * @param string $alias
430
-     * @param string $for_class
431
-     * @return string
432
-     */
433
-    public function getFqnForAlias(string $alias = '', string $for_class = ''): string
434
-    {
435
-        return $this->class_cache->getFqnForAlias($alias, $for_class);
436
-    }
437
-
438
-
439
-    /**
440
-     * Registers the core dependencies and whether a previously instantiated object should be loaded from the cache,
441
-     * if one exists, or whether a new object should be generated every time the requested class is loaded.
442
-     * This is done by using the following class constants:
443
-     *        EE_Dependency_Map::load_from_cache - loads previously instantiated object
444
-     *        EE_Dependency_Map::load_new_object - generates a new object every time
445
-     */
446
-    protected function _register_core_dependencies()
447
-    {
448
-        $this->_dependency_map = [
449
-            'EE_Admin'                                                                                                           => [
450
-                'EventEspresso\core\services\loaders\Loader'  => EE_Dependency_Map::load_from_cache,
451
-                'EventEspresso\core\services\request\Request' => EE_Dependency_Map::load_from_cache,
452
-            ],
453
-            'EE_Maintenance_Mode'                                                                                                => [
454
-                'EventEspresso\core\services\loaders\Loader'  => EE_Dependency_Map::load_from_cache,
455
-                'EventEspresso\core\services\request\Request' => EE_Dependency_Map::load_from_cache,
456
-            ],
457
-            'EE_Request_Handler'                                                                                                 => [
458
-                'EventEspresso\core\services\request\Request'  => EE_Dependency_Map::load_from_cache,
459
-                'EventEspresso\core\services\request\Response' => EE_Dependency_Map::load_from_cache,
460
-            ],
461
-            'EE_System'                                                                                                   => [
462
-                'EventEspresso\core\services\loaders\Loader'                   => EE_Dependency_Map::load_from_cache,
463
-                'EE_Maintenance_Mode'                                          => EE_Dependency_Map::load_from_cache,
464
-                'EE_Registry'                                                  => EE_Dependency_Map::load_from_cache,
465
-                'EventEspresso\core\services\request\Request'                  => EE_Dependency_Map::load_from_cache,
466
-                'EventEspresso\core\services\routing\Router'                   => EE_Dependency_Map::load_from_cache,
467
-                'EventEspresso\core\domain\services\capabilities\FeatureFlags' => EE_Dependency_Map::load_from_cache,
468
-            ],
469
-            'EE_Session'                                                                                                         => [
470
-                'EventEspresso\core\services\cache\TransientCacheStorage'  => EE_Dependency_Map::load_from_cache,
471
-                'EventEspresso\core\domain\values\session\SessionLifespan' => EE_Dependency_Map::load_from_cache,
472
-                'EventEspresso\core\services\request\Request'              => EE_Dependency_Map::load_from_cache,
473
-                'EventEspresso\core\services\session\SessionStartHandler'  => EE_Dependency_Map::load_from_cache,
474
-                'EventEspresso\core\services\encryption\Base64Encoder'     => EE_Dependency_Map::load_from_cache,
475
-            ],
476
-            'EventEspresso\core\services\session\SessionStartHandler'                                                            => [
477
-                'EventEspresso\core\services\request\Request' => EE_Dependency_Map::load_from_cache,
478
-            ],
479
-            'EE_Cart'                                                                                                            => [
480
-                'EE_Session' => EE_Dependency_Map::load_from_cache,
481
-            ],
482
-            'EE_Messenger_Collection_Loader'                                                                                     => [
483
-                'EE_Messenger_Collection' => EE_Dependency_Map::load_new_object,
484
-            ],
485
-            'EE_Message_Type_Collection_Loader'                                                                                  => [
486
-                'EE_Message_Type_Collection' => EE_Dependency_Map::load_new_object,
487
-            ],
488
-            'EE_Message_Resource_Manager'                                                                                        => [
489
-                'EE_Messenger_Collection_Loader'    => EE_Dependency_Map::load_new_object,
490
-                'EE_Message_Type_Collection_Loader' => EE_Dependency_Map::load_new_object,
491
-                'EEM_Message_Template_Group'        => EE_Dependency_Map::load_from_cache,
492
-            ],
493
-            'EE_Message_Factory'                                                                                                 => [
494
-                'EE_Message_Resource_Manager' => EE_Dependency_Map::load_from_cache,
495
-            ],
496
-            'EE_messages'                                                                                                        => [
497
-                'EE_Message_Resource_Manager' => EE_Dependency_Map::load_from_cache,
498
-            ],
499
-            'EE_Messages_Generator'                                                                                              => [
500
-                'EE_Messages_Queue'                    => EE_Dependency_Map::load_new_object,
501
-                'EE_Messages_Data_Handler_Collection'  => EE_Dependency_Map::load_new_object,
502
-                'EE_Message_Template_Group_Collection' => EE_Dependency_Map::load_new_object,
503
-                'EEH_Parse_Shortcodes'                 => EE_Dependency_Map::load_from_cache,
504
-            ],
505
-            'EE_Messages_Processor'                                                                                              => [
506
-                'EE_Message_Resource_Manager' => EE_Dependency_Map::load_from_cache,
507
-            ],
508
-            'EE_Messages_Queue'                                                                                                  => [
509
-                'EE_Message_Repository' => EE_Dependency_Map::load_new_object,
510
-            ],
511
-            'EE_Messages_Template_Defaults'                                                                                      => [
512
-                'EEM_Message_Template_Group' => EE_Dependency_Map::load_from_cache,
513
-                'EEM_Message_Template'       => EE_Dependency_Map::load_from_cache,
514
-            ],
515
-            'EE_Message_To_Generate_From_Request'                                                                                => [
516
-                'EE_Message_Resource_Manager'                 => EE_Dependency_Map::load_from_cache,
517
-                'EventEspresso\core\services\request\Request' => EE_Dependency_Map::load_from_cache,
518
-            ],
519
-            'EventEspresso\core\services\commands\CommandBus'                                                                    => [
520
-                'EventEspresso\core\services\commands\CommandHandlerManager' => EE_Dependency_Map::load_from_cache,
521
-            ],
522
-            'EventEspresso\services\commands\CommandHandler'                                                                     => [
523
-                'EE_Registry'         => EE_Dependency_Map::load_from_cache,
524
-                'CommandBusInterface' => EE_Dependency_Map::load_from_cache,
525
-            ],
526
-            'EventEspresso\core\services\commands\CommandHandlerManager'                                                         => [
527
-                'EventEspresso\core\services\loaders\Loader' => EE_Dependency_Map::load_from_cache,
528
-            ],
529
-            'EventEspresso\core\services\commands\CompositeCommandHandler'                                                       => [
530
-                'EventEspresso\core\services\commands\CommandBus'     => EE_Dependency_Map::load_from_cache,
531
-                'EventEspresso\core\services\commands\CommandFactory' => EE_Dependency_Map::load_from_cache,
532
-            ],
533
-            'EventEspresso\core\services\commands\CommandFactory'                                                                => [
534
-                'EventEspresso\core\services\loaders\Loader' => EE_Dependency_Map::load_from_cache,
535
-            ],
536
-            'EventEspresso\core\services\commands\middleware\CapChecker'                                                         => [
537
-                'EventEspresso\core\domain\services\capabilities\CapabilitiesChecker' => EE_Dependency_Map::load_from_cache,
538
-            ],
539
-            'EventEspresso\core\domain\services\capabilities\CapabilitiesChecker'                                                => [
540
-                'EE_Capabilities' => EE_Dependency_Map::load_from_cache,
541
-            ],
542
-            'EventEspresso\core\domain\services\capabilities\RegistrationsCapChecker'                                            => [
543
-                'EE_Capabilities' => EE_Dependency_Map::load_from_cache,
544
-            ],
545
-            'EventEspresso\core\domain\services\commands\registration\CreateRegistrationCommandHandler'                          => [
546
-                'EventEspresso\core\domain\services\registration\CreateRegistrationService' => EE_Dependency_Map::load_from_cache,
547
-            ],
548
-            'EventEspresso\core\domain\services\commands\registration\CopyRegistrationDetailsCommandHandler'                     => [
549
-                'EventEspresso\core\domain\services\registration\CopyRegistrationService' => EE_Dependency_Map::load_from_cache,
550
-            ],
551
-            'EventEspresso\core\domain\services\commands\registration\CopyRegistrationPaymentsCommandHandler'                    => [
552
-                'EventEspresso\core\domain\services\registration\CopyRegistrationService' => EE_Dependency_Map::load_from_cache,
553
-            ],
554
-            'EventEspresso\core\domain\services\commands\registration\CancelRegistrationAndTicketLineItemCommandHandler'         => [
555
-                'EventEspresso\core\domain\services\registration\CancelTicketLineItemService' => EE_Dependency_Map::load_from_cache,
556
-            ],
557
-            'EventEspresso\core\domain\services\commands\registration\UpdateRegistrationAndTransactionAfterChangeCommandHandler' => [
558
-                'EventEspresso\core\domain\services\registration\UpdateRegistrationService' => EE_Dependency_Map::load_from_cache,
559
-            ],
560
-            'EventEspresso\core\domain\services\commands\ticket\CreateTicketLineItemCommandHandler'                              => [
561
-                'EventEspresso\core\domain\services\ticket\CreateTicketLineItemService' => EE_Dependency_Map::load_from_cache,
562
-            ],
563
-            'EventEspresso\core\domain\services\commands\ticket\CancelTicketLineItemCommandHandler'                              => [
564
-                'EventEspresso\core\domain\services\ticket\CancelTicketLineItemService' => EE_Dependency_Map::load_from_cache,
565
-            ],
566
-            'EventEspresso\core\domain\services\registration\CancelRegistrationService'                                          => [
567
-                'EventEspresso\core\domain\services\ticket\CancelTicketLineItemService' => EE_Dependency_Map::load_from_cache,
568
-            ],
569
-            'EventEspresso\core\domain\services\commands\attendee\CreateAttendeeCommandHandler'                                  => [
570
-                'EEM_Attendee' => EE_Dependency_Map::load_from_cache,
571
-            ],
572
-            'EventEspresso\core\domain\values\session\SessionLifespan'                                                           => [
573
-                'EventEspresso\core\domain\values\session\SessionLifespanOption' => EE_Dependency_Map::load_from_cache,
574
-            ],
575
-            'EventEspresso\caffeinated\admin\extend\registration_form\forms\SessionLifespanForm'                                 => [
576
-                'EventEspresso\core\domain\values\session\SessionLifespanOption' => EE_Dependency_Map::load_from_cache,
577
-                'EE_Registration_Config'                                         => EE_Dependency_Map::load_from_cache,
578
-            ],
579
-            'EventEspresso\caffeinated\admin\extend\registration_form\forms\SessionLifespanFormHandler'                          => [
580
-                'EventEspresso\core\domain\values\session\SessionLifespanOption' => EE_Dependency_Map::load_from_cache,
581
-                'EE_Config'                                                      => EE_Dependency_Map::load_from_cache,
582
-            ],
583
-            'EventEspresso\core\services\database\TableManager'                                                                  => [
584
-                'EventEspresso\core\services\database\TableAnalysis' => EE_Dependency_Map::load_from_cache,
585
-            ],
586
-            'EE_Data_Migration_Class_Base'                                                                                       => [
587
-                'EventEspresso\core\services\database\TableAnalysis' => EE_Dependency_Map::load_from_cache,
588
-                'EventEspresso\core\services\database\TableManager'  => EE_Dependency_Map::load_from_cache,
589
-            ],
590
-            'EE_DMS_Core_4_1_0'                                                                                                  => [
591
-                'EventEspresso\core\services\database\TableAnalysis' => EE_Dependency_Map::load_from_cache,
592
-                'EventEspresso\core\services\database\TableManager'  => EE_Dependency_Map::load_from_cache,
593
-            ],
594
-            'EE_DMS_Core_4_2_0'                                                                                                  => [
595
-                'EventEspresso\core\services\database\TableAnalysis' => EE_Dependency_Map::load_from_cache,
596
-                'EventEspresso\core\services\database\TableManager'  => EE_Dependency_Map::load_from_cache,
597
-            ],
598
-            'EE_DMS_Core_4_3_0'                                                                                                  => [
599
-                'EventEspresso\core\services\database\TableAnalysis' => EE_Dependency_Map::load_from_cache,
600
-                'EventEspresso\core\services\database\TableManager'  => EE_Dependency_Map::load_from_cache,
601
-            ],
602
-            'EE_DMS_Core_4_4_0'                                                                                                  => [
603
-                'EventEspresso\core\services\database\TableAnalysis' => EE_Dependency_Map::load_from_cache,
604
-                'EventEspresso\core\services\database\TableManager'  => EE_Dependency_Map::load_from_cache,
605
-            ],
606
-            'EE_DMS_Core_4_5_0'                                                                                                  => [
607
-                'EventEspresso\core\services\database\TableAnalysis' => EE_Dependency_Map::load_from_cache,
608
-                'EventEspresso\core\services\database\TableManager'  => EE_Dependency_Map::load_from_cache,
609
-            ],
610
-            'EE_DMS_Core_4_6_0'                                                                                                  => [
611
-                'EventEspresso\core\services\database\TableAnalysis' => EE_Dependency_Map::load_from_cache,
612
-                'EventEspresso\core\services\database\TableManager'  => EE_Dependency_Map::load_from_cache,
613
-            ],
614
-            'EE_DMS_Core_4_7_0'                                                                                                  => [
615
-                'EventEspresso\core\services\database\TableAnalysis' => EE_Dependency_Map::load_from_cache,
616
-                'EventEspresso\core\services\database\TableManager'  => EE_Dependency_Map::load_from_cache,
617
-            ],
618
-            'EE_DMS_Core_4_8_0'                                                                                                  => [
619
-                'EventEspresso\core\services\database\TableAnalysis' => EE_Dependency_Map::load_from_cache,
620
-                'EventEspresso\core\services\database\TableManager'  => EE_Dependency_Map::load_from_cache,
621
-            ],
622
-            'EE_DMS_Core_4_9_0'                                                                                                  => [
623
-                'EventEspresso\core\services\database\TableAnalysis' => EE_Dependency_Map::load_from_cache,
624
-                'EventEspresso\core\services\database\TableManager'  => EE_Dependency_Map::load_from_cache,
625
-            ],
626
-            'EE_DMS_Core_4_10_0'                                                                                                 => [
627
-                'EventEspresso\core\services\database\TableAnalysis' => EE_Dependency_Map::load_from_cache,
628
-                'EventEspresso\core\services\database\TableManager'  => EE_Dependency_Map::load_from_cache,
629
-                'EE_DMS_Core_4_9_0'                                  => EE_Dependency_Map::load_from_cache,
630
-            ],
631
-            'EE_DMS_Core_5_0_0'                                                                                                  => [
632
-                'EE_DMS_Core_4_10_0'                                 => EE_Dependency_Map::load_from_cache,
633
-                'EventEspresso\core\services\database\TableAnalysis' => EE_Dependency_Map::load_from_cache,
634
-                'EventEspresso\core\services\database\TableManager'  => EE_Dependency_Map::load_from_cache,
635
-            ],
636
-            'EventEspresso\core\services\assets\I18nRegistry'                                                                    => [
637
-                'EventEspresso\core\domain\Domain' => EE_Dependency_Map::load_from_cache,
638
-            ],
639
-            'EventEspresso\core\services\assets\Registry'                                                                        => [
640
-                'EventEspresso\core\services\assets\AssetCollection' => EE_Dependency_Map::load_from_cache,
641
-                'EventEspresso\core\services\assets\AssetManifest'   => EE_Dependency_Map::load_from_cache,
642
-            ],
643
-            'EventEspresso\core\domain\entities\shortcodes\EspressoCancelled'                                                    => [
644
-                'EventEspresso\core\services\cache\PostRelatedCacheManager' => EE_Dependency_Map::load_from_cache,
645
-            ],
646
-            'EventEspresso\core\domain\entities\shortcodes\EspressoCheckout'                                                     => [
647
-                'EventEspresso\core\services\cache\PostRelatedCacheManager' => EE_Dependency_Map::load_from_cache,
648
-            ],
649
-            'EventEspresso\core\domain\entities\shortcodes\EspressoEventAttendees'                                               => [
650
-                'EventEspresso\core\services\cache\PostRelatedCacheManager' => EE_Dependency_Map::load_from_cache,
651
-            ],
652
-            'EventEspresso\core\domain\entities\shortcodes\EspressoEvents'                                                       => [
653
-                'EventEspresso\core\services\cache\PostRelatedCacheManager' => EE_Dependency_Map::load_from_cache,
654
-            ],
655
-            'EventEspresso\core\domain\entities\shortcodes\EspressoThankYou'                                                     => [
656
-                'EventEspresso\core\services\cache\PostRelatedCacheManager' => EE_Dependency_Map::load_from_cache,
657
-            ],
658
-            'EventEspresso\core\domain\entities\shortcodes\EspressoTicketSelector'                                               => [
659
-                'EventEspresso\core\services\cache\PostRelatedCacheManager' => EE_Dependency_Map::load_from_cache,
660
-            ],
661
-            'EventEspresso\core\domain\entities\shortcodes\EspressoTxnPage'                                                      => [
662
-                'EventEspresso\core\services\cache\PostRelatedCacheManager' => EE_Dependency_Map::load_from_cache,
663
-            ],
664
-            'EventEspresso\core\services\cache\BasicCacheManager'                                                                => [
665
-                'EventEspresso\core\services\cache\TransientCacheStorage' => EE_Dependency_Map::load_from_cache,
666
-            ],
667
-            'EventEspresso\core\services\cache\PostRelatedCacheManager'                                                          => [
668
-                'EventEspresso\core\services\cache\TransientCacheStorage' => EE_Dependency_Map::load_from_cache,
669
-            ],
670
-            'EventEspresso\core\domain\services\validation\email\EmailValidationService'                                         => [
671
-                'EE_Registration_Config'                     => EE_Dependency_Map::load_from_cache,
672
-                'EventEspresso\core\services\loaders\Loader' => EE_Dependency_Map::load_from_cache,
673
-            ],
674
-            'EventEspresso\core\domain\values\EmailAddress'                                                                      => [
675
-                null,
676
-                'EventEspresso\core\domain\services\validation\email\EmailValidationService' => EE_Dependency_Map::load_from_cache,
677
-            ],
678
-            'EventEspresso\core\services\orm\ModelFieldFactory'                                                                  => [
679
-                'EventEspresso\core\services\loaders\Loader' => EE_Dependency_Map::load_from_cache,
680
-            ],
681
-            'LEGACY_MODELS'                                                                                                      => [
682
-                null,
683
-                'EventEspresso\core\services\database\ModelFieldFactory' => EE_Dependency_Map::load_from_cache,
684
-            ],
685
-            'EE_Module_Request_Router'                                                                                           => [
686
-                'EventEspresso\core\services\request\Request' => EE_Dependency_Map::load_from_cache,
687
-            ],
688
-            'EE_Registration_Processor'                                                                                          => [
689
-                'EventEspresso\core\services\request\Request' => EE_Dependency_Map::load_from_cache,
690
-            ],
691
-            'EventEspresso\core\services\notifications\PersistentAdminNoticeManager'                                             => [
692
-                'EventEspresso\core\domain\services\capabilities\CapabilitiesChecker' => EE_Dependency_Map::load_from_cache,
693
-                'EventEspresso\core\services\request\Request'                         => EE_Dependency_Map::load_from_cache,
694
-            ],
695
-            'EventEspresso\caffeinated\modules\recaptcha_invisible\InvisibleRecaptcha'                                           => [
696
-                'EE_Registration_Config' => EE_Dependency_Map::load_from_cache,
697
-                'EE_Session'             => EE_Dependency_Map::load_from_cache,
698
-            ],
699
-            'EventEspresso\modules\ticket_selector\DisplayTicketSelector'                                                        => [
700
-                'EventEspresso\core\domain\entities\users\CurrentUser' => EE_Dependency_Map::load_from_cache,
701
-                'EventEspresso\core\services\request\Request'          => EE_Dependency_Map::load_from_cache,
702
-                'EE_Ticket_Selector_Config'                            => EE_Dependency_Map::load_from_cache,
703
-            ],
704
-            'EventEspresso\modules\ticket_selector\ProcessTicketSelector'                                                        => [
705
-                'EE_Core_Config'                                                          => EE_Dependency_Map::load_from_cache,
706
-                'EventEspresso\core\services\request\Request'                             => EE_Dependency_Map::load_from_cache,
707
-                'EE_Session'                                                              => EE_Dependency_Map::load_from_cache,
708
-                'EEM_Ticket'                                                              => EE_Dependency_Map::load_from_cache,
709
-                'EventEspresso\modules\ticket_selector\TicketDatetimeAvailabilityTracker' => EE_Dependency_Map::load_from_cache,
710
-            ],
711
-            'EventEspresso\modules\ticket_selector\ProcessTicketSelectorPostData'                                                => [
712
-                'EventEspresso\core\services\request\Request' => EE_Dependency_Map::load_from_cache,
713
-                'EEM_Event'                                   => EE_Dependency_Map::load_from_cache,
714
-            ],
715
-            'EventEspresso\modules\ticket_selector\TicketDatetimeAvailabilityTracker'                                            => [
716
-                'EEM_Datetime' => EE_Dependency_Map::load_from_cache,
717
-            ],
718
-            'EventEspresso\core\domain\entities\custom_post_types\CustomPostTypeDefinitions'                                     => [
719
-                'EE_Core_Config'                             => EE_Dependency_Map::load_from_cache,
720
-                'EventEspresso\core\services\loaders\Loader' => EE_Dependency_Map::load_from_cache,
721
-            ],
722
-            'EventEspresso\core\domain\services\custom_post_types\RegisterCustomPostTypes'                                       => [
723
-                'EventEspresso\core\domain\entities\custom_post_types\CustomPostTypeDefinitions' => EE_Dependency_Map::load_from_cache,
724
-            ],
725
-            'EventEspresso\core\domain\services\custom_post_types\RegisterCustomTaxonomies'                                      => [
726
-                'EventEspresso\core\domain\entities\custom_post_types\CustomTaxonomyDefinitions' => EE_Dependency_Map::load_from_cache,
727
-            ],
728
-            'EE_CPT_Strategy'                                                                                                    => [
729
-                'EventEspresso\core\domain\entities\custom_post_types\CustomPostTypeDefinitions' => EE_Dependency_Map::load_from_cache,
730
-                'EventEspresso\core\domain\entities\custom_post_types\CustomTaxonomyDefinitions' => EE_Dependency_Map::load_from_cache,
731
-            ],
732
-            'EventEspresso\core\services\loaders\ObjectIdentifier'                                                               => [
733
-                'EventEspresso\core\services\loaders\ClassInterfaceCache' => EE_Dependency_Map::load_from_cache,
734
-            ],
735
-            'EventEspresso\core\CPTs\CptQueryModifier'                                                                           => [
736
-                null,
737
-                null,
738
-                null,
739
-                'EventEspresso\core\services\request\CurrentPage' => EE_Dependency_Map::load_from_cache,
740
-                'EventEspresso\core\services\request\Request'     => EE_Dependency_Map::load_from_cache,
741
-                'EventEspresso\core\services\loaders\Loader'      => EE_Dependency_Map::load_from_cache,
742
-            ],
743
-            'EventEspresso\core\services\dependencies\DependencyResolver'                                                        => [
744
-                'EventEspresso\core\services\container\Mirror'            => EE_Dependency_Map::load_from_cache,
745
-                'EventEspresso\core\services\loaders\ClassInterfaceCache' => EE_Dependency_Map::load_from_cache,
746
-                'EE_Dependency_Map'                                       => EE_Dependency_Map::load_from_cache,
747
-            ],
748
-            'EventEspresso\core\services\routing\RouteMatchSpecificationDependencyResolver'                                      => [
749
-                'EventEspresso\core\services\container\Mirror'            => EE_Dependency_Map::load_from_cache,
750
-                'EventEspresso\core\services\loaders\ClassInterfaceCache' => EE_Dependency_Map::load_from_cache,
751
-                'EE_Dependency_Map'                                       => EE_Dependency_Map::load_from_cache,
752
-            ],
753
-            'EventEspresso\core\services\routing\RouteMatchSpecificationFactory'                                                 => [
754
-                'EventEspresso\core\services\routing\RouteMatchSpecificationDependencyResolver' => EE_Dependency_Map::load_from_cache,
755
-                'EventEspresso\core\services\loaders\Loader'                                    => EE_Dependency_Map::load_from_cache,
756
-            ],
757
-            'EventEspresso\core\services\routing\RouteMatchSpecificationManager'                                                 => [
758
-                'EventEspresso\core\services\routing\RouteMatchSpecificationCollection' => EE_Dependency_Map::load_from_cache,
759
-                'EventEspresso\core\services\routing\RouteMatchSpecificationFactory'    => EE_Dependency_Map::load_from_cache,
760
-            ],
761
-            'EventEspresso\core\services\request\files\FilesDataHandler'                                                         => [
762
-                'EventEspresso\core\services\request\Request' => EE_Dependency_Map::load_from_cache,
763
-            ],
764
-            'EventEspresso\core\libraries\batch\BatchRequestProcessor'                                                           => [
765
-                'EventEspresso\core\services\loaders\Loader'  => EE_Dependency_Map::load_from_cache,
766
-                'EventEspresso\core\services\request\Request' => EE_Dependency_Map::load_from_cache,
767
-            ],
768
-            'EventEspresso\core\domain\services\converters\RestApiSpoofer'                                                       => [
769
-                'WP_REST_Server'                                               => EE_Dependency_Map::load_from_cache,
770
-                'EED_Core_Rest_Api'                                            => EE_Dependency_Map::load_from_cache,
771
-                'EventEspresso\core\libraries\rest_api\controllers\model\Read' => EE_Dependency_Map::load_from_cache,
772
-                null,
773
-            ],
774
-            'EventEspresso\core\services\routing\RouteHandler'                                                                   => [
775
-                'EventEspresso\core\domain\services\capabilities\CapabilitiesChecker' => EE_Dependency_Map::load_from_cache,
776
-                'EventEspresso\core\services\json\JsonDataNodeHandler'                => EE_Dependency_Map::load_from_cache,
777
-                'EventEspresso\core\services\loaders\Loader'                          => EE_Dependency_Map::load_from_cache,
778
-                'EventEspresso\core\services\request\Request'                         => EE_Dependency_Map::load_from_cache,
779
-                'EventEspresso\core\services\routing\RouteCollection'                 => EE_Dependency_Map::load_from_cache,
780
-            ],
781
-            'EventEspresso\core\services\json\JsonDataNodeHandler'                                                               => [
782
-                'EventEspresso\core\services\json\JsonDataNodeValidator' => EE_Dependency_Map::load_from_cache,
783
-            ],
784
-            'EventEspresso\core\services\routing\Router'                                                                         => [
785
-                'EE_Dependency_Map'                                => EE_Dependency_Map::load_from_cache,
786
-                'EventEspresso\core\services\loaders\Loader'       => EE_Dependency_Map::load_from_cache,
787
-                'EventEspresso\core\services\routing\RouteHandler' => EE_Dependency_Map::load_from_cache,
788
-            ],
789
-            'EventEspresso\core\services\assets\AssetManifest'                                                                   => [
790
-                'EventEspresso\core\domain\Domain' => EE_Dependency_Map::load_from_cache,
791
-            ],
792
-            'EventEspresso\core\services\assets\AssetManifestFactory'                                                            => [
793
-                'EventEspresso\core\services\loaders\Loader' => EE_Dependency_Map::load_from_cache,
794
-            ],
795
-            'EventEspresso\core\services\assets\BaristaFactory'                                                                  => [
796
-                'EventEspresso\core\services\assets\AssetManifestFactory' => EE_Dependency_Map::load_from_cache,
797
-                'EventEspresso\core\services\loaders\Loader'              => EE_Dependency_Map::load_from_cache,
798
-            ],
799
-            'EventEspresso\core\domain\services\capabilities\FeatureFlagsConfig' => [
800
-                'EventEspresso\core\domain\Domain'                                    => EE_Dependency_Map::load_from_cache,
801
-                'EventEspresso\core\services\json\JsonDataHandler'                    => EE_Dependency_Map::load_from_cache,
802
-            ],
803
-            'EventEspresso\core\domain\services\capabilities\FeatureFlags'       => [
804
-                'EventEspresso\core\domain\services\capabilities\CapabilitiesChecker' => EE_Dependency_Map::load_from_cache,
805
-                'EventEspresso\core\domain\services\capabilities\FeatureFlagsConfig'  => EE_Dependency_Map::load_from_cache,
806
-            ],
807
-            'EventEspresso\core\services\addon\AddonManager'                                                                     => [
808
-                'EventEspresso\core\services\addon\AddonCollection'              => EE_Dependency_Map::load_from_cache,
809
-                'EventEspresso\core\Psr4Autoloader'                              => EE_Dependency_Map::load_from_cache,
810
-                'EventEspresso\core\services\addon\api\v1\RegisterAddon'         => EE_Dependency_Map::load_from_cache,
811
-                'EventEspresso\core\services\addon\api\IncompatibleAddonHandler' => EE_Dependency_Map::load_from_cache,
812
-                'EventEspresso\core\services\addon\api\ThirdPartyPluginHandler'  => EE_Dependency_Map::load_from_cache,
813
-            ],
814
-            'EventEspresso\core\services\addon\api\ThirdPartyPluginHandler'                                                      => [
815
-                'EventEspresso\core\services\request\Request' => EE_Dependency_Map::load_from_cache,
816
-            ],
817
-            'EventEspresso\core\libraries\batch\JobHandlers\ExecuteBatchDeletion'                                                => [
818
-                'EventEspresso\core\services\orm\tree_traversal\NodeGroupDao' => EE_Dependency_Map::load_from_cache,
819
-            ],
820
-            'EventEspresso\core\libraries\batch\JobHandlers\PreviewEventDeletion'                                                => [
821
-                'EventEspresso\core\services\orm\tree_traversal\NodeGroupDao' => EE_Dependency_Map::load_from_cache,
822
-            ],
823
-            'EventEspresso\core\domain\services\admin\events\data\PreviewDeletion'                                               => [
824
-                'EventEspresso\core\services\orm\tree_traversal\NodeGroupDao' => EE_Dependency_Map::load_from_cache,
825
-                'EEM_Event'                                                   => EE_Dependency_Map::load_from_cache,
826
-                'EEM_Datetime'                                                => EE_Dependency_Map::load_from_cache,
827
-                'EEM_Registration'                                            => EE_Dependency_Map::load_from_cache,
828
-            ],
829
-            'EventEspresso\core\domain\services\admin\events\data\ConfirmDeletion'                                               => [
830
-                'EventEspresso\core\services\orm\tree_traversal\NodeGroupDao' => EE_Dependency_Map::load_from_cache,
831
-            ],
832
-            'EventEspresso\core\services\request\CurrentPage'                                                                    => [
833
-                'EE_CPT_Strategy'                             => EE_Dependency_Map::load_from_cache,
834
-                'EventEspresso\core\services\request\Request' => EE_Dependency_Map::load_from_cache,
835
-            ],
836
-            'EventEspresso\core\services\shortcodes\LegacyShortcodesManager'                                                     => [
837
-                'EE_Registry'                                     => EE_Dependency_Map::load_from_cache,
838
-                'EventEspresso\core\services\request\CurrentPage' => EE_Dependency_Map::load_from_cache,
839
-            ],
840
-            'EventEspresso\core\services\shortcodes\ShortcodesManager'                                                           => [
841
-                'EventEspresso\core\services\shortcodes\LegacyShortcodesManager' => EE_Dependency_Map::load_from_cache,
842
-                'EventEspresso\core\services\request\CurrentPage'                => EE_Dependency_Map::load_from_cache,
843
-            ],
844
-            'EventEspresso\core\domain\entities\users\CurrentUser'                                                               => [
845
-                'EventEspresso\core\domain\entities\users\EventManagers' => EE_Dependency_Map::load_from_cache,
846
-            ],
847
-            'EventEspresso\core\services\form\meta\InputTypes'                                                                   => [
848
-                'EventEspresso\core\services\form\meta\inputs\Block'    => EE_Dependency_Map::load_from_cache,
849
-                'EventEspresso\core\services\form\meta\inputs\Button'   => EE_Dependency_Map::load_from_cache,
850
-                'EventEspresso\core\services\form\meta\inputs\DateTime' => EE_Dependency_Map::load_from_cache,
851
-                'EventEspresso\core\services\form\meta\inputs\Input'    => EE_Dependency_Map::load_from_cache,
852
-                'EventEspresso\core\services\form\meta\inputs\Number'   => EE_Dependency_Map::load_from_cache,
853
-                'EventEspresso\core\services\form\meta\inputs\Phone'    => EE_Dependency_Map::load_from_cache,
854
-                'EventEspresso\core\services\form\meta\inputs\Select'   => EE_Dependency_Map::load_from_cache,
855
-                'EventEspresso\core\services\form\meta\inputs\Text'     => EE_Dependency_Map::load_from_cache,
856
-            ],
857
-            'EventEspresso\core\domain\services\registration\form\v1\RegFormDependencyHandler'                                   => [
858
-                'EE_Dependency_Map' => EE_Dependency_Map::load_from_cache,
859
-            ],
860
-            'EventEspresso\core\services\calculators\LineItemCalculator'                                                         => [
861
-                'EventEspresso\core\services\helpers\DecimalValues' => EE_Dependency_Map::load_from_cache,
862
-            ],
863
-            'EventEspresso\core\services\helpers\DecimalValues'                                                                  => [
864
-                'EE_Currency_Config' => EE_Dependency_Map::load_from_cache,
865
-            ],
866
-            'EE_Brewing_Regular'                                                                                                 => [
867
-                'EE_Dependency_Map'                                  => EE_Dependency_Map::load_from_cache,
868
-                'EventEspresso\core\services\loaders\Loader'         => EE_Dependency_Map::load_from_cache,
869
-                'EventEspresso\core\services\routing\RouteHandler'   => EE_Dependency_Map::load_from_cache,
870
-                'EventEspresso\core\services\database\TableAnalysis' => EE_Dependency_Map::load_from_cache,
871
-            ],
872
-            'EventEspresso\core\domain\services\messages\MessageTemplateRequestData'                                             => [
873
-                'EventEspresso\core\services\request\Request' => EE_Dependency_Map::load_from_cache,
874
-            ],
875
-            'EventEspresso\core\domain\services\messages\MessageTemplateValidator'                                               => [
876
-                'EventEspresso\core\services\loaders\Loader' => EE_Dependency_Map::load_from_cache,
877
-            ],
878
-            'EventEspresso\core\domain\services\messages\MessageTemplateManager'                                                 => [
879
-                'EEM_Message_Template'                                                   => EE_Dependency_Map::load_from_cache,
880
-                'EEM_Message_Template_Group'                                             => EE_Dependency_Map::load_from_cache,
881
-                'EventEspresso\core\domain\services\messages\MessageTemplateRequestData' => EE_Dependency_Map::load_from_cache,
882
-                'EventEspresso\core\domain\services\messages\MessageTemplateValidator'   => EE_Dependency_Map::load_from_cache,
883
-                'EventEspresso\core\services\request\Request'                            => EE_Dependency_Map::load_from_cache,
884
-            ],
885
-            'EventEspresso\core\services\request\sanitizers\RequestSanitizer'                                                    => [
886
-                'EventEspresso\core\domain\services\validation\email\strategies\Basic' => EE_Dependency_Map::load_from_cache,
887
-            ],
888
-            'EE_CPT_Event_Strategy'                                                    => [
889
-                null,
890
-                null,
891
-                'EE_Template_Config' => EE_Dependency_Map::load_from_cache,
892
-            ],
893
-            'EventEspresso\core\domain\services\licensing\LicenseKeyFormInput'                                                    => [
894
-                'EventEspresso\core\services\licensing\PluginLicense'  => EE_Dependency_Map::not_registered,
895
-                'EventEspresso\core\services\licensing\LicenseManager' => EE_Dependency_Map::load_from_cache,
896
-            ],
897
-        ];
898
-    }
899
-
900
-
901
-    /**
902
-     * Registers how core classes are loaded.
903
-     * This can either be done by simply providing the name of one of the EE_Registry loader methods such as:
904
-     *        'EE_Request_Handler' => 'load_core'
905
-     *        'EE_Messages_Queue'  => 'load_lib'
906
-     *        'EEH_Debug_Tools'    => 'load_helper'
907
-     * or, if greater control is required, by providing a custom closure. For example:
908
-     *        'Some_Class' => function () {
909
-     *            return new Some_Class();
910
-     *        },
911
-     * This is required for instantiating dependencies
912
-     * where an interface has been type hinted in a class constructor. For example:
913
-     *        'Required_Interface' => function () {
914
-     *            return new A_Class_That_Implements_Required_Interface();
915
-     *        },
916
-     */
917
-    protected function _register_core_class_loaders()
918
-    {
919
-        $this->_class_loaders = [
920
-            // load_core
921
-            'EE_Dependency_Map'                            => function () {
922
-                return $this;
923
-            },
924
-            'EE_Capabilities'                              => 'load_core',
925
-            'EE_Encryption'                                => 'load_core',
926
-            'EE_Front_Controller'                          => 'load_core',
927
-            'EE_Module_Request_Router'                     => 'load_core',
928
-            'EE_Registry'                                  => 'load_core',
929
-            'EE_Request'                                   => function () {
930
-                return $this->legacy_request;
931
-            },
932
-            'EventEspresso\core\services\request\Request'  => function () {
933
-                return $this->request;
934
-            },
935
-            'EventEspresso\core\services\request\Response' => function () {
936
-                return $this->response;
937
-            },
938
-            'EE_Base'                                      => 'load_core',
939
-            'EE_Request_Handler'                           => 'load_core',
940
-            'EE_Session'                                   => 'load_core',
941
-            'EE_Cron_Tasks'                                => 'load_core',
942
-            'EE_System'                                    => 'load_core',
943
-            'EE_Maintenance_Mode'                          => 'load_core',
944
-            'EE_Register_CPTs'                             => 'load_core',
945
-            'EE_Admin'                                     => 'load_core',
946
-            'EE_CPT_Strategy'                              => 'load_core',
947
-            // load_class
948
-            'EE_Registration_Processor'                    => 'load_class',
949
-            'EE_Transaction_Payments'                      => 'load_class',
950
-            'EE_Transaction_Processor'                     => 'load_class',
951
-            // load_lib
952
-            'EE_Message_Resource_Manager'                  => 'load_lib',
953
-            'EE_Message_Type_Collection'                   => 'load_lib',
954
-            'EE_Message_Type_Collection_Loader'            => 'load_lib',
955
-            'EE_Messenger_Collection'                      => 'load_lib',
956
-            'EE_Messenger_Collection_Loader'               => 'load_lib',
957
-            'EE_Messages_Processor'                        => 'load_lib',
958
-            'EE_Message_Repository'                        => 'load_lib',
959
-            'EE_Messages_Queue'                            => 'load_lib',
960
-            'EE_Messages_Data_Handler_Collection'          => 'load_lib',
961
-            'EE_Message_Template_Group_Collection'         => 'load_lib',
962
-            'EE_Payment_Method_Manager'                    => 'load_lib',
963
-            'EE_Payment_Processor'                         => 'load_core',
964
-            'EE_DMS_Core_4_1_0'                            => 'load_dms',
965
-            'EE_DMS_Core_4_2_0'                            => 'load_dms',
966
-            'EE_DMS_Core_4_3_0'                            => 'load_dms',
967
-            'EE_DMS_Core_4_5_0'                            => 'load_dms',
968
-            'EE_DMS_Core_4_6_0'                            => 'load_dms',
969
-            'EE_DMS_Core_4_7_0'                            => 'load_dms',
970
-            'EE_DMS_Core_4_8_0'                            => 'load_dms',
971
-            'EE_DMS_Core_4_9_0'                            => 'load_dms',
972
-            'EE_DMS_Core_4_10_0'                           => 'load_dms',
973
-            'EE_DMS_Core_5_0_0'                            => 'load_dms',
974
-            'EE_Messages_Generator'                        => static function () {
975
-                return EE_Registry::instance()->load_lib(
976
-                    'Messages_Generator',
977
-                    [],
978
-                    false,
979
-                    false
980
-                );
981
-            },
982
-            'EE_Messages_Template_Defaults'                => static function ($arguments = []) {
983
-                return EE_Registry::instance()->load_lib(
984
-                    'Messages_Template_Defaults',
985
-                    $arguments,
986
-                    false,
987
-                    false
988
-                );
989
-            },
990
-            // load_helper
991
-            'EEH_Parse_Shortcodes'                         => static function () {
992
-                if (EE_Registry::instance()->load_helper('Parse_Shortcodes')) {
993
-                    return new EEH_Parse_Shortcodes();
994
-                }
995
-                return null;
996
-            },
997
-            'EE_Template_Config'                           => static function () {
998
-                return EE_Config::instance()->template_settings;
999
-            },
1000
-            'EE_Currency_Config'                           => static function () {
1001
-                return EE_Currency_Config::getCurrencyConfig();
1002
-            },
1003
-            'EE_Registration_Config'                       => static function () {
1004
-                return EE_Config::instance()->registration;
1005
-            },
1006
-            'EE_Core_Config'                               => static function () {
1007
-                return EE_Config::instance()->core;
1008
-            },
1009
-            'EventEspresso\core\services\loaders\Loader'   => static function () {
1010
-                return LoaderFactory::getLoader();
1011
-            },
1012
-            'EE_Network_Config'                            => static function () {
1013
-                return EE_Network_Config::instance();
1014
-            },
1015
-            'EE_Config'                                    => static function () {
1016
-                return EE_Config::instance();
1017
-            },
1018
-            'EventEspresso\core\domain\Domain'             => static function () {
1019
-                return DomainFactory::getEventEspressoCoreDomain();
1020
-            },
1021
-            'EE_Admin_Config'                              => static function () {
1022
-                return EE_Config::instance()->admin;
1023
-            },
1024
-            'EE_Organization_Config'                       => static function () {
1025
-                return EE_Config::instance()->organization;
1026
-            },
1027
-            'EE_Network_Core_Config'                       => static function () {
1028
-                return EE_Network_Config::instance()->core;
1029
-            },
1030
-            'EE_Environment_Config'                        => static function () {
1031
-                return EE_Config::instance()->environment;
1032
-            },
1033
-            'EED_Core_Rest_Api'                            => static function () {
1034
-                return EED_Core_Rest_Api::instance();
1035
-            },
1036
-            'WP_REST_Server'                               => static function () {
1037
-                return rest_get_server();
1038
-            },
1039
-            'EventEspresso\core\Psr4Autoloader'            => static function () {
1040
-                return EE_Psr4AutoloaderInit::psr4_loader();
1041
-            },
1042
-            'EE_Ticket_Selector_Config'                    => function () {
1043
-                return EE_Config::instance()->template_settings->EED_Ticket_Selector;
1044
-            },
1045
-        ];
1046
-    }
1047
-
1048
-
1049
-    /**
1050
-     * can be used for supplying alternate names for classes,
1051
-     * or for connecting interface names to instantiable classes
1052
-     *
1053
-     * @throws InvalidAliasException
1054
-     */
1055
-    protected function _register_core_aliases()
1056
-    {
1057
-        $aliases = [
1058
-            'CommandBusInterface'                                                          => 'EventEspresso\core\services\commands\CommandBusInterface',
1059
-            'EventEspresso\core\services\commands\CommandBusInterface'                     => 'EventEspresso\core\services\commands\CommandBus',
1060
-            'CommandHandlerManagerInterface'                                               => 'EventEspresso\core\services\commands\CommandHandlerManagerInterface',
1061
-            'EventEspresso\core\services\commands\CommandHandlerManagerInterface'          => 'EventEspresso\core\services\commands\CommandHandlerManager',
1062
-            'CapChecker'                                                                   => 'EventEspresso\core\services\commands\middleware\CapChecker',
1063
-            'AddActionHook'                                                                => 'EventEspresso\core\services\commands\middleware\AddActionHook',
1064
-            'CapabilitiesChecker'                                                          => 'EventEspresso\core\domain\services\capabilities\CapabilitiesChecker',
1065
-            'CapabilitiesCheckerInterface'                                                 => 'EventEspresso\core\domain\services\capabilities\CapabilitiesCheckerInterface',
1066
-            'EventEspresso\core\domain\services\capabilities\CapabilitiesCheckerInterface' => 'EventEspresso\core\domain\services\capabilities\CapabilitiesChecker',
1067
-            'CreateRegistrationService'                                                    => 'EventEspresso\core\domain\services\registration\CreateRegistrationService',
1068
-            'CreateRegistrationCommandHandler'                                             => 'EventEspresso\core\domain\services\commands\registration\CreateRegistrationCommand',
1069
-            'CopyRegistrationDetailsCommandHandler'                                        => 'EventEspresso\core\domain\services\commands\registration\CopyRegistrationDetailsCommand',
1070
-            'CopyRegistrationPaymentsCommandHandler'                                       => 'EventEspresso\core\domain\services\commands\registration\CopyRegistrationPaymentsCommand',
1071
-            'CancelRegistrationAndTicketLineItemCommandHandler'                            => 'EventEspresso\core\domain\services\commands\registration\CancelRegistrationAndTicketLineItemCommandHandler',
1072
-            'UpdateRegistrationAndTransactionAfterChangeCommandHandler'                    => 'EventEspresso\core\domain\services\commands\registration\UpdateRegistrationAndTransactionAfterChangeCommandHandler',
1073
-            'CreateTicketLineItemCommandHandler'                                           => 'EventEspresso\core\domain\services\commands\ticket\CreateTicketLineItemCommand',
1074
-            'CreateTransactionCommandHandler'                                              => 'EventEspresso\core\domain\services\commands\transaction\CreateTransactionCommandHandler',
1075
-            'CreateAttendeeCommandHandler'                                                 => 'EventEspresso\core\domain\services\commands\attendee\CreateAttendeeCommandHandler',
1076
-            'TableManager'                                                                 => 'EventEspresso\core\services\database\TableManager',
1077
-            'TableAnalysis'                                                                => 'EventEspresso\core\services\database\TableAnalysis',
1078
-            'EspressoShortcode'                                                            => 'EventEspresso\core\services\shortcodes\EspressoShortcode',
1079
-            'ShortcodeInterface'                                                           => 'EventEspresso\core\services\shortcodes\ShortcodeInterface',
1080
-            'EventEspresso\core\services\shortcodes\ShortcodeInterface'                    => 'EventEspresso\core\services\shortcodes\EspressoShortcode',
1081
-            'EventEspresso\core\services\cache\CacheStorageInterface'                      => 'EventEspresso\core\services\cache\TransientCacheStorage',
1082
-            'LoaderInterface'                                                              => 'EventEspresso\core\services\loaders\LoaderInterface',
1083
-            'EventEspresso\core\services\loaders\LoaderInterface'                          => 'EventEspresso\core\services\loaders\Loader',
1084
-            'CommandFactoryInterface'                                                      => 'EventEspresso\core\services\commands\CommandFactoryInterface',
1085
-            'EventEspresso\core\services\commands\CommandFactoryInterface'                 => 'EventEspresso\core\services\commands\CommandFactory',
1086
-            'EmailValidatorInterface'                                                      => 'EventEspresso\core\domain\services\validation\email\EmailValidatorInterface',
1087
-            'EventEspresso\core\domain\services\validation\email\EmailValidatorInterface'  => 'EventEspresso\core\domain\services\validation\email\EmailValidationService',
1088
-            'NoticeConverterInterface'                                                     => 'EventEspresso\core\services\notices\NoticeConverterInterface',
1089
-            'EventEspresso\core\services\notices\NoticeConverterInterface'                 => 'EventEspresso\core\services\notices\ConvertNoticesToEeErrors',
1090
-            'NoticesContainerInterface'                                                    => 'EventEspresso\core\services\notices\NoticesContainerInterface',
1091
-            'EventEspresso\core\services\notices\NoticesContainerInterface'                => 'EventEspresso\core\services\notices\NoticesContainer',
1092
-            'EventEspresso\core\services\request\RequestInterface'                         => 'EventEspresso\core\services\request\Request',
1093
-            'EventEspresso\core\services\request\ResponseInterface'                        => 'EventEspresso\core\services\request\Response',
1094
-            'EventEspresso\core\domain\DomainInterface'                                    => 'EventEspresso\core\domain\Domain',
1095
-            'Registration_Processor'                                                       => 'EE_Registration_Processor',
1096
-            'EventEspresso\core\services\assets\AssetManifestInterface'                    => 'EventEspresso\core\services\assets\AssetManifest',
1097
-        ];
1098
-        foreach ($aliases as $alias => $fqn) {
1099
-            if (is_array($fqn)) {
1100
-                foreach ($fqn as $class => $for_class) {
1101
-                    $this->class_cache->addAlias($class, $alias, $for_class);
1102
-                }
1103
-                continue;
1104
-            }
1105
-            $this->class_cache->addAlias($fqn, $alias);
1106
-        }
1107
-        if (! (defined('DOING_AJAX') && DOING_AJAX) && is_admin()) {
1108
-            $this->class_cache->addAlias(
1109
-                'EventEspresso\core\services\notices\ConvertNoticesToAdminNotices',
1110
-                'EventEspresso\core\services\notices\NoticeConverterInterface'
1111
-            );
1112
-        }
1113
-    }
1114
-
1115
-
1116
-    public function debug($for_class = '')
1117
-    {
1118
-        if (method_exists($this->class_cache, 'debug')) {
1119
-            $this->class_cache->debug($for_class);
1120
-        }
1121
-    }
1122
-
1123
-
1124
-    /**
1125
-     * This is used to reset the internal map and class_loaders to their original default state at the beginning of the
1126
-     * request Primarily used by unit tests.
1127
-     */
1128
-    public function reset()
1129
-    {
1130
-        $this->_register_core_class_loaders();
1131
-        $this->_register_core_dependencies();
1132
-    }
1133
-
1134
-
1135
-    /**
1136
-     * PLZ NOTE: a better name for this method would be is_alias()
1137
-     * because it returns TRUE if the provided fully qualified name IS an alias
1138
-     * WHY?
1139
-     * Because if a class is type hinting for a concretion,
1140
-     * then why would we need to find another class to supply it?
1141
-     * ie: if a class asks for `Fully/Qualified/Namespace/SpecificClassName`,
1142
-     * then give it an instance of `Fully/Qualified/Namespace/SpecificClassName`.
1143
-     * Don't go looking for some substitute.
1144
-     * Whereas if a class is type hinting for an interface...
1145
-     * then we need to find an actual class to use.
1146
-     * So the interface IS the alias for some other FQN,
1147
-     * and we need to find out if `Fully/Qualified/Namespace/SomeInterface`
1148
-     * represents some other class.
1149
-     *
1150
-     * @param string $fqn
1151
-     * @param string $for_class
1152
-     * @return bool
1153
-     * @deprecated 4.9.62.p
1154
-     */
1155
-    public function has_alias(string $fqn = '', string $for_class = ''): bool
1156
-    {
1157
-        return $this->isAlias($fqn, $for_class);
1158
-    }
1159
-
1160
-
1161
-    /**
1162
-     * PLZ NOTE: a better name for this method would be get_fqn_for_alias()
1163
-     * because it returns a FQN for provided alias if one exists, otherwise returns the original $alias
1164
-     * functions recursively, so that multiple aliases can be used to drill down to a FQN
1165
-     *  for example:
1166
-     *      if the following two entries were added to the _aliases array:
1167
-     *          array(
1168
-     *              'interface_alias'           => 'some\namespace\interface'
1169
-     *              'some\namespace\interface'  => 'some\namespace\classname'
1170
-     *          )
1171
-     *      then one could use EE_Registry::instance()->create( 'interface_alias' )
1172
-     *      to load an instance of 'some\namespace\classname'
1173
-     *
1174
-     * @param string $alias
1175
-     * @param string $for_class
1176
-     * @return string
1177
-     * @deprecated 4.9.62.p
1178
-     */
1179
-    public function get_alias(string $alias = '', string $for_class = ''): string
1180
-    {
1181
-        return $this->getFqnForAlias($alias, $for_class);
1182
-    }
23
+	/**
24
+	 * This means that the requested class dependency is not present in the dependency map
25
+	 */
26
+	const not_registered = 0;
27
+
28
+	/**
29
+	 * This instructs class loaders to ALWAYS return a newly instantiated object for the requested class.
30
+	 */
31
+	const load_new_object = 1;
32
+
33
+	/**
34
+	 * This instructs class loaders to return a previously instantiated and cached object for the requested class.
35
+	 * IF a previously instantiated object does not exist, a new one will be created and added to the cache.
36
+	 */
37
+	const load_from_cache = 2;
38
+
39
+	/**
40
+	 * When registering a dependency,
41
+	 * this indicates to keep any existing dependencies that already exist,
42
+	 * and simply discard any new dependencies declared in the incoming data
43
+	 */
44
+	const KEEP_EXISTING_DEPENDENCIES = 0;
45
+
46
+	/**
47
+	 * When registering a dependency,
48
+	 * this indicates to overwrite any existing dependencies that already exist using the incoming data
49
+	 */
50
+	const OVERWRITE_DEPENDENCIES = 1;
51
+
52
+	protected static ?EE_Dependency_Map $_instance = null;
53
+
54
+	private ClassInterfaceCache $class_cache;
55
+
56
+	protected ?RequestInterface $request = null;
57
+
58
+	protected ?LegacyRequestInterface $legacy_request = null;
59
+
60
+	protected ?ResponseInterface $response = null;
61
+
62
+	protected ?LoaderInterface $loader = null;
63
+
64
+	protected array $_dependency_map = [];
65
+
66
+	protected array $_class_loaders = [];
67
+
68
+
69
+	/**
70
+	 * EE_Dependency_Map constructor.
71
+	 *
72
+	 * @param ClassInterfaceCache $class_cache
73
+	 */
74
+	protected function __construct(ClassInterfaceCache $class_cache)
75
+	{
76
+		$this->class_cache = $class_cache;
77
+		do_action('EE_Dependency_Map____construct', $this);
78
+	}
79
+
80
+
81
+	/**
82
+	 * @return void
83
+	 * @throws InvalidAliasException
84
+	 */
85
+	public function initialize()
86
+	{
87
+		$this->_register_core_dependencies();
88
+		$this->_register_core_class_loaders();
89
+		$this->_register_core_aliases();
90
+	}
91
+
92
+
93
+	/**
94
+	 * @singleton method used to instantiate class object
95
+	 * @param ClassInterfaceCache|null $class_cache
96
+	 * @return EE_Dependency_Map
97
+	 */
98
+	public static function instance(ClassInterfaceCache $class_cache = null): EE_Dependency_Map
99
+	{
100
+		// check if class object is instantiated, and instantiated properly
101
+		if (
102
+			! EE_Dependency_Map::$_instance instanceof EE_Dependency_Map
103
+			&& $class_cache instanceof ClassInterfaceCache
104
+		) {
105
+			EE_Dependency_Map::$_instance = new EE_Dependency_Map($class_cache);
106
+		}
107
+		return EE_Dependency_Map::$_instance;
108
+	}
109
+
110
+
111
+	/**
112
+	 * @param RequestInterface $request
113
+	 */
114
+	public function setRequest(RequestInterface $request)
115
+	{
116
+		$this->request = $request;
117
+	}
118
+
119
+
120
+	/**
121
+	 * @param LegacyRequestInterface $legacy_request
122
+	 */
123
+	public function setLegacyRequest(LegacyRequestInterface $legacy_request)
124
+	{
125
+		$this->legacy_request = $legacy_request;
126
+	}
127
+
128
+
129
+	/**
130
+	 * @param ResponseInterface $response
131
+	 */
132
+	public function setResponse(ResponseInterface $response)
133
+	{
134
+		$this->response = $response;
135
+	}
136
+
137
+
138
+	/**
139
+	 * @param LoaderInterface $loader
140
+	 */
141
+	public function setLoader(LoaderInterface $loader)
142
+	{
143
+		$this->loader = $loader;
144
+	}
145
+
146
+
147
+	/**
148
+	 * @param string $class
149
+	 * @param array  $dependencies
150
+	 * @param int    $overwrite
151
+	 * @return bool
152
+	 */
153
+	public static function register_dependencies(
154
+		string $class,
155
+		array $dependencies,
156
+		int $overwrite = EE_Dependency_Map::KEEP_EXISTING_DEPENDENCIES
157
+	): bool {
158
+		return EE_Dependency_Map::$_instance->registerDependencies($class, $dependencies, $overwrite);
159
+	}
160
+
161
+
162
+	/**
163
+	 * Assigns an array of class names and corresponding load sources (new or cached)
164
+	 * to the class specified by the first parameter.
165
+	 * IMPORTANT !!!
166
+	 * The order of elements in the incoming $dependencies array MUST match
167
+	 * the order of the constructor parameters for the class in question.
168
+	 * This is especially important when overriding any existing dependencies that are registered.
169
+	 * the third parameter controls whether any duplicate dependencies are overwritten or not.
170
+	 *
171
+	 * @param string $class
172
+	 * @param array  $dependencies
173
+	 * @param int    $overwrite
174
+	 * @return bool
175
+	 */
176
+	public function registerDependencies(
177
+		string $class,
178
+		array $dependencies,
179
+		int $overwrite = EE_Dependency_Map::KEEP_EXISTING_DEPENDENCIES
180
+	): bool {
181
+		if (empty($dependencies)) {
182
+			return false;
183
+		}
184
+		$class      = trim($class, '\\');
185
+		$registered = false;
186
+		if (empty(EE_Dependency_Map::$_instance->_dependency_map[ $class ])) {
187
+			EE_Dependency_Map::$_instance->_dependency_map[ $class ] = [];
188
+		}
189
+		// we need to make sure that any aliases used when registering a dependency
190
+		// get resolved to the correct class name
191
+		foreach ($dependencies as $dependency => $load_source) {
192
+			$alias = EE_Dependency_Map::$_instance->getFqnForAlias($dependency);
193
+			if (
194
+				$overwrite === EE_Dependency_Map::OVERWRITE_DEPENDENCIES
195
+				|| ! isset(
196
+					EE_Dependency_Map::$_instance->_dependency_map[ $class ][ $dependency ],
197
+					EE_Dependency_Map::$_instance->_dependency_map[ $class ][ $alias ]
198
+				)
199
+			) {
200
+				unset($dependencies[ $dependency ]);
201
+				$dependencies[ $alias ] = $load_source;
202
+				$registered             = true;
203
+			}
204
+		}
205
+		// now add our two lists of dependencies together.
206
+		// using Union (+=) favours the arrays in precedence from left to right,
207
+		// so $dependencies is NOT overwritten because it is listed first
208
+		// ie: with A = B + C, entries in B take precedence over duplicate entries in C
209
+		// Union is way faster than array_merge() but should be used with caution...
210
+		// especially with numerically indexed arrays
211
+		$dependencies += EE_Dependency_Map::$_instance->_dependency_map[ $class ];
212
+		// now we need to ensure that the resulting dependencies
213
+		// array only has the entries that are required for the class
214
+		// so first count how many dependencies were originally registered for the class
215
+		$dependency_count = count(EE_Dependency_Map::$_instance->_dependency_map[ $class ]);
216
+		// if that count is non-zero (meaning dependencies were already registered)
217
+		EE_Dependency_Map::$_instance->_dependency_map[ $class ] = $dependency_count
218
+			// then truncate the  final array to match that count
219
+			? array_slice($dependencies, 0, $dependency_count)
220
+			// otherwise just take the incoming array because nothing previously existed
221
+			: $dependencies;
222
+		return $registered
223
+			|| count(EE_Dependency_Map::$_instance->_dependency_map[ $class ]) === count($dependencies);
224
+	}
225
+
226
+
227
+	/**
228
+	 * @param string          $class_name
229
+	 * @param callable|string $loader
230
+	 * @param bool            $overwrite
231
+	 * @return bool
232
+	 * @throws DomainException
233
+	 */
234
+	public static function register_class_loader(
235
+		string $class_name,
236
+		$loader = 'load_core',
237
+		bool $overwrite = false
238
+	): bool {
239
+		return EE_Dependency_Map::$_instance->registerClassLoader($class_name, $loader, $overwrite);
240
+	}
241
+
242
+
243
+	/**
244
+	 * @param string         $class_name
245
+	 * @param Closure|string $loader
246
+	 * @param bool           $overwrite
247
+	 * @return bool
248
+	 * @throws DomainException
249
+	 */
250
+	public function registerClassLoader(string $class_name, $loader = 'load_core', bool $overwrite = false): bool
251
+	{
252
+		if (! $loader instanceof Closure && strpos($class_name, '\\') !== false) {
253
+			throw new DomainException(
254
+				esc_html__('Don\'t use class loaders for FQCNs.', 'event_espresso')
255
+			);
256
+		}
257
+		// check that loader is callable or method starts with "load_" and exists in EE_Registry
258
+		if (
259
+			! is_callable($loader)
260
+			&& (
261
+				strpos($loader, 'load_') !== 0
262
+				|| ! method_exists('EE_Registry', $loader)
263
+			)
264
+		) {
265
+			throw new DomainException(
266
+				sprintf(
267
+					esc_html__(
268
+						'"%1$s" is not a valid loader method on EE_Registry.',
269
+						'event_espresso'
270
+					),
271
+					$loader
272
+				)
273
+			);
274
+		}
275
+		$class_name = EE_Dependency_Map::$_instance->getFqnForAlias($class_name);
276
+		if ($overwrite || ! isset(EE_Dependency_Map::$_instance->_class_loaders[ $class_name ])) {
277
+			EE_Dependency_Map::$_instance->_class_loaders[ $class_name ] = $loader;
278
+			return true;
279
+		}
280
+		return false;
281
+	}
282
+
283
+
284
+	/**
285
+	 * @return array
286
+	 */
287
+	public function dependency_map(): array
288
+	{
289
+		return $this->_dependency_map;
290
+	}
291
+
292
+
293
+	/**
294
+	 * returns TRUE if dependency map contains a listing for the provided class name
295
+	 *
296
+	 * @param string $class_name
297
+	 * @return boolean
298
+	 */
299
+	public function has(string $class_name = ''): bool
300
+	{
301
+		// all legacy models have the same dependencies
302
+		if (strpos($class_name, 'EEM_') === 0) {
303
+			$class_name = 'LEGACY_MODELS';
304
+		}
305
+		return isset($this->_dependency_map[ $class_name ]);
306
+	}
307
+
308
+
309
+	/**
310
+	 * returns TRUE if dependency map contains a listing for the provided class name AND dependency
311
+	 *
312
+	 * @param string $class_name
313
+	 * @param string $dependency
314
+	 * @return bool
315
+	 */
316
+	public function has_dependency_for_class(string $class_name = '', string $dependency = ''): bool
317
+	{
318
+		// all legacy models have the same dependencies
319
+		if (strpos($class_name, 'EEM_') === 0) {
320
+			$class_name = 'LEGACY_MODELS';
321
+		}
322
+		$dependency = $this->getFqnForAlias($dependency, $class_name);
323
+		return isset($this->_dependency_map[ $class_name ][ $dependency ]);
324
+	}
325
+
326
+
327
+	/**
328
+	 * returns loading strategy for whether a previously cached dependency should be loaded or a new instance returned
329
+	 *
330
+	 * @param string $class_name
331
+	 * @param string $dependency
332
+	 * @return int
333
+	 */
334
+	public function loading_strategy_for_class_dependency(string $class_name = '', string $dependency = ''): int
335
+	{
336
+		// all legacy models have the same dependencies
337
+		if (strpos($class_name, 'EEM_') === 0) {
338
+			$class_name = 'LEGACY_MODELS';
339
+		}
340
+		$dependency = $this->getFqnForAlias($dependency);
341
+		return $this->has_dependency_for_class($class_name, $dependency)
342
+			? $this->_dependency_map[ $class_name ][ $dependency ]
343
+			: EE_Dependency_Map::not_registered;
344
+	}
345
+
346
+
347
+	/**
348
+	 * @param string $class_name
349
+	 * @return string | Closure
350
+	 */
351
+	public function class_loader(string $class_name)
352
+	{
353
+		// all legacy models use load_model()
354
+		if (strpos($class_name, 'EEM_') === 0) {
355
+			return 'load_model';
356
+		}
357
+		// EE_CPT_*_Strategy classes like EE_CPT_Event_Strategy, EE_CPT_Venue_Strategy, etc
358
+		// perform strpos() first to avoid loading regex every time we load a class
359
+		if (
360
+			strpos($class_name, 'EE_CPT_') === 0
361
+			&& preg_match('/^EE_CPT_([a-zA-Z]+)_Strategy$/', $class_name)
362
+		) {
363
+			return 'load_core';
364
+		}
365
+		$class_name = $this->getFqnForAlias($class_name);
366
+		return $this->_class_loaders[ $class_name ] ?? '';
367
+	}
368
+
369
+
370
+	/**
371
+	 * @return array
372
+	 */
373
+	public function class_loaders(): array
374
+	{
375
+		return $this->_class_loaders;
376
+	}
377
+
378
+
379
+	/**
380
+	 * adds an alias for a classname
381
+	 *
382
+	 * @param string $fqcn      the class name that should be used (concrete class to replace interface)
383
+	 * @param string $alias     the class name that would be type hinted for (abstract parent or interface)
384
+	 * @param string $for_class the class that has the dependency (is type hinting for the interface)
385
+	 * @throws InvalidAliasException
386
+	 */
387
+	public function add_alias(string $fqcn, string $alias, string $for_class = '')
388
+	{
389
+		$this->class_cache->addAlias($fqcn, $alias, $for_class);
390
+	}
391
+
392
+
393
+	/**
394
+	 * Returns TRUE if the provided fully qualified name IS an alias
395
+	 * WHY?
396
+	 * Because if a class is type hinting for a concretion,
397
+	 * then why would we need to find another class to supply it?
398
+	 * ie: if a class asks for `Fully/Qualified/Namespace/SpecificClassName`,
399
+	 * then give it an instance of `Fully/Qualified/Namespace/SpecificClassName`.
400
+	 * Don't go looking for some substitute.
401
+	 * Whereas if a class is type hinting for an interface...
402
+	 * then we need to find an actual class to use.
403
+	 * So the interface IS the alias for some other FQN,
404
+	 * and we need to find out if `Fully/Qualified/Namespace/SomeInterface`
405
+	 * represents some other class.
406
+	 *
407
+	 * @param string $fqn
408
+	 * @param string $for_class
409
+	 * @return bool
410
+	 */
411
+	public function isAlias(string $fqn = '', string $for_class = ''): bool
412
+	{
413
+		return $this->class_cache->isAlias($fqn, $for_class);
414
+	}
415
+
416
+
417
+	/**
418
+	 * Returns a FQN for provided alias if one exists, otherwise returns the original $alias
419
+	 * functions recursively, so that multiple aliases can be used to drill down to a FQN
420
+	 *  for example:
421
+	 *      if the following two entries were added to the _aliases array:
422
+	 *          array(
423
+	 *              'interface_alias'           => 'some\namespace\interface'
424
+	 *              'some\namespace\interface'  => 'some\namespace\classname'
425
+	 *          )
426
+	 *      then one could use EE_Registry::instance()->create( 'interface_alias' )
427
+	 *      to load an instance of 'some\namespace\classname'
428
+	 *
429
+	 * @param string $alias
430
+	 * @param string $for_class
431
+	 * @return string
432
+	 */
433
+	public function getFqnForAlias(string $alias = '', string $for_class = ''): string
434
+	{
435
+		return $this->class_cache->getFqnForAlias($alias, $for_class);
436
+	}
437
+
438
+
439
+	/**
440
+	 * Registers the core dependencies and whether a previously instantiated object should be loaded from the cache,
441
+	 * if one exists, or whether a new object should be generated every time the requested class is loaded.
442
+	 * This is done by using the following class constants:
443
+	 *        EE_Dependency_Map::load_from_cache - loads previously instantiated object
444
+	 *        EE_Dependency_Map::load_new_object - generates a new object every time
445
+	 */
446
+	protected function _register_core_dependencies()
447
+	{
448
+		$this->_dependency_map = [
449
+			'EE_Admin'                                                                                                           => [
450
+				'EventEspresso\core\services\loaders\Loader'  => EE_Dependency_Map::load_from_cache,
451
+				'EventEspresso\core\services\request\Request' => EE_Dependency_Map::load_from_cache,
452
+			],
453
+			'EE_Maintenance_Mode'                                                                                                => [
454
+				'EventEspresso\core\services\loaders\Loader'  => EE_Dependency_Map::load_from_cache,
455
+				'EventEspresso\core\services\request\Request' => EE_Dependency_Map::load_from_cache,
456
+			],
457
+			'EE_Request_Handler'                                                                                                 => [
458
+				'EventEspresso\core\services\request\Request'  => EE_Dependency_Map::load_from_cache,
459
+				'EventEspresso\core\services\request\Response' => EE_Dependency_Map::load_from_cache,
460
+			],
461
+			'EE_System'                                                                                                   => [
462
+				'EventEspresso\core\services\loaders\Loader'                   => EE_Dependency_Map::load_from_cache,
463
+				'EE_Maintenance_Mode'                                          => EE_Dependency_Map::load_from_cache,
464
+				'EE_Registry'                                                  => EE_Dependency_Map::load_from_cache,
465
+				'EventEspresso\core\services\request\Request'                  => EE_Dependency_Map::load_from_cache,
466
+				'EventEspresso\core\services\routing\Router'                   => EE_Dependency_Map::load_from_cache,
467
+				'EventEspresso\core\domain\services\capabilities\FeatureFlags' => EE_Dependency_Map::load_from_cache,
468
+			],
469
+			'EE_Session'                                                                                                         => [
470
+				'EventEspresso\core\services\cache\TransientCacheStorage'  => EE_Dependency_Map::load_from_cache,
471
+				'EventEspresso\core\domain\values\session\SessionLifespan' => EE_Dependency_Map::load_from_cache,
472
+				'EventEspresso\core\services\request\Request'              => EE_Dependency_Map::load_from_cache,
473
+				'EventEspresso\core\services\session\SessionStartHandler'  => EE_Dependency_Map::load_from_cache,
474
+				'EventEspresso\core\services\encryption\Base64Encoder'     => EE_Dependency_Map::load_from_cache,
475
+			],
476
+			'EventEspresso\core\services\session\SessionStartHandler'                                                            => [
477
+				'EventEspresso\core\services\request\Request' => EE_Dependency_Map::load_from_cache,
478
+			],
479
+			'EE_Cart'                                                                                                            => [
480
+				'EE_Session' => EE_Dependency_Map::load_from_cache,
481
+			],
482
+			'EE_Messenger_Collection_Loader'                                                                                     => [
483
+				'EE_Messenger_Collection' => EE_Dependency_Map::load_new_object,
484
+			],
485
+			'EE_Message_Type_Collection_Loader'                                                                                  => [
486
+				'EE_Message_Type_Collection' => EE_Dependency_Map::load_new_object,
487
+			],
488
+			'EE_Message_Resource_Manager'                                                                                        => [
489
+				'EE_Messenger_Collection_Loader'    => EE_Dependency_Map::load_new_object,
490
+				'EE_Message_Type_Collection_Loader' => EE_Dependency_Map::load_new_object,
491
+				'EEM_Message_Template_Group'        => EE_Dependency_Map::load_from_cache,
492
+			],
493
+			'EE_Message_Factory'                                                                                                 => [
494
+				'EE_Message_Resource_Manager' => EE_Dependency_Map::load_from_cache,
495
+			],
496
+			'EE_messages'                                                                                                        => [
497
+				'EE_Message_Resource_Manager' => EE_Dependency_Map::load_from_cache,
498
+			],
499
+			'EE_Messages_Generator'                                                                                              => [
500
+				'EE_Messages_Queue'                    => EE_Dependency_Map::load_new_object,
501
+				'EE_Messages_Data_Handler_Collection'  => EE_Dependency_Map::load_new_object,
502
+				'EE_Message_Template_Group_Collection' => EE_Dependency_Map::load_new_object,
503
+				'EEH_Parse_Shortcodes'                 => EE_Dependency_Map::load_from_cache,
504
+			],
505
+			'EE_Messages_Processor'                                                                                              => [
506
+				'EE_Message_Resource_Manager' => EE_Dependency_Map::load_from_cache,
507
+			],
508
+			'EE_Messages_Queue'                                                                                                  => [
509
+				'EE_Message_Repository' => EE_Dependency_Map::load_new_object,
510
+			],
511
+			'EE_Messages_Template_Defaults'                                                                                      => [
512
+				'EEM_Message_Template_Group' => EE_Dependency_Map::load_from_cache,
513
+				'EEM_Message_Template'       => EE_Dependency_Map::load_from_cache,
514
+			],
515
+			'EE_Message_To_Generate_From_Request'                                                                                => [
516
+				'EE_Message_Resource_Manager'                 => EE_Dependency_Map::load_from_cache,
517
+				'EventEspresso\core\services\request\Request' => EE_Dependency_Map::load_from_cache,
518
+			],
519
+			'EventEspresso\core\services\commands\CommandBus'                                                                    => [
520
+				'EventEspresso\core\services\commands\CommandHandlerManager' => EE_Dependency_Map::load_from_cache,
521
+			],
522
+			'EventEspresso\services\commands\CommandHandler'                                                                     => [
523
+				'EE_Registry'         => EE_Dependency_Map::load_from_cache,
524
+				'CommandBusInterface' => EE_Dependency_Map::load_from_cache,
525
+			],
526
+			'EventEspresso\core\services\commands\CommandHandlerManager'                                                         => [
527
+				'EventEspresso\core\services\loaders\Loader' => EE_Dependency_Map::load_from_cache,
528
+			],
529
+			'EventEspresso\core\services\commands\CompositeCommandHandler'                                                       => [
530
+				'EventEspresso\core\services\commands\CommandBus'     => EE_Dependency_Map::load_from_cache,
531
+				'EventEspresso\core\services\commands\CommandFactory' => EE_Dependency_Map::load_from_cache,
532
+			],
533
+			'EventEspresso\core\services\commands\CommandFactory'                                                                => [
534
+				'EventEspresso\core\services\loaders\Loader' => EE_Dependency_Map::load_from_cache,
535
+			],
536
+			'EventEspresso\core\services\commands\middleware\CapChecker'                                                         => [
537
+				'EventEspresso\core\domain\services\capabilities\CapabilitiesChecker' => EE_Dependency_Map::load_from_cache,
538
+			],
539
+			'EventEspresso\core\domain\services\capabilities\CapabilitiesChecker'                                                => [
540
+				'EE_Capabilities' => EE_Dependency_Map::load_from_cache,
541
+			],
542
+			'EventEspresso\core\domain\services\capabilities\RegistrationsCapChecker'                                            => [
543
+				'EE_Capabilities' => EE_Dependency_Map::load_from_cache,
544
+			],
545
+			'EventEspresso\core\domain\services\commands\registration\CreateRegistrationCommandHandler'                          => [
546
+				'EventEspresso\core\domain\services\registration\CreateRegistrationService' => EE_Dependency_Map::load_from_cache,
547
+			],
548
+			'EventEspresso\core\domain\services\commands\registration\CopyRegistrationDetailsCommandHandler'                     => [
549
+				'EventEspresso\core\domain\services\registration\CopyRegistrationService' => EE_Dependency_Map::load_from_cache,
550
+			],
551
+			'EventEspresso\core\domain\services\commands\registration\CopyRegistrationPaymentsCommandHandler'                    => [
552
+				'EventEspresso\core\domain\services\registration\CopyRegistrationService' => EE_Dependency_Map::load_from_cache,
553
+			],
554
+			'EventEspresso\core\domain\services\commands\registration\CancelRegistrationAndTicketLineItemCommandHandler'         => [
555
+				'EventEspresso\core\domain\services\registration\CancelTicketLineItemService' => EE_Dependency_Map::load_from_cache,
556
+			],
557
+			'EventEspresso\core\domain\services\commands\registration\UpdateRegistrationAndTransactionAfterChangeCommandHandler' => [
558
+				'EventEspresso\core\domain\services\registration\UpdateRegistrationService' => EE_Dependency_Map::load_from_cache,
559
+			],
560
+			'EventEspresso\core\domain\services\commands\ticket\CreateTicketLineItemCommandHandler'                              => [
561
+				'EventEspresso\core\domain\services\ticket\CreateTicketLineItemService' => EE_Dependency_Map::load_from_cache,
562
+			],
563
+			'EventEspresso\core\domain\services\commands\ticket\CancelTicketLineItemCommandHandler'                              => [
564
+				'EventEspresso\core\domain\services\ticket\CancelTicketLineItemService' => EE_Dependency_Map::load_from_cache,
565
+			],
566
+			'EventEspresso\core\domain\services\registration\CancelRegistrationService'                                          => [
567
+				'EventEspresso\core\domain\services\ticket\CancelTicketLineItemService' => EE_Dependency_Map::load_from_cache,
568
+			],
569
+			'EventEspresso\core\domain\services\commands\attendee\CreateAttendeeCommandHandler'                                  => [
570
+				'EEM_Attendee' => EE_Dependency_Map::load_from_cache,
571
+			],
572
+			'EventEspresso\core\domain\values\session\SessionLifespan'                                                           => [
573
+				'EventEspresso\core\domain\values\session\SessionLifespanOption' => EE_Dependency_Map::load_from_cache,
574
+			],
575
+			'EventEspresso\caffeinated\admin\extend\registration_form\forms\SessionLifespanForm'                                 => [
576
+				'EventEspresso\core\domain\values\session\SessionLifespanOption' => EE_Dependency_Map::load_from_cache,
577
+				'EE_Registration_Config'                                         => EE_Dependency_Map::load_from_cache,
578
+			],
579
+			'EventEspresso\caffeinated\admin\extend\registration_form\forms\SessionLifespanFormHandler'                          => [
580
+				'EventEspresso\core\domain\values\session\SessionLifespanOption' => EE_Dependency_Map::load_from_cache,
581
+				'EE_Config'                                                      => EE_Dependency_Map::load_from_cache,
582
+			],
583
+			'EventEspresso\core\services\database\TableManager'                                                                  => [
584
+				'EventEspresso\core\services\database\TableAnalysis' => EE_Dependency_Map::load_from_cache,
585
+			],
586
+			'EE_Data_Migration_Class_Base'                                                                                       => [
587
+				'EventEspresso\core\services\database\TableAnalysis' => EE_Dependency_Map::load_from_cache,
588
+				'EventEspresso\core\services\database\TableManager'  => EE_Dependency_Map::load_from_cache,
589
+			],
590
+			'EE_DMS_Core_4_1_0'                                                                                                  => [
591
+				'EventEspresso\core\services\database\TableAnalysis' => EE_Dependency_Map::load_from_cache,
592
+				'EventEspresso\core\services\database\TableManager'  => EE_Dependency_Map::load_from_cache,
593
+			],
594
+			'EE_DMS_Core_4_2_0'                                                                                                  => [
595
+				'EventEspresso\core\services\database\TableAnalysis' => EE_Dependency_Map::load_from_cache,
596
+				'EventEspresso\core\services\database\TableManager'  => EE_Dependency_Map::load_from_cache,
597
+			],
598
+			'EE_DMS_Core_4_3_0'                                                                                                  => [
599
+				'EventEspresso\core\services\database\TableAnalysis' => EE_Dependency_Map::load_from_cache,
600
+				'EventEspresso\core\services\database\TableManager'  => EE_Dependency_Map::load_from_cache,
601
+			],
602
+			'EE_DMS_Core_4_4_0'                                                                                                  => [
603
+				'EventEspresso\core\services\database\TableAnalysis' => EE_Dependency_Map::load_from_cache,
604
+				'EventEspresso\core\services\database\TableManager'  => EE_Dependency_Map::load_from_cache,
605
+			],
606
+			'EE_DMS_Core_4_5_0'                                                                                                  => [
607
+				'EventEspresso\core\services\database\TableAnalysis' => EE_Dependency_Map::load_from_cache,
608
+				'EventEspresso\core\services\database\TableManager'  => EE_Dependency_Map::load_from_cache,
609
+			],
610
+			'EE_DMS_Core_4_6_0'                                                                                                  => [
611
+				'EventEspresso\core\services\database\TableAnalysis' => EE_Dependency_Map::load_from_cache,
612
+				'EventEspresso\core\services\database\TableManager'  => EE_Dependency_Map::load_from_cache,
613
+			],
614
+			'EE_DMS_Core_4_7_0'                                                                                                  => [
615
+				'EventEspresso\core\services\database\TableAnalysis' => EE_Dependency_Map::load_from_cache,
616
+				'EventEspresso\core\services\database\TableManager'  => EE_Dependency_Map::load_from_cache,
617
+			],
618
+			'EE_DMS_Core_4_8_0'                                                                                                  => [
619
+				'EventEspresso\core\services\database\TableAnalysis' => EE_Dependency_Map::load_from_cache,
620
+				'EventEspresso\core\services\database\TableManager'  => EE_Dependency_Map::load_from_cache,
621
+			],
622
+			'EE_DMS_Core_4_9_0'                                                                                                  => [
623
+				'EventEspresso\core\services\database\TableAnalysis' => EE_Dependency_Map::load_from_cache,
624
+				'EventEspresso\core\services\database\TableManager'  => EE_Dependency_Map::load_from_cache,
625
+			],
626
+			'EE_DMS_Core_4_10_0'                                                                                                 => [
627
+				'EventEspresso\core\services\database\TableAnalysis' => EE_Dependency_Map::load_from_cache,
628
+				'EventEspresso\core\services\database\TableManager'  => EE_Dependency_Map::load_from_cache,
629
+				'EE_DMS_Core_4_9_0'                                  => EE_Dependency_Map::load_from_cache,
630
+			],
631
+			'EE_DMS_Core_5_0_0'                                                                                                  => [
632
+				'EE_DMS_Core_4_10_0'                                 => EE_Dependency_Map::load_from_cache,
633
+				'EventEspresso\core\services\database\TableAnalysis' => EE_Dependency_Map::load_from_cache,
634
+				'EventEspresso\core\services\database\TableManager'  => EE_Dependency_Map::load_from_cache,
635
+			],
636
+			'EventEspresso\core\services\assets\I18nRegistry'                                                                    => [
637
+				'EventEspresso\core\domain\Domain' => EE_Dependency_Map::load_from_cache,
638
+			],
639
+			'EventEspresso\core\services\assets\Registry'                                                                        => [
640
+				'EventEspresso\core\services\assets\AssetCollection' => EE_Dependency_Map::load_from_cache,
641
+				'EventEspresso\core\services\assets\AssetManifest'   => EE_Dependency_Map::load_from_cache,
642
+			],
643
+			'EventEspresso\core\domain\entities\shortcodes\EspressoCancelled'                                                    => [
644
+				'EventEspresso\core\services\cache\PostRelatedCacheManager' => EE_Dependency_Map::load_from_cache,
645
+			],
646
+			'EventEspresso\core\domain\entities\shortcodes\EspressoCheckout'                                                     => [
647
+				'EventEspresso\core\services\cache\PostRelatedCacheManager' => EE_Dependency_Map::load_from_cache,
648
+			],
649
+			'EventEspresso\core\domain\entities\shortcodes\EspressoEventAttendees'                                               => [
650
+				'EventEspresso\core\services\cache\PostRelatedCacheManager' => EE_Dependency_Map::load_from_cache,
651
+			],
652
+			'EventEspresso\core\domain\entities\shortcodes\EspressoEvents'                                                       => [
653
+				'EventEspresso\core\services\cache\PostRelatedCacheManager' => EE_Dependency_Map::load_from_cache,
654
+			],
655
+			'EventEspresso\core\domain\entities\shortcodes\EspressoThankYou'                                                     => [
656
+				'EventEspresso\core\services\cache\PostRelatedCacheManager' => EE_Dependency_Map::load_from_cache,
657
+			],
658
+			'EventEspresso\core\domain\entities\shortcodes\EspressoTicketSelector'                                               => [
659
+				'EventEspresso\core\services\cache\PostRelatedCacheManager' => EE_Dependency_Map::load_from_cache,
660
+			],
661
+			'EventEspresso\core\domain\entities\shortcodes\EspressoTxnPage'                                                      => [
662
+				'EventEspresso\core\services\cache\PostRelatedCacheManager' => EE_Dependency_Map::load_from_cache,
663
+			],
664
+			'EventEspresso\core\services\cache\BasicCacheManager'                                                                => [
665
+				'EventEspresso\core\services\cache\TransientCacheStorage' => EE_Dependency_Map::load_from_cache,
666
+			],
667
+			'EventEspresso\core\services\cache\PostRelatedCacheManager'                                                          => [
668
+				'EventEspresso\core\services\cache\TransientCacheStorage' => EE_Dependency_Map::load_from_cache,
669
+			],
670
+			'EventEspresso\core\domain\services\validation\email\EmailValidationService'                                         => [
671
+				'EE_Registration_Config'                     => EE_Dependency_Map::load_from_cache,
672
+				'EventEspresso\core\services\loaders\Loader' => EE_Dependency_Map::load_from_cache,
673
+			],
674
+			'EventEspresso\core\domain\values\EmailAddress'                                                                      => [
675
+				null,
676
+				'EventEspresso\core\domain\services\validation\email\EmailValidationService' => EE_Dependency_Map::load_from_cache,
677
+			],
678
+			'EventEspresso\core\services\orm\ModelFieldFactory'                                                                  => [
679
+				'EventEspresso\core\services\loaders\Loader' => EE_Dependency_Map::load_from_cache,
680
+			],
681
+			'LEGACY_MODELS'                                                                                                      => [
682
+				null,
683
+				'EventEspresso\core\services\database\ModelFieldFactory' => EE_Dependency_Map::load_from_cache,
684
+			],
685
+			'EE_Module_Request_Router'                                                                                           => [
686
+				'EventEspresso\core\services\request\Request' => EE_Dependency_Map::load_from_cache,
687
+			],
688
+			'EE_Registration_Processor'                                                                                          => [
689
+				'EventEspresso\core\services\request\Request' => EE_Dependency_Map::load_from_cache,
690
+			],
691
+			'EventEspresso\core\services\notifications\PersistentAdminNoticeManager'                                             => [
692
+				'EventEspresso\core\domain\services\capabilities\CapabilitiesChecker' => EE_Dependency_Map::load_from_cache,
693
+				'EventEspresso\core\services\request\Request'                         => EE_Dependency_Map::load_from_cache,
694
+			],
695
+			'EventEspresso\caffeinated\modules\recaptcha_invisible\InvisibleRecaptcha'                                           => [
696
+				'EE_Registration_Config' => EE_Dependency_Map::load_from_cache,
697
+				'EE_Session'             => EE_Dependency_Map::load_from_cache,
698
+			],
699
+			'EventEspresso\modules\ticket_selector\DisplayTicketSelector'                                                        => [
700
+				'EventEspresso\core\domain\entities\users\CurrentUser' => EE_Dependency_Map::load_from_cache,
701
+				'EventEspresso\core\services\request\Request'          => EE_Dependency_Map::load_from_cache,
702
+				'EE_Ticket_Selector_Config'                            => EE_Dependency_Map::load_from_cache,
703
+			],
704
+			'EventEspresso\modules\ticket_selector\ProcessTicketSelector'                                                        => [
705
+				'EE_Core_Config'                                                          => EE_Dependency_Map::load_from_cache,
706
+				'EventEspresso\core\services\request\Request'                             => EE_Dependency_Map::load_from_cache,
707
+				'EE_Session'                                                              => EE_Dependency_Map::load_from_cache,
708
+				'EEM_Ticket'                                                              => EE_Dependency_Map::load_from_cache,
709
+				'EventEspresso\modules\ticket_selector\TicketDatetimeAvailabilityTracker' => EE_Dependency_Map::load_from_cache,
710
+			],
711
+			'EventEspresso\modules\ticket_selector\ProcessTicketSelectorPostData'                                                => [
712
+				'EventEspresso\core\services\request\Request' => EE_Dependency_Map::load_from_cache,
713
+				'EEM_Event'                                   => EE_Dependency_Map::load_from_cache,
714
+			],
715
+			'EventEspresso\modules\ticket_selector\TicketDatetimeAvailabilityTracker'                                            => [
716
+				'EEM_Datetime' => EE_Dependency_Map::load_from_cache,
717
+			],
718
+			'EventEspresso\core\domain\entities\custom_post_types\CustomPostTypeDefinitions'                                     => [
719
+				'EE_Core_Config'                             => EE_Dependency_Map::load_from_cache,
720
+				'EventEspresso\core\services\loaders\Loader' => EE_Dependency_Map::load_from_cache,
721
+			],
722
+			'EventEspresso\core\domain\services\custom_post_types\RegisterCustomPostTypes'                                       => [
723
+				'EventEspresso\core\domain\entities\custom_post_types\CustomPostTypeDefinitions' => EE_Dependency_Map::load_from_cache,
724
+			],
725
+			'EventEspresso\core\domain\services\custom_post_types\RegisterCustomTaxonomies'                                      => [
726
+				'EventEspresso\core\domain\entities\custom_post_types\CustomTaxonomyDefinitions' => EE_Dependency_Map::load_from_cache,
727
+			],
728
+			'EE_CPT_Strategy'                                                                                                    => [
729
+				'EventEspresso\core\domain\entities\custom_post_types\CustomPostTypeDefinitions' => EE_Dependency_Map::load_from_cache,
730
+				'EventEspresso\core\domain\entities\custom_post_types\CustomTaxonomyDefinitions' => EE_Dependency_Map::load_from_cache,
731
+			],
732
+			'EventEspresso\core\services\loaders\ObjectIdentifier'                                                               => [
733
+				'EventEspresso\core\services\loaders\ClassInterfaceCache' => EE_Dependency_Map::load_from_cache,
734
+			],
735
+			'EventEspresso\core\CPTs\CptQueryModifier'                                                                           => [
736
+				null,
737
+				null,
738
+				null,
739
+				'EventEspresso\core\services\request\CurrentPage' => EE_Dependency_Map::load_from_cache,
740
+				'EventEspresso\core\services\request\Request'     => EE_Dependency_Map::load_from_cache,
741
+				'EventEspresso\core\services\loaders\Loader'      => EE_Dependency_Map::load_from_cache,
742
+			],
743
+			'EventEspresso\core\services\dependencies\DependencyResolver'                                                        => [
744
+				'EventEspresso\core\services\container\Mirror'            => EE_Dependency_Map::load_from_cache,
745
+				'EventEspresso\core\services\loaders\ClassInterfaceCache' => EE_Dependency_Map::load_from_cache,
746
+				'EE_Dependency_Map'                                       => EE_Dependency_Map::load_from_cache,
747
+			],
748
+			'EventEspresso\core\services\routing\RouteMatchSpecificationDependencyResolver'                                      => [
749
+				'EventEspresso\core\services\container\Mirror'            => EE_Dependency_Map::load_from_cache,
750
+				'EventEspresso\core\services\loaders\ClassInterfaceCache' => EE_Dependency_Map::load_from_cache,
751
+				'EE_Dependency_Map'                                       => EE_Dependency_Map::load_from_cache,
752
+			],
753
+			'EventEspresso\core\services\routing\RouteMatchSpecificationFactory'                                                 => [
754
+				'EventEspresso\core\services\routing\RouteMatchSpecificationDependencyResolver' => EE_Dependency_Map::load_from_cache,
755
+				'EventEspresso\core\services\loaders\Loader'                                    => EE_Dependency_Map::load_from_cache,
756
+			],
757
+			'EventEspresso\core\services\routing\RouteMatchSpecificationManager'                                                 => [
758
+				'EventEspresso\core\services\routing\RouteMatchSpecificationCollection' => EE_Dependency_Map::load_from_cache,
759
+				'EventEspresso\core\services\routing\RouteMatchSpecificationFactory'    => EE_Dependency_Map::load_from_cache,
760
+			],
761
+			'EventEspresso\core\services\request\files\FilesDataHandler'                                                         => [
762
+				'EventEspresso\core\services\request\Request' => EE_Dependency_Map::load_from_cache,
763
+			],
764
+			'EventEspresso\core\libraries\batch\BatchRequestProcessor'                                                           => [
765
+				'EventEspresso\core\services\loaders\Loader'  => EE_Dependency_Map::load_from_cache,
766
+				'EventEspresso\core\services\request\Request' => EE_Dependency_Map::load_from_cache,
767
+			],
768
+			'EventEspresso\core\domain\services\converters\RestApiSpoofer'                                                       => [
769
+				'WP_REST_Server'                                               => EE_Dependency_Map::load_from_cache,
770
+				'EED_Core_Rest_Api'                                            => EE_Dependency_Map::load_from_cache,
771
+				'EventEspresso\core\libraries\rest_api\controllers\model\Read' => EE_Dependency_Map::load_from_cache,
772
+				null,
773
+			],
774
+			'EventEspresso\core\services\routing\RouteHandler'                                                                   => [
775
+				'EventEspresso\core\domain\services\capabilities\CapabilitiesChecker' => EE_Dependency_Map::load_from_cache,
776
+				'EventEspresso\core\services\json\JsonDataNodeHandler'                => EE_Dependency_Map::load_from_cache,
777
+				'EventEspresso\core\services\loaders\Loader'                          => EE_Dependency_Map::load_from_cache,
778
+				'EventEspresso\core\services\request\Request'                         => EE_Dependency_Map::load_from_cache,
779
+				'EventEspresso\core\services\routing\RouteCollection'                 => EE_Dependency_Map::load_from_cache,
780
+			],
781
+			'EventEspresso\core\services\json\JsonDataNodeHandler'                                                               => [
782
+				'EventEspresso\core\services\json\JsonDataNodeValidator' => EE_Dependency_Map::load_from_cache,
783
+			],
784
+			'EventEspresso\core\services\routing\Router'                                                                         => [
785
+				'EE_Dependency_Map'                                => EE_Dependency_Map::load_from_cache,
786
+				'EventEspresso\core\services\loaders\Loader'       => EE_Dependency_Map::load_from_cache,
787
+				'EventEspresso\core\services\routing\RouteHandler' => EE_Dependency_Map::load_from_cache,
788
+			],
789
+			'EventEspresso\core\services\assets\AssetManifest'                                                                   => [
790
+				'EventEspresso\core\domain\Domain' => EE_Dependency_Map::load_from_cache,
791
+			],
792
+			'EventEspresso\core\services\assets\AssetManifestFactory'                                                            => [
793
+				'EventEspresso\core\services\loaders\Loader' => EE_Dependency_Map::load_from_cache,
794
+			],
795
+			'EventEspresso\core\services\assets\BaristaFactory'                                                                  => [
796
+				'EventEspresso\core\services\assets\AssetManifestFactory' => EE_Dependency_Map::load_from_cache,
797
+				'EventEspresso\core\services\loaders\Loader'              => EE_Dependency_Map::load_from_cache,
798
+			],
799
+			'EventEspresso\core\domain\services\capabilities\FeatureFlagsConfig' => [
800
+				'EventEspresso\core\domain\Domain'                                    => EE_Dependency_Map::load_from_cache,
801
+				'EventEspresso\core\services\json\JsonDataHandler'                    => EE_Dependency_Map::load_from_cache,
802
+			],
803
+			'EventEspresso\core\domain\services\capabilities\FeatureFlags'       => [
804
+				'EventEspresso\core\domain\services\capabilities\CapabilitiesChecker' => EE_Dependency_Map::load_from_cache,
805
+				'EventEspresso\core\domain\services\capabilities\FeatureFlagsConfig'  => EE_Dependency_Map::load_from_cache,
806
+			],
807
+			'EventEspresso\core\services\addon\AddonManager'                                                                     => [
808
+				'EventEspresso\core\services\addon\AddonCollection'              => EE_Dependency_Map::load_from_cache,
809
+				'EventEspresso\core\Psr4Autoloader'                              => EE_Dependency_Map::load_from_cache,
810
+				'EventEspresso\core\services\addon\api\v1\RegisterAddon'         => EE_Dependency_Map::load_from_cache,
811
+				'EventEspresso\core\services\addon\api\IncompatibleAddonHandler' => EE_Dependency_Map::load_from_cache,
812
+				'EventEspresso\core\services\addon\api\ThirdPartyPluginHandler'  => EE_Dependency_Map::load_from_cache,
813
+			],
814
+			'EventEspresso\core\services\addon\api\ThirdPartyPluginHandler'                                                      => [
815
+				'EventEspresso\core\services\request\Request' => EE_Dependency_Map::load_from_cache,
816
+			],
817
+			'EventEspresso\core\libraries\batch\JobHandlers\ExecuteBatchDeletion'                                                => [
818
+				'EventEspresso\core\services\orm\tree_traversal\NodeGroupDao' => EE_Dependency_Map::load_from_cache,
819
+			],
820
+			'EventEspresso\core\libraries\batch\JobHandlers\PreviewEventDeletion'                                                => [
821
+				'EventEspresso\core\services\orm\tree_traversal\NodeGroupDao' => EE_Dependency_Map::load_from_cache,
822
+			],
823
+			'EventEspresso\core\domain\services\admin\events\data\PreviewDeletion'                                               => [
824
+				'EventEspresso\core\services\orm\tree_traversal\NodeGroupDao' => EE_Dependency_Map::load_from_cache,
825
+				'EEM_Event'                                                   => EE_Dependency_Map::load_from_cache,
826
+				'EEM_Datetime'                                                => EE_Dependency_Map::load_from_cache,
827
+				'EEM_Registration'                                            => EE_Dependency_Map::load_from_cache,
828
+			],
829
+			'EventEspresso\core\domain\services\admin\events\data\ConfirmDeletion'                                               => [
830
+				'EventEspresso\core\services\orm\tree_traversal\NodeGroupDao' => EE_Dependency_Map::load_from_cache,
831
+			],
832
+			'EventEspresso\core\services\request\CurrentPage'                                                                    => [
833
+				'EE_CPT_Strategy'                             => EE_Dependency_Map::load_from_cache,
834
+				'EventEspresso\core\services\request\Request' => EE_Dependency_Map::load_from_cache,
835
+			],
836
+			'EventEspresso\core\services\shortcodes\LegacyShortcodesManager'                                                     => [
837
+				'EE_Registry'                                     => EE_Dependency_Map::load_from_cache,
838
+				'EventEspresso\core\services\request\CurrentPage' => EE_Dependency_Map::load_from_cache,
839
+			],
840
+			'EventEspresso\core\services\shortcodes\ShortcodesManager'                                                           => [
841
+				'EventEspresso\core\services\shortcodes\LegacyShortcodesManager' => EE_Dependency_Map::load_from_cache,
842
+				'EventEspresso\core\services\request\CurrentPage'                => EE_Dependency_Map::load_from_cache,
843
+			],
844
+			'EventEspresso\core\domain\entities\users\CurrentUser'                                                               => [
845
+				'EventEspresso\core\domain\entities\users\EventManagers' => EE_Dependency_Map::load_from_cache,
846
+			],
847
+			'EventEspresso\core\services\form\meta\InputTypes'                                                                   => [
848
+				'EventEspresso\core\services\form\meta\inputs\Block'    => EE_Dependency_Map::load_from_cache,
849
+				'EventEspresso\core\services\form\meta\inputs\Button'   => EE_Dependency_Map::load_from_cache,
850
+				'EventEspresso\core\services\form\meta\inputs\DateTime' => EE_Dependency_Map::load_from_cache,
851
+				'EventEspresso\core\services\form\meta\inputs\Input'    => EE_Dependency_Map::load_from_cache,
852
+				'EventEspresso\core\services\form\meta\inputs\Number'   => EE_Dependency_Map::load_from_cache,
853
+				'EventEspresso\core\services\form\meta\inputs\Phone'    => EE_Dependency_Map::load_from_cache,
854
+				'EventEspresso\core\services\form\meta\inputs\Select'   => EE_Dependency_Map::load_from_cache,
855
+				'EventEspresso\core\services\form\meta\inputs\Text'     => EE_Dependency_Map::load_from_cache,
856
+			],
857
+			'EventEspresso\core\domain\services\registration\form\v1\RegFormDependencyHandler'                                   => [
858
+				'EE_Dependency_Map' => EE_Dependency_Map::load_from_cache,
859
+			],
860
+			'EventEspresso\core\services\calculators\LineItemCalculator'                                                         => [
861
+				'EventEspresso\core\services\helpers\DecimalValues' => EE_Dependency_Map::load_from_cache,
862
+			],
863
+			'EventEspresso\core\services\helpers\DecimalValues'                                                                  => [
864
+				'EE_Currency_Config' => EE_Dependency_Map::load_from_cache,
865
+			],
866
+			'EE_Brewing_Regular'                                                                                                 => [
867
+				'EE_Dependency_Map'                                  => EE_Dependency_Map::load_from_cache,
868
+				'EventEspresso\core\services\loaders\Loader'         => EE_Dependency_Map::load_from_cache,
869
+				'EventEspresso\core\services\routing\RouteHandler'   => EE_Dependency_Map::load_from_cache,
870
+				'EventEspresso\core\services\database\TableAnalysis' => EE_Dependency_Map::load_from_cache,
871
+			],
872
+			'EventEspresso\core\domain\services\messages\MessageTemplateRequestData'                                             => [
873
+				'EventEspresso\core\services\request\Request' => EE_Dependency_Map::load_from_cache,
874
+			],
875
+			'EventEspresso\core\domain\services\messages\MessageTemplateValidator'                                               => [
876
+				'EventEspresso\core\services\loaders\Loader' => EE_Dependency_Map::load_from_cache,
877
+			],
878
+			'EventEspresso\core\domain\services\messages\MessageTemplateManager'                                                 => [
879
+				'EEM_Message_Template'                                                   => EE_Dependency_Map::load_from_cache,
880
+				'EEM_Message_Template_Group'                                             => EE_Dependency_Map::load_from_cache,
881
+				'EventEspresso\core\domain\services\messages\MessageTemplateRequestData' => EE_Dependency_Map::load_from_cache,
882
+				'EventEspresso\core\domain\services\messages\MessageTemplateValidator'   => EE_Dependency_Map::load_from_cache,
883
+				'EventEspresso\core\services\request\Request'                            => EE_Dependency_Map::load_from_cache,
884
+			],
885
+			'EventEspresso\core\services\request\sanitizers\RequestSanitizer'                                                    => [
886
+				'EventEspresso\core\domain\services\validation\email\strategies\Basic' => EE_Dependency_Map::load_from_cache,
887
+			],
888
+			'EE_CPT_Event_Strategy'                                                    => [
889
+				null,
890
+				null,
891
+				'EE_Template_Config' => EE_Dependency_Map::load_from_cache,
892
+			],
893
+			'EventEspresso\core\domain\services\licensing\LicenseKeyFormInput'                                                    => [
894
+				'EventEspresso\core\services\licensing\PluginLicense'  => EE_Dependency_Map::not_registered,
895
+				'EventEspresso\core\services\licensing\LicenseManager' => EE_Dependency_Map::load_from_cache,
896
+			],
897
+		];
898
+	}
899
+
900
+
901
+	/**
902
+	 * Registers how core classes are loaded.
903
+	 * This can either be done by simply providing the name of one of the EE_Registry loader methods such as:
904
+	 *        'EE_Request_Handler' => 'load_core'
905
+	 *        'EE_Messages_Queue'  => 'load_lib'
906
+	 *        'EEH_Debug_Tools'    => 'load_helper'
907
+	 * or, if greater control is required, by providing a custom closure. For example:
908
+	 *        'Some_Class' => function () {
909
+	 *            return new Some_Class();
910
+	 *        },
911
+	 * This is required for instantiating dependencies
912
+	 * where an interface has been type hinted in a class constructor. For example:
913
+	 *        'Required_Interface' => function () {
914
+	 *            return new A_Class_That_Implements_Required_Interface();
915
+	 *        },
916
+	 */
917
+	protected function _register_core_class_loaders()
918
+	{
919
+		$this->_class_loaders = [
920
+			// load_core
921
+			'EE_Dependency_Map'                            => function () {
922
+				return $this;
923
+			},
924
+			'EE_Capabilities'                              => 'load_core',
925
+			'EE_Encryption'                                => 'load_core',
926
+			'EE_Front_Controller'                          => 'load_core',
927
+			'EE_Module_Request_Router'                     => 'load_core',
928
+			'EE_Registry'                                  => 'load_core',
929
+			'EE_Request'                                   => function () {
930
+				return $this->legacy_request;
931
+			},
932
+			'EventEspresso\core\services\request\Request'  => function () {
933
+				return $this->request;
934
+			},
935
+			'EventEspresso\core\services\request\Response' => function () {
936
+				return $this->response;
937
+			},
938
+			'EE_Base'                                      => 'load_core',
939
+			'EE_Request_Handler'                           => 'load_core',
940
+			'EE_Session'                                   => 'load_core',
941
+			'EE_Cron_Tasks'                                => 'load_core',
942
+			'EE_System'                                    => 'load_core',
943
+			'EE_Maintenance_Mode'                          => 'load_core',
944
+			'EE_Register_CPTs'                             => 'load_core',
945
+			'EE_Admin'                                     => 'load_core',
946
+			'EE_CPT_Strategy'                              => 'load_core',
947
+			// load_class
948
+			'EE_Registration_Processor'                    => 'load_class',
949
+			'EE_Transaction_Payments'                      => 'load_class',
950
+			'EE_Transaction_Processor'                     => 'load_class',
951
+			// load_lib
952
+			'EE_Message_Resource_Manager'                  => 'load_lib',
953
+			'EE_Message_Type_Collection'                   => 'load_lib',
954
+			'EE_Message_Type_Collection_Loader'            => 'load_lib',
955
+			'EE_Messenger_Collection'                      => 'load_lib',
956
+			'EE_Messenger_Collection_Loader'               => 'load_lib',
957
+			'EE_Messages_Processor'                        => 'load_lib',
958
+			'EE_Message_Repository'                        => 'load_lib',
959
+			'EE_Messages_Queue'                            => 'load_lib',
960
+			'EE_Messages_Data_Handler_Collection'          => 'load_lib',
961
+			'EE_Message_Template_Group_Collection'         => 'load_lib',
962
+			'EE_Payment_Method_Manager'                    => 'load_lib',
963
+			'EE_Payment_Processor'                         => 'load_core',
964
+			'EE_DMS_Core_4_1_0'                            => 'load_dms',
965
+			'EE_DMS_Core_4_2_0'                            => 'load_dms',
966
+			'EE_DMS_Core_4_3_0'                            => 'load_dms',
967
+			'EE_DMS_Core_4_5_0'                            => 'load_dms',
968
+			'EE_DMS_Core_4_6_0'                            => 'load_dms',
969
+			'EE_DMS_Core_4_7_0'                            => 'load_dms',
970
+			'EE_DMS_Core_4_8_0'                            => 'load_dms',
971
+			'EE_DMS_Core_4_9_0'                            => 'load_dms',
972
+			'EE_DMS_Core_4_10_0'                           => 'load_dms',
973
+			'EE_DMS_Core_5_0_0'                            => 'load_dms',
974
+			'EE_Messages_Generator'                        => static function () {
975
+				return EE_Registry::instance()->load_lib(
976
+					'Messages_Generator',
977
+					[],
978
+					false,
979
+					false
980
+				);
981
+			},
982
+			'EE_Messages_Template_Defaults'                => static function ($arguments = []) {
983
+				return EE_Registry::instance()->load_lib(
984
+					'Messages_Template_Defaults',
985
+					$arguments,
986
+					false,
987
+					false
988
+				);
989
+			},
990
+			// load_helper
991
+			'EEH_Parse_Shortcodes'                         => static function () {
992
+				if (EE_Registry::instance()->load_helper('Parse_Shortcodes')) {
993
+					return new EEH_Parse_Shortcodes();
994
+				}
995
+				return null;
996
+			},
997
+			'EE_Template_Config'                           => static function () {
998
+				return EE_Config::instance()->template_settings;
999
+			},
1000
+			'EE_Currency_Config'                           => static function () {
1001
+				return EE_Currency_Config::getCurrencyConfig();
1002
+			},
1003
+			'EE_Registration_Config'                       => static function () {
1004
+				return EE_Config::instance()->registration;
1005
+			},
1006
+			'EE_Core_Config'                               => static function () {
1007
+				return EE_Config::instance()->core;
1008
+			},
1009
+			'EventEspresso\core\services\loaders\Loader'   => static function () {
1010
+				return LoaderFactory::getLoader();
1011
+			},
1012
+			'EE_Network_Config'                            => static function () {
1013
+				return EE_Network_Config::instance();
1014
+			},
1015
+			'EE_Config'                                    => static function () {
1016
+				return EE_Config::instance();
1017
+			},
1018
+			'EventEspresso\core\domain\Domain'             => static function () {
1019
+				return DomainFactory::getEventEspressoCoreDomain();
1020
+			},
1021
+			'EE_Admin_Config'                              => static function () {
1022
+				return EE_Config::instance()->admin;
1023
+			},
1024
+			'EE_Organization_Config'                       => static function () {
1025
+				return EE_Config::instance()->organization;
1026
+			},
1027
+			'EE_Network_Core_Config'                       => static function () {
1028
+				return EE_Network_Config::instance()->core;
1029
+			},
1030
+			'EE_Environment_Config'                        => static function () {
1031
+				return EE_Config::instance()->environment;
1032
+			},
1033
+			'EED_Core_Rest_Api'                            => static function () {
1034
+				return EED_Core_Rest_Api::instance();
1035
+			},
1036
+			'WP_REST_Server'                               => static function () {
1037
+				return rest_get_server();
1038
+			},
1039
+			'EventEspresso\core\Psr4Autoloader'            => static function () {
1040
+				return EE_Psr4AutoloaderInit::psr4_loader();
1041
+			},
1042
+			'EE_Ticket_Selector_Config'                    => function () {
1043
+				return EE_Config::instance()->template_settings->EED_Ticket_Selector;
1044
+			},
1045
+		];
1046
+	}
1047
+
1048
+
1049
+	/**
1050
+	 * can be used for supplying alternate names for classes,
1051
+	 * or for connecting interface names to instantiable classes
1052
+	 *
1053
+	 * @throws InvalidAliasException
1054
+	 */
1055
+	protected function _register_core_aliases()
1056
+	{
1057
+		$aliases = [
1058
+			'CommandBusInterface'                                                          => 'EventEspresso\core\services\commands\CommandBusInterface',
1059
+			'EventEspresso\core\services\commands\CommandBusInterface'                     => 'EventEspresso\core\services\commands\CommandBus',
1060
+			'CommandHandlerManagerInterface'                                               => 'EventEspresso\core\services\commands\CommandHandlerManagerInterface',
1061
+			'EventEspresso\core\services\commands\CommandHandlerManagerInterface'          => 'EventEspresso\core\services\commands\CommandHandlerManager',
1062
+			'CapChecker'                                                                   => 'EventEspresso\core\services\commands\middleware\CapChecker',
1063
+			'AddActionHook'                                                                => 'EventEspresso\core\services\commands\middleware\AddActionHook',
1064
+			'CapabilitiesChecker'                                                          => 'EventEspresso\core\domain\services\capabilities\CapabilitiesChecker',
1065
+			'CapabilitiesCheckerInterface'                                                 => 'EventEspresso\core\domain\services\capabilities\CapabilitiesCheckerInterface',
1066
+			'EventEspresso\core\domain\services\capabilities\CapabilitiesCheckerInterface' => 'EventEspresso\core\domain\services\capabilities\CapabilitiesChecker',
1067
+			'CreateRegistrationService'                                                    => 'EventEspresso\core\domain\services\registration\CreateRegistrationService',
1068
+			'CreateRegistrationCommandHandler'                                             => 'EventEspresso\core\domain\services\commands\registration\CreateRegistrationCommand',
1069
+			'CopyRegistrationDetailsCommandHandler'                                        => 'EventEspresso\core\domain\services\commands\registration\CopyRegistrationDetailsCommand',
1070
+			'CopyRegistrationPaymentsCommandHandler'                                       => 'EventEspresso\core\domain\services\commands\registration\CopyRegistrationPaymentsCommand',
1071
+			'CancelRegistrationAndTicketLineItemCommandHandler'                            => 'EventEspresso\core\domain\services\commands\registration\CancelRegistrationAndTicketLineItemCommandHandler',
1072
+			'UpdateRegistrationAndTransactionAfterChangeCommandHandler'                    => 'EventEspresso\core\domain\services\commands\registration\UpdateRegistrationAndTransactionAfterChangeCommandHandler',
1073
+			'CreateTicketLineItemCommandHandler'                                           => 'EventEspresso\core\domain\services\commands\ticket\CreateTicketLineItemCommand',
1074
+			'CreateTransactionCommandHandler'                                              => 'EventEspresso\core\domain\services\commands\transaction\CreateTransactionCommandHandler',
1075
+			'CreateAttendeeCommandHandler'                                                 => 'EventEspresso\core\domain\services\commands\attendee\CreateAttendeeCommandHandler',
1076
+			'TableManager'                                                                 => 'EventEspresso\core\services\database\TableManager',
1077
+			'TableAnalysis'                                                                => 'EventEspresso\core\services\database\TableAnalysis',
1078
+			'EspressoShortcode'                                                            => 'EventEspresso\core\services\shortcodes\EspressoShortcode',
1079
+			'ShortcodeInterface'                                                           => 'EventEspresso\core\services\shortcodes\ShortcodeInterface',
1080
+			'EventEspresso\core\services\shortcodes\ShortcodeInterface'                    => 'EventEspresso\core\services\shortcodes\EspressoShortcode',
1081
+			'EventEspresso\core\services\cache\CacheStorageInterface'                      => 'EventEspresso\core\services\cache\TransientCacheStorage',
1082
+			'LoaderInterface'                                                              => 'EventEspresso\core\services\loaders\LoaderInterface',
1083
+			'EventEspresso\core\services\loaders\LoaderInterface'                          => 'EventEspresso\core\services\loaders\Loader',
1084
+			'CommandFactoryInterface'                                                      => 'EventEspresso\core\services\commands\CommandFactoryInterface',
1085
+			'EventEspresso\core\services\commands\CommandFactoryInterface'                 => 'EventEspresso\core\services\commands\CommandFactory',
1086
+			'EmailValidatorInterface'                                                      => 'EventEspresso\core\domain\services\validation\email\EmailValidatorInterface',
1087
+			'EventEspresso\core\domain\services\validation\email\EmailValidatorInterface'  => 'EventEspresso\core\domain\services\validation\email\EmailValidationService',
1088
+			'NoticeConverterInterface'                                                     => 'EventEspresso\core\services\notices\NoticeConverterInterface',
1089
+			'EventEspresso\core\services\notices\NoticeConverterInterface'                 => 'EventEspresso\core\services\notices\ConvertNoticesToEeErrors',
1090
+			'NoticesContainerInterface'                                                    => 'EventEspresso\core\services\notices\NoticesContainerInterface',
1091
+			'EventEspresso\core\services\notices\NoticesContainerInterface'                => 'EventEspresso\core\services\notices\NoticesContainer',
1092
+			'EventEspresso\core\services\request\RequestInterface'                         => 'EventEspresso\core\services\request\Request',
1093
+			'EventEspresso\core\services\request\ResponseInterface'                        => 'EventEspresso\core\services\request\Response',
1094
+			'EventEspresso\core\domain\DomainInterface'                                    => 'EventEspresso\core\domain\Domain',
1095
+			'Registration_Processor'                                                       => 'EE_Registration_Processor',
1096
+			'EventEspresso\core\services\assets\AssetManifestInterface'                    => 'EventEspresso\core\services\assets\AssetManifest',
1097
+		];
1098
+		foreach ($aliases as $alias => $fqn) {
1099
+			if (is_array($fqn)) {
1100
+				foreach ($fqn as $class => $for_class) {
1101
+					$this->class_cache->addAlias($class, $alias, $for_class);
1102
+				}
1103
+				continue;
1104
+			}
1105
+			$this->class_cache->addAlias($fqn, $alias);
1106
+		}
1107
+		if (! (defined('DOING_AJAX') && DOING_AJAX) && is_admin()) {
1108
+			$this->class_cache->addAlias(
1109
+				'EventEspresso\core\services\notices\ConvertNoticesToAdminNotices',
1110
+				'EventEspresso\core\services\notices\NoticeConverterInterface'
1111
+			);
1112
+		}
1113
+	}
1114
+
1115
+
1116
+	public function debug($for_class = '')
1117
+	{
1118
+		if (method_exists($this->class_cache, 'debug')) {
1119
+			$this->class_cache->debug($for_class);
1120
+		}
1121
+	}
1122
+
1123
+
1124
+	/**
1125
+	 * This is used to reset the internal map and class_loaders to their original default state at the beginning of the
1126
+	 * request Primarily used by unit tests.
1127
+	 */
1128
+	public function reset()
1129
+	{
1130
+		$this->_register_core_class_loaders();
1131
+		$this->_register_core_dependencies();
1132
+	}
1133
+
1134
+
1135
+	/**
1136
+	 * PLZ NOTE: a better name for this method would be is_alias()
1137
+	 * because it returns TRUE if the provided fully qualified name IS an alias
1138
+	 * WHY?
1139
+	 * Because if a class is type hinting for a concretion,
1140
+	 * then why would we need to find another class to supply it?
1141
+	 * ie: if a class asks for `Fully/Qualified/Namespace/SpecificClassName`,
1142
+	 * then give it an instance of `Fully/Qualified/Namespace/SpecificClassName`.
1143
+	 * Don't go looking for some substitute.
1144
+	 * Whereas if a class is type hinting for an interface...
1145
+	 * then we need to find an actual class to use.
1146
+	 * So the interface IS the alias for some other FQN,
1147
+	 * and we need to find out if `Fully/Qualified/Namespace/SomeInterface`
1148
+	 * represents some other class.
1149
+	 *
1150
+	 * @param string $fqn
1151
+	 * @param string $for_class
1152
+	 * @return bool
1153
+	 * @deprecated 4.9.62.p
1154
+	 */
1155
+	public function has_alias(string $fqn = '', string $for_class = ''): bool
1156
+	{
1157
+		return $this->isAlias($fqn, $for_class);
1158
+	}
1159
+
1160
+
1161
+	/**
1162
+	 * PLZ NOTE: a better name for this method would be get_fqn_for_alias()
1163
+	 * because it returns a FQN for provided alias if one exists, otherwise returns the original $alias
1164
+	 * functions recursively, so that multiple aliases can be used to drill down to a FQN
1165
+	 *  for example:
1166
+	 *      if the following two entries were added to the _aliases array:
1167
+	 *          array(
1168
+	 *              'interface_alias'           => 'some\namespace\interface'
1169
+	 *              'some\namespace\interface'  => 'some\namespace\classname'
1170
+	 *          )
1171
+	 *      then one could use EE_Registry::instance()->create( 'interface_alias' )
1172
+	 *      to load an instance of 'some\namespace\classname'
1173
+	 *
1174
+	 * @param string $alias
1175
+	 * @param string $for_class
1176
+	 * @return string
1177
+	 * @deprecated 4.9.62.p
1178
+	 */
1179
+	public function get_alias(string $alias = '', string $for_class = ''): string
1180
+	{
1181
+		return $this->getFqnForAlias($alias, $for_class);
1182
+	}
1183 1183
 }
Please login to merge, or discard this patch.
core/helpers/EEH_Line_Item.helper.php 2 patches
Indentation   +2214 added lines, -2214 removed lines patch added patch discarded remove patch
@@ -21,2218 +21,2218 @@
 block discarded – undo
21 21
  */
22 22
 class EEH_Line_Item
23 23
 {
24
-    /**
25
-     * @var EE_Line_Item[]|null
26
-     */
27
-    private static ?array $global_taxes = null;
28
-
29
-
30
-    /**
31
-     * Adds a simple item (unrelated to any other model object) to the provided PARENT line item.
32
-     * Does NOT automatically re-calculate the line item totals or update the related transaction.
33
-     * You should call recalculate_total_including_taxes() on the grant total line item after this
34
-     * to update the subtotals, and EE_Registration_Processor::calculate_reg_final_prices_per_line_item()
35
-     * to keep the registration final prices in-sync with the transaction's total.
36
-     *
37
-     * @param EE_Line_Item $parent_line_item
38
-     * @param string       $name
39
-     * @param float        $unit_price
40
-     * @param string       $description
41
-     * @param int          $quantity
42
-     * @param boolean      $taxable
43
-     * @param string|null  $code if set to a value, ensures there is only one line item with that code
44
-     * @param bool         $return_item
45
-     * @param bool         $recalculate_totals
46
-     * @return boolean|EE_Line_Item success
47
-     * @throws EE_Error
48
-     * @throws ReflectionException
49
-     */
50
-    public static function add_unrelated_item(
51
-        EE_Line_Item $parent_line_item,
52
-        string $name,
53
-        float $unit_price,
54
-        string $description = '',
55
-        int $quantity = 1,
56
-        bool $taxable = false,
57
-        ?string $code = null,
58
-        bool $return_item = false,
59
-        bool $recalculate_totals = true
60
-    ) {
61
-        $items_subtotal = self::get_pre_tax_subtotal($parent_line_item);
62
-        $line_item      = EE_Line_Item::new_instance(
63
-            [
64
-                'LIN_name'       => $name,
65
-                'LIN_desc'       => $description,
66
-                'LIN_unit_price' => $unit_price,
67
-                'LIN_quantity'   => $quantity,
68
-                'LIN_percent'    => null,
69
-                'LIN_is_taxable' => $taxable,
70
-                'LIN_order'      => count($items_subtotal->children()),
71
-                'LIN_total'      => $unit_price * $quantity,
72
-                'LIN_type'       => EEM_Line_Item::type_line_item,
73
-                'LIN_code'       => $code,
74
-            ]
75
-        );
76
-        $line_item      = apply_filters(
77
-            'FHEE__EEH_Line_Item__add_unrelated_item__line_item',
78
-            $line_item,
79
-            $parent_line_item
80
-        );
81
-        $added          = self::add_item($parent_line_item, $line_item, $recalculate_totals);
82
-        return $return_item ? $line_item : $added;
83
-    }
84
-
85
-
86
-    /**
87
-     * Adds a simple item ( unrelated to any other model object) to the total line item,
88
-     * in the correct spot in the line item tree. Does not automatically
89
-     * re-calculate the line item totals, nor update the related transaction, nor upgrade the transaction's
90
-     * registrations' final prices (which should probably change because of this).
91
-     * You should call recalculate_total_including_taxes() on the grand total line item, then
92
-     * update the transaction's total, and EE_Registration_Processor::update_registration_final_prices()
93
-     * after using this, to keep the registration final prices in-sync with the transaction's total.
94
-     *
95
-     * @param EE_Line_Item $parent_line_item
96
-     * @param string       $name
97
-     * @param float        $percentage_amount
98
-     * @param string       $description
99
-     * @param boolean      $taxable
100
-     * @param string|null  $code
101
-     * @param bool         $return_item
102
-     * @return boolean|EE_Line_Item success
103
-     * @throws EE_Error
104
-     * @throws ReflectionException
105
-     */
106
-    public static function add_percentage_based_item(
107
-        EE_Line_Item $parent_line_item,
108
-        string $name,
109
-        float $percentage_amount,
110
-        string $description = '',
111
-        bool $taxable = false,
112
-        ?string $code = null,
113
-        bool $return_item = false
114
-    ) {
115
-        $total     = $percentage_amount * $parent_line_item->total() / 100;
116
-        $line_item = EE_Line_Item::new_instance(
117
-            [
118
-                'LIN_name'       => $name,
119
-                'LIN_desc'       => $description,
120
-                'LIN_unit_price' => 0,
121
-                'LIN_percent'    => $percentage_amount,
122
-                'LIN_quantity'   => 1,
123
-                'LIN_is_taxable' => $taxable,
124
-                'LIN_total'      => $total,
125
-                'LIN_type'       => EEM_Line_Item::type_line_item,
126
-                'LIN_parent'     => $parent_line_item->ID(),
127
-                'LIN_code'       => $code,
128
-            ]
129
-        );
130
-        $line_item = apply_filters(
131
-            'FHEE__EEH_Line_Item__add_percentage_based_item__line_item',
132
-            $line_item
133
-        );
134
-        $added     = $parent_line_item->add_child_line_item($line_item, false);
135
-        return $return_item ? $line_item : $added;
136
-    }
137
-
138
-
139
-    /**
140
-     * Returns the new line item created by adding a purchase of the ticket
141
-     * ensures that ticket line item is saved, and that cart total has been recalculated.
142
-     * If this ticket has already been purchased, just increments its count.
143
-     * Automatically re-calculates the line item totals and updates the related transaction. But
144
-     * DOES NOT automatically upgrade the transaction's registrations' final prices (which
145
-     * should probably change because of this).
146
-     * You should call EE_Registration_Processor::calculate_reg_final_prices_per_line_item()
147
-     * after using this, to keep the registration final prices in-sync with the transaction's total.
148
-     *
149
-     * @param EE_Line_Item|null $total_line_item grand total line item of type EEM_Line_Item::type_total
150
-     * @param EE_Ticket         $ticket
151
-     * @param int               $qty
152
-     * @param bool              $recalculate_totals
153
-     * @return EE_Line_Item
154
-     * @throws EE_Error
155
-     * @throws ReflectionException
156
-     */
157
-    public static function add_ticket_purchase(
158
-        ?EE_Line_Item $total_line_item,
159
-        EE_Ticket $ticket,
160
-        int $qty = 1,
161
-        bool $recalculate_totals = true
162
-    ): ?EE_Line_Item {
163
-        if (! $total_line_item instanceof EE_Line_Item || ! $total_line_item->is_total()) {
164
-            throw new EE_Error(
165
-                sprintf(
166
-                    esc_html__(
167
-                        'A valid line item total is required in order to add tickets. A line item of type "%s" was passed.',
168
-                        'event_espresso'
169
-                    ),
170
-                    $ticket->ID(),
171
-                    $total_line_item->ID()
172
-                )
173
-            );
174
-        }
175
-        // either increment the qty for an existing ticket
176
-        $line_item = self::increment_ticket_qty_if_already_in_cart($total_line_item, $ticket, $qty);
177
-        // or add a new one
178
-        if (! $line_item instanceof EE_Line_Item) {
179
-            $line_item = self::create_ticket_line_item($total_line_item, $ticket, $qty);
180
-        }
181
-        if ($recalculate_totals) {
182
-            $total_line_item->recalculate_total_including_taxes();
183
-        }
184
-        return $line_item;
185
-    }
186
-
187
-
188
-    /**
189
-     * Returns the new line item created by adding a purchase of the ticket
190
-     *
191
-     * @param EE_Line_Item|null $total_line_item
192
-     * @param EE_Ticket         $ticket
193
-     * @param int               $qty
194
-     * @return EE_Line_Item
195
-     * @throws EE_Error
196
-     * @throws InvalidArgumentException
197
-     * @throws InvalidDataTypeException
198
-     * @throws InvalidInterfaceException
199
-     * @throws ReflectionException
200
-     */
201
-    public static function increment_ticket_qty_if_already_in_cart(
202
-        ?EE_Line_Item $total_line_item,
203
-        EE_Ticket $ticket,
204
-        int $qty = 1
205
-    ): ?EE_Line_Item {
206
-        $line_item = null;
207
-        if ($total_line_item instanceof EE_Line_Item && $total_line_item->is_total()) {
208
-            $ticket_line_items = EEH_Line_Item::get_ticket_line_items($total_line_item);
209
-            foreach ($ticket_line_items as $ticket_line_item) {
210
-                if (
211
-                    $ticket_line_item instanceof EE_Line_Item
212
-                    && $ticket_line_item->OBJ_ID() === $ticket->ID()
213
-                ) {
214
-                    $line_item = $ticket_line_item;
215
-                    break;
216
-                }
217
-            }
218
-        }
219
-        if ($line_item instanceof EE_Line_Item) {
220
-            EEH_Line_Item::increment_quantity($line_item, $qty);
221
-            return $line_item;
222
-        }
223
-        return null;
224
-    }
225
-
226
-
227
-    /**
228
-     * Increments the line item and all its children's quantity by $qty (but percent line items are unaffected).
229
-     * Does NOT save or recalculate other line items totals
230
-     *
231
-     * @param EE_Line_Item $line_item
232
-     * @param int          $qty
233
-     * @return void
234
-     * @throws EE_Error
235
-     * @throws InvalidArgumentException
236
-     * @throws InvalidDataTypeException
237
-     * @throws InvalidInterfaceException
238
-     * @throws ReflectionException
239
-     */
240
-    public static function increment_quantity(EE_Line_Item $line_item, int $qty = 1)
241
-    {
242
-        if (! $line_item->is_percent()) {
243
-            $qty += $line_item->quantity();
244
-            $line_item->set_quantity($qty);
245
-            $line_item->set_total($line_item->unit_price() * $qty);
246
-            $line_item->save();
247
-        }
248
-        foreach ($line_item->children() as $child) {
249
-            if ($child->is_sub_line_item()) {
250
-                EEH_Line_Item::update_quantity($child, $qty);
251
-            }
252
-        }
253
-    }
254
-
255
-
256
-    /**
257
-     * Decrements the line item and all its children's quantity by $qty (but percent line items are unaffected).
258
-     * Does NOT save or recalculate other line items totals
259
-     *
260
-     * @param EE_Line_Item $line_item
261
-     * @param int          $qty
262
-     * @return void
263
-     * @throws EE_Error
264
-     * @throws InvalidArgumentException
265
-     * @throws InvalidDataTypeException
266
-     * @throws InvalidInterfaceException
267
-     * @throws ReflectionException
268
-     */
269
-    public static function decrement_quantity(EE_Line_Item $line_item, int $qty = 1)
270
-    {
271
-        if (! $line_item->is_percent()) {
272
-            $qty = $line_item->quantity() - $qty;
273
-            $qty = max($qty, 0);
274
-            $line_item->set_quantity($qty);
275
-            $line_item->set_total($line_item->unit_price() * $qty);
276
-            $line_item->save();
277
-        }
278
-        foreach ($line_item->children() as $child) {
279
-            if ($child->is_sub_line_item()) {
280
-                EEH_Line_Item::update_quantity($child, $qty);
281
-            }
282
-        }
283
-    }
284
-
285
-
286
-    /**
287
-     * Updates the line item and its children's quantities to the specified number.
288
-     * Does NOT save them or recalculate totals.
289
-     *
290
-     * @param EE_Line_Item $line_item
291
-     * @param int          $new_quantity
292
-     * @throws EE_Error
293
-     * @throws InvalidArgumentException
294
-     * @throws InvalidDataTypeException
295
-     * @throws InvalidInterfaceException
296
-     * @throws ReflectionException
297
-     */
298
-    public static function update_quantity(EE_Line_Item $line_item, int $new_quantity)
299
-    {
300
-        if (! $line_item->is_percent()) {
301
-            $line_item->set_quantity($new_quantity);
302
-            $line_item->set_total($line_item->unit_price() * $new_quantity);
303
-            $line_item->save();
304
-        }
305
-        foreach ($line_item->children() as $child) {
306
-            if ($child->is_sub_line_item()) {
307
-                EEH_Line_Item::update_quantity($child, $new_quantity);
308
-            }
309
-        }
310
-    }
311
-
312
-
313
-    /**
314
-     * Returns the new line item created by adding a purchase of the ticket
315
-     *
316
-     * @param EE_Line_Item $total_line_item of type EEM_Line_Item::type_total
317
-     * @param EE_Ticket    $ticket
318
-     * @param int          $qty
319
-     * @return EE_Line_Item
320
-     * @throws EE_Error
321
-     * @throws InvalidArgumentException
322
-     * @throws InvalidDataTypeException
323
-     * @throws InvalidInterfaceException
324
-     * @throws ReflectionException
325
-     */
326
-    public static function create_ticket_line_item(
327
-        EE_Line_Item $total_line_item,
328
-        EE_Ticket $ticket,
329
-        int $qty = 1
330
-    ): EE_Line_Item {
331
-        $datetimes           = $ticket->datetimes();
332
-        $first_datetime      = reset($datetimes);
333
-        $first_datetime_name = esc_html__('Event', 'event_espresso');
334
-        if ($first_datetime instanceof EE_Datetime && $first_datetime->event() instanceof EE_Event) {
335
-            $first_datetime_name = $first_datetime->event()->name();
336
-        }
337
-        $event = sprintf(_x('(For %1$s)', '(For Event Name)', 'event_espresso'), $first_datetime_name);
338
-        // get event subtotal line
339
-        $events_sub_total = self::get_event_line_item_for_ticket($total_line_item, $ticket);
340
-        $taxes            = $ticket->tax_price_modifiers();
341
-        // add $ticket to cart
342
-        $line_item = EE_Line_Item::new_instance(
343
-            [
344
-                'LIN_name'       => $ticket->name(),
345
-                'LIN_desc'       => $ticket->description() !== '' ? $ticket->description() . ' ' . $event : $event,
346
-                'LIN_unit_price' => $ticket->price(),
347
-                'LIN_quantity'   => $qty,
348
-                'LIN_is_taxable' => empty($taxes) && $ticket->taxable(),
349
-                'LIN_order'      => count($events_sub_total->children()),
350
-                'LIN_total'      => $ticket->price() * $qty,
351
-                'LIN_type'       => EEM_Line_Item::type_line_item,
352
-                'OBJ_ID'         => $ticket->ID(),
353
-                'OBJ_type'       => EEM_Line_Item::OBJ_TYPE_TICKET,
354
-            ]
355
-        );
356
-        $line_item = apply_filters(
357
-            'FHEE__EEH_Line_Item__create_ticket_line_item__line_item',
358
-            $line_item
359
-        );
360
-        if (! $line_item instanceof EE_Line_Item) {
361
-            throw new DomainException(
362
-                esc_html__('Invalid EE_Line_Item received.', 'event_espresso')
363
-            );
364
-        }
365
-        $events_sub_total->add_child_line_item($line_item);
366
-        // now add the sub-line items
367
-        $running_pre_tax_total = 0;
368
-        $prices                = $ticket->prices();
369
-        if (empty($prices)) {
370
-            // WUT?!?! NO PRICES??? Well, just create a default price then.
371
-            $default_price = EEM_Price::instance()->get_new_price();
372
-            if ($default_price->amount() !== $ticket->price()) {
373
-                $default_price->set_amount($ticket->price());
374
-            }
375
-            $default_price->save();
376
-            $ticket->_add_relation_to($default_price, 'Price');
377
-            $ticket->save();
378
-            $prices = [$default_price];
379
-        }
380
-        foreach ($prices as $price) {
381
-            $sign        = $price->is_discount() ? -1 : 1;
382
-            $price_total = $price->is_percent()
383
-                ? $running_pre_tax_total * $price->amount() / 100
384
-                : $price->amount() * $qty;
385
-            if ($price->is_percent()) {
386
-                $percent    = $sign * $price->amount();
387
-                $unit_price = 0;
388
-            } else {
389
-                $percent    = 0;
390
-                $unit_price = $sign * $price->amount();
391
-            }
392
-
393
-            $price_desc = $price->desc();
394
-            $price_type = $price->type_obj();
395
-            $price_desc = $price_desc === '' && $price_type instanceof EE_Price_Type
396
-                ? $price_type->name()
397
-                : $price_desc;
398
-
399
-            $sub_line_item         = EE_Line_Item::new_instance(
400
-                [
401
-                    'LIN_name'       => $price->name(),
402
-                    'LIN_desc'       => $price_desc,
403
-                    'LIN_quantity'   => $price->is_percent() ? null : $qty,
404
-                    'LIN_is_taxable' => false,
405
-                    'LIN_order'      => $price->order(),
406
-                    'LIN_total'      => $price_total,
407
-                    'LIN_pretax'     => 0,
408
-                    'LIN_unit_price' => $unit_price,
409
-                    'LIN_percent'    => $percent,
410
-                    'LIN_type'       => $price->is_tax() ? EEM_Line_Item::type_sub_tax
411
-                        : EEM_Line_Item::type_sub_line_item,
412
-                    'OBJ_ID'         => $price->ID(),
413
-                    'OBJ_type'       => EEM_Line_Item::OBJ_TYPE_PRICE,
414
-                ]
415
-            );
416
-            $sub_line_item         = apply_filters(
417
-                'FHEE__EEH_Line_Item__create_ticket_line_item__sub_line_item',
418
-                $sub_line_item
419
-            );
420
-            $running_pre_tax_total += ! $price->is_tax() ? $sign * $price_total : 0;
421
-            $line_item->add_child_line_item($sub_line_item);
422
-        }
423
-        $line_item->setPretaxTotal($running_pre_tax_total);
424
-        return $line_item;
425
-    }
426
-
427
-
428
-    /**
429
-     * Adds the specified item under the pre-tax-sub-total line item. Automatically
430
-     * re-calculates the line item totals and updates the related transaction. But
431
-     * DOES NOT automatically upgrade the transaction's registrations' final prices (which
432
-     * should probably change because of this).
433
-     * You should call EE_Registration_Processor::calculate_reg_final_prices_per_line_item()
434
-     * after using this, to keep the registration final prices in-sync with the transaction's total.
435
-     *
436
-     * @param EE_Line_Item $total_line_item
437
-     * @param EE_Line_Item $item to be added
438
-     * @param bool         $recalculate_totals
439
-     * @return boolean
440
-     * @throws EE_Error
441
-     * @throws InvalidArgumentException
442
-     * @throws InvalidDataTypeException
443
-     * @throws InvalidInterfaceException
444
-     * @throws ReflectionException
445
-     */
446
-    public static function add_item(
447
-        EE_Line_Item $total_line_item,
448
-        EE_Line_Item $item,
449
-        bool $recalculate_totals = true
450
-    ): bool {
451
-        $pre_tax_subtotal = self::get_pre_tax_subtotal($total_line_item);
452
-        $success          = $pre_tax_subtotal->add_child_line_item($item);
453
-        if ($recalculate_totals) {
454
-            $total_line_item->recalculate_total_including_taxes();
455
-        }
456
-        return $success;
457
-    }
458
-
459
-
460
-    /**
461
-     * cancels an existing ticket line item,
462
-     * by decrementing its quantity by 1 and adding a new "type_cancellation" sub-line-item.
463
-     * ALL totals and subtotals will NEED TO BE UPDATED after performing this action
464
-     *
465
-     * @param EE_Line_Item $ticket_line_item
466
-     * @param int          $qty
467
-     * @return bool success
468
-     * @throws EE_Error
469
-     * @throws InvalidArgumentException
470
-     * @throws InvalidDataTypeException
471
-     * @throws InvalidInterfaceException
472
-     * @throws ReflectionException
473
-     */
474
-    public static function cancel_ticket_line_item(EE_Line_Item $ticket_line_item, int $qty = 1): bool
475
-    {
476
-        // validate incoming line_item
477
-        if ($ticket_line_item->OBJ_type() !== EEM_Line_Item::OBJ_TYPE_TICKET) {
478
-            throw new EE_Error(
479
-                sprintf(
480
-                    esc_html__(
481
-                        'The supplied line item must have an Object Type of "Ticket", not %1$s.',
482
-                        'event_espresso'
483
-                    ),
484
-                    $ticket_line_item->type()
485
-                )
486
-            );
487
-        }
488
-        if ($ticket_line_item->quantity() < $qty) {
489
-            throw new EE_Error(
490
-                sprintf(
491
-                    esc_html__(
492
-                        'Can not cancel %1$d ticket(s) because the supplied line item has a quantity of %2$d.',
493
-                        'event_espresso'
494
-                    ),
495
-                    $qty,
496
-                    $ticket_line_item->quantity()
497
-                )
498
-            );
499
-        }
500
-        // decrement ticket quantity; don't rely on auto-fixing when recalculating totals to do this
501
-        $ticket_line_item->set_quantity($ticket_line_item->quantity() - $qty);
502
-        foreach ($ticket_line_item->children() as $child_line_item) {
503
-            if (
504
-                $child_line_item->is_sub_line_item()
505
-                && ! $child_line_item->is_percent()
506
-                && ! $child_line_item->is_cancellation()
507
-            ) {
508
-                $child_line_item->set_quantity($child_line_item->quantity() - $qty);
509
-            }
510
-        }
511
-        // get cancellation sub line item
512
-        $cancellation_line_item = EEH_Line_Item::get_descendants_of_type(
513
-            $ticket_line_item,
514
-            EEM_Line_Item::type_cancellation
515
-        );
516
-        $cancellation_line_item = reset($cancellation_line_item);
517
-        // verify that this ticket was indeed previously cancelled
518
-        if ($cancellation_line_item instanceof EE_Line_Item) {
519
-            // increment cancelled quantity
520
-            $cancellation_line_item->set_quantity($cancellation_line_item->quantity() + $qty);
521
-        } else {
522
-            // create cancellation sub line item
523
-            $cancellation_line_item = EE_Line_Item::new_instance(
524
-                [
525
-                    'LIN_name'       => esc_html__('Cancellation', 'event_espresso'),
526
-                    'LIN_desc'       => sprintf(
527
-                        esc_html_x(
528
-                            'Cancelled %1$s : %2$s',
529
-                            'Cancelled Ticket Name : 2015-01-01 11:11',
530
-                            'event_espresso'
531
-                        ),
532
-                        $ticket_line_item->name(),
533
-                        current_time(get_option('date_format') . ' ' . get_option('time_format'))
534
-                    ),
535
-                    'LIN_unit_price' => 0, // $ticket_line_item->unit_price()
536
-                    'LIN_quantity'   => $qty,
537
-                    'LIN_is_taxable' => $ticket_line_item->is_taxable(),
538
-                    'LIN_order'      => count($ticket_line_item->children()),
539
-                    'LIN_total'      => 0, // $ticket_line_item->unit_price()
540
-                    'LIN_type'       => EEM_Line_Item::type_cancellation,
541
-                ]
542
-            );
543
-            $ticket_line_item->add_child_line_item($cancellation_line_item);
544
-        }
545
-        if ($ticket_line_item->save_this_and_descendants() > 0) {
546
-            // decrement parent line item quantity
547
-            $event_line_item = $ticket_line_item->parent();
548
-            if (
549
-                $event_line_item instanceof EE_Line_Item
550
-                && $event_line_item->OBJ_type() === EEM_Line_Item::OBJ_TYPE_EVENT
551
-            ) {
552
-                $event_line_item->set_quantity($event_line_item->quantity() - $qty);
553
-                $event_line_item->save();
554
-            }
555
-            EEH_Line_Item::get_grand_total_and_recalculate_everything($ticket_line_item);
556
-            return true;
557
-        }
558
-        return false;
559
-    }
560
-
561
-
562
-    /**
563
-     * reinstates (un-cancels?) a previously canceled ticket line item,
564
-     * by incrementing its quantity by 1, and decrementing its "type_cancellation" sub-line-item.
565
-     * ALL totals and subtotals will NEED TO BE UPDATED after performing this action
566
-     *
567
-     * @param EE_Line_Item $ticket_line_item
568
-     * @param int          $qty
569
-     * @return bool success
570
-     * @throws EE_Error
571
-     * @throws InvalidArgumentException
572
-     * @throws InvalidDataTypeException
573
-     * @throws InvalidInterfaceException
574
-     * @throws ReflectionException
575
-     */
576
-    public static function reinstate_canceled_ticket_line_item(EE_Line_Item $ticket_line_item, int $qty = 1): bool
577
-    {
578
-        // validate incoming line_item
579
-        if ($ticket_line_item->OBJ_type() !== EEM_Line_Item::OBJ_TYPE_TICKET) {
580
-            throw new EE_Error(
581
-                sprintf(
582
-                    esc_html__(
583
-                        'The supplied line item must have an Object Type of "Ticket", not %1$s.',
584
-                        'event_espresso'
585
-                    ),
586
-                    $ticket_line_item->type()
587
-                )
588
-            );
589
-        }
590
-        // get cancellation sub line item
591
-        $cancellation_line_item = EEH_Line_Item::get_descendants_of_type(
592
-            $ticket_line_item,
593
-            EEM_Line_Item::type_cancellation
594
-        );
595
-        $cancellation_line_item = reset($cancellation_line_item);
596
-        // verify that this ticket was indeed previously cancelled
597
-        if (! $cancellation_line_item instanceof EE_Line_Item) {
598
-            return false;
599
-        }
600
-        if ($cancellation_line_item->quantity() > $qty) {
601
-            // decrement cancelled quantity
602
-            $cancellation_line_item->set_quantity($cancellation_line_item->quantity() - $qty);
603
-        } elseif ($cancellation_line_item->quantity() === $qty) {
604
-            // decrement cancelled quantity in case anyone still has the object kicking around
605
-            $cancellation_line_item->set_quantity($cancellation_line_item->quantity() - $qty);
606
-            // delete because quantity will end up as 0
607
-            $cancellation_line_item->delete();
608
-            // and attempt to destroy the object,
609
-            // even though PHP won't actually destroy it until it needs the memory
610
-            unset($cancellation_line_item);
611
-        } else {
612
-            // what ?!?! negative quantity ?!?!
613
-            throw new EE_Error(
614
-                sprintf(
615
-                    esc_html__(
616
-                        'Can not reinstate %1$d cancelled ticket(s) because the cancelled ticket quantity is only %2$d.',
617
-                        'event_espresso'
618
-                    ),
619
-                    $qty,
620
-                    $cancellation_line_item->quantity()
621
-                )
622
-            );
623
-        }
624
-        // increment ticket quantity
625
-        $ticket_line_item->set_quantity($ticket_line_item->quantity() + $qty);
626
-        if ($ticket_line_item->save_this_and_descendants() > 0) {
627
-            // increment parent line item quantity
628
-            $event_line_item = $ticket_line_item->parent();
629
-            if (
630
-                $event_line_item instanceof EE_Line_Item
631
-                && $event_line_item->OBJ_type() === EEM_Line_Item::OBJ_TYPE_EVENT
632
-            ) {
633
-                $event_line_item->set_quantity($event_line_item->quantity() + $qty);
634
-            }
635
-            EEH_Line_Item::get_grand_total_and_recalculate_everything($ticket_line_item);
636
-            return true;
637
-        }
638
-        return false;
639
-    }
640
-
641
-
642
-    /**
643
-     * calls EEH_Line_Item::find_transaction_grand_total_for_line_item()
644
-     * then EE_Line_Item::recalculate_total_including_taxes() on the result
645
-     *
646
-     * @param EE_Line_Item $line_item
647
-     * @return float
648
-     * @throws EE_Error
649
-     * @throws InvalidArgumentException
650
-     * @throws InvalidDataTypeException
651
-     * @throws InvalidInterfaceException
652
-     * @throws ReflectionException
653
-     */
654
-    public static function get_grand_total_and_recalculate_everything(EE_Line_Item $line_item): float
655
-    {
656
-        $grand_total_line_item = EEH_Line_Item::find_transaction_grand_total_for_line_item($line_item);
657
-        return $grand_total_line_item->recalculate_total_including_taxes();
658
-    }
659
-
660
-
661
-    /**
662
-     * Gets the line item which contains the subtotal of all the items
663
-     *
664
-     * @param EE_Line_Item $total_line_item of type EEM_Line_Item::type_total
665
-     * @return EE_Line_Item
666
-     * @throws EE_Error
667
-     * @throws InvalidArgumentException
668
-     * @throws InvalidDataTypeException
669
-     * @throws InvalidInterfaceException
670
-     * @throws ReflectionException
671
-     */
672
-    public static function get_pre_tax_subtotal(EE_Line_Item $total_line_item): EE_Line_Item
673
-    {
674
-        $pre_tax_subtotal = $total_line_item->get_child_line_item('pre-tax-subtotal');
675
-        return $pre_tax_subtotal instanceof EE_Line_Item
676
-            ? $pre_tax_subtotal
677
-            : self::create_pre_tax_subtotal($total_line_item);
678
-    }
679
-
680
-
681
-    /**
682
-     * Gets the line item for the taxes subtotal
683
-     *
684
-     * @param EE_Line_Item $total_line_item of type EEM_Line_Item::type_total
685
-     * @return EE_Line_Item
686
-     * @throws EE_Error
687
-     * @throws InvalidArgumentException
688
-     * @throws InvalidDataTypeException
689
-     * @throws InvalidInterfaceException
690
-     * @throws ReflectionException
691
-     */
692
-    public static function get_taxes_subtotal(EE_Line_Item $total_line_item): EE_Line_Item
693
-    {
694
-        $taxes = $total_line_item->get_child_line_item('taxes');
695
-        return $taxes ?: self::create_taxes_subtotal($total_line_item);
696
-    }
697
-
698
-
699
-    /**
700
-     * sets the TXN ID on an EE_Line_Item if passed a valid EE_Transaction object
701
-     *
702
-     * @param EE_Line_Item        $line_item
703
-     * @param EE_Transaction|null $transaction
704
-     * @return void
705
-     * @throws EE_Error
706
-     * @throws InvalidArgumentException
707
-     * @throws InvalidDataTypeException
708
-     * @throws InvalidInterfaceException
709
-     * @throws ReflectionException
710
-     */
711
-    public static function set_TXN_ID(EE_Line_Item $line_item, ?EE_Transaction $transaction = null)
712
-    {
713
-        if ($transaction) {
714
-            /** @type EEM_Transaction $EEM_Transaction */
715
-            $EEM_Transaction = EE_Registry::instance()->load_model('Transaction');
716
-            $TXN_ID          = $EEM_Transaction->ensure_is_ID($transaction);
717
-            $line_item->set_TXN_ID($TXN_ID);
718
-        }
719
-    }
720
-
721
-
722
-    /**
723
-     * Creates a new default total line item for the transaction,
724
-     * and its tickets subtotal and taxes subtotal line items (and adds the
725
-     * existing taxes as children of the taxes subtotal line item)
726
-     *
727
-     * @param EE_Transaction|null $transaction
728
-     * @return EE_Line_Item of type total
729
-     * @throws EE_Error
730
-     * @throws InvalidArgumentException
731
-     * @throws InvalidDataTypeException
732
-     * @throws InvalidInterfaceException
733
-     * @throws ReflectionException
734
-     */
735
-    public static function create_total_line_item(?EE_Transaction $transaction = null): EE_Line_Item
736
-    {
737
-        $total_line_item = EE_Line_Item::new_instance(
738
-            [
739
-                'LIN_code' => 'total',
740
-                'LIN_name' => esc_html__('Grand Total', 'event_espresso'),
741
-                'LIN_type' => EEM_Line_Item::type_total,
742
-                'OBJ_type' => EEM_Line_Item::OBJ_TYPE_TRANSACTION,
743
-            ]
744
-        );
745
-        $total_line_item = apply_filters(
746
-            'FHEE__EEH_Line_Item__create_total_line_item__total_line_item',
747
-            $total_line_item
748
-        );
749
-        self::set_TXN_ID($total_line_item, $transaction);
750
-        self::create_pre_tax_subtotal($total_line_item, $transaction);
751
-        self::create_taxes_subtotal($total_line_item, $transaction);
752
-        return $total_line_item;
753
-    }
754
-
755
-
756
-    /**
757
-     * Creates a default items subtotal line item
758
-     *
759
-     * @param EE_Line_Item        $total_line_item
760
-     * @param EE_Transaction|null $transaction
761
-     * @return EE_Line_Item
762
-     * @throws EE_Error
763
-     * @throws InvalidArgumentException
764
-     * @throws InvalidDataTypeException
765
-     * @throws InvalidInterfaceException
766
-     * @throws ReflectionException
767
-     */
768
-    protected static function create_pre_tax_subtotal(
769
-        EE_Line_Item $total_line_item,
770
-        ?EE_Transaction $transaction = null
771
-    ): EE_Line_Item {
772
-        $pre_tax_line_item = EE_Line_Item::new_instance(
773
-            [
774
-                'LIN_code' => 'pre-tax-subtotal',
775
-                'LIN_name' => esc_html__('Pre-Tax Subtotal', 'event_espresso'),
776
-                'LIN_type' => EEM_Line_Item::type_sub_total,
777
-            ]
778
-        );
779
-        $pre_tax_line_item = apply_filters(
780
-            'FHEE__EEH_Line_Item__create_pre_tax_subtotal__pre_tax_line_item',
781
-            $pre_tax_line_item
782
-        );
783
-        self::set_TXN_ID($pre_tax_line_item, $transaction);
784
-        $total_line_item->add_child_line_item($pre_tax_line_item);
785
-        self::create_event_subtotal($pre_tax_line_item, $transaction);
786
-        return $pre_tax_line_item;
787
-    }
788
-
789
-
790
-    /**
791
-     * Creates a line item for the taxes subtotal and finds all the tax prices
792
-     * and applies taxes to it
793
-     *
794
-     * @param EE_Line_Item        $total_line_item of type EEM_Line_Item::type_total
795
-     * @param EE_Transaction|null $transaction
796
-     * @return EE_Line_Item
797
-     * @throws EE_Error
798
-     * @throws InvalidArgumentException
799
-     * @throws InvalidDataTypeException
800
-     * @throws InvalidInterfaceException
801
-     * @throws ReflectionException
802
-     */
803
-    protected static function create_taxes_subtotal(
804
-        EE_Line_Item $total_line_item,
805
-        ?EE_Transaction $transaction = null
806
-    ): EE_Line_Item {
807
-        $tax_line_item = EE_Line_Item::new_instance(
808
-            [
809
-                'LIN_code'  => 'taxes',
810
-                'LIN_name'  => esc_html__('Taxes', 'event_espresso'),
811
-                'LIN_type'  => EEM_Line_Item::type_tax_sub_total,
812
-                'LIN_order' => 1000,// this should always come last
813
-            ]
814
-        );
815
-        $tax_line_item = apply_filters(
816
-            'FHEE__EEH_Line_Item__create_taxes_subtotal__tax_line_item',
817
-            $tax_line_item
818
-        );
819
-        self::set_TXN_ID($tax_line_item, $transaction);
820
-        $total_line_item->add_child_line_item($tax_line_item);
821
-        // and lastly, add the actual taxes
822
-        self::apply_taxes($total_line_item);
823
-        return $tax_line_item;
824
-    }
825
-
826
-
827
-    /**
828
-     * Creates a default items subtotal line item
829
-     *
830
-     * @param EE_Line_Item        $pre_tax_line_item
831
-     * @param EE_Transaction|null $transaction
832
-     * @param EE_Event|null       $event
833
-     * @return EE_Line_Item
834
-     * @throws EE_Error
835
-     * @throws InvalidArgumentException
836
-     * @throws InvalidDataTypeException
837
-     * @throws InvalidInterfaceException
838
-     * @throws ReflectionException
839
-     */
840
-    public static function create_event_subtotal(
841
-        EE_Line_Item $pre_tax_line_item,
842
-        ?EE_Transaction $transaction = null,
843
-        ?EE_Event $event = null
844
-    ): EE_Line_Item {
845
-        $event_line_item = EE_Line_Item::new_instance(
846
-            [
847
-                'LIN_code' => self::get_event_code($event),
848
-                'LIN_name' => self::get_event_name($event),
849
-                'LIN_desc' => self::get_event_desc($event),
850
-                'LIN_type' => EEM_Line_Item::type_sub_total,
851
-                'OBJ_type' => EEM_Line_Item::OBJ_TYPE_EVENT,
852
-                'OBJ_ID'   => $event instanceof EE_Event ? $event->ID() : 0,
853
-            ]
854
-        );
855
-        $event_line_item = apply_filters(
856
-            'FHEE__EEH_Line_Item__create_event_subtotal__event_line_item',
857
-            $event_line_item
858
-        );
859
-        self::set_TXN_ID($event_line_item, $transaction);
860
-        $pre_tax_line_item->add_child_line_item($event_line_item);
861
-        return $event_line_item;
862
-    }
863
-
864
-
865
-    /**
866
-     * Gets what the event ticket's code SHOULD be
867
-     *
868
-     * @param EE_Event|null $event
869
-     * @return string
870
-     * @throws EE_Error
871
-     * @throws ReflectionException
872
-     */
873
-    public static function get_event_code(?EE_Event $event = null): string
874
-    {
875
-        return 'event-' . ($event instanceof EE_Event ? $event->ID() : '0');
876
-    }
877
-
878
-
879
-    /**
880
-     * Gets the event name
881
-     *
882
-     * @param EE_Event|null $event
883
-     * @return string
884
-     * @throws EE_Error
885
-     * @throws ReflectionException
886
-     */
887
-    public static function get_event_name(?EE_Event $event = null): string
888
-    {
889
-        return $event instanceof EE_Event
890
-            ? mb_substr($event->name(), 0, 245)
891
-            : esc_html__('Event', 'event_espresso');
892
-    }
893
-
894
-
895
-    /**
896
-     * Gets the event excerpt
897
-     *
898
-     * @param EE_Event|null $event
899
-     * @return string
900
-     * @throws EE_Error
901
-     * @throws ReflectionException
902
-     */
903
-    public static function get_event_desc(?EE_Event $event = null): string
904
-    {
905
-        return $event instanceof EE_Event ? $event->short_description() : '';
906
-    }
907
-
908
-
909
-    /**
910
-     * Given the grand total line item and a ticket, finds the event sub-total
911
-     * line item the ticket's purchase should be added onto
912
-     *
913
-     * @access public
914
-     * @param EE_Line_Item $grand_total the grand total line item
915
-     * @param EE_Ticket    $ticket
916
-     * @return EE_Line_Item
917
-     * @throws EE_Error
918
-     * @throws InvalidArgumentException
919
-     * @throws InvalidDataTypeException
920
-     * @throws InvalidInterfaceException
921
-     * @throws ReflectionException
922
-     */
923
-    public static function get_event_line_item_for_ticket(EE_Line_Item $grand_total, EE_Ticket $ticket): EE_Line_Item
924
-    {
925
-        $first_datetime = $ticket->first_datetime();
926
-        if (! $first_datetime instanceof EE_Datetime) {
927
-            throw new EE_Error(
928
-                sprintf(
929
-                    esc_html__('The supplied ticket (ID %d) has no datetimes', 'event_espresso'),
930
-                    $ticket->ID()
931
-                )
932
-            );
933
-        }
934
-        $event = $first_datetime->event();
935
-        if (! $event instanceof EE_Event) {
936
-            throw new EE_Error(
937
-                sprintf(
938
-                    esc_html__(
939
-                        'The supplied ticket (ID %d) has no event data associated with it.',
940
-                        'event_espresso'
941
-                    ),
942
-                    $ticket->ID()
943
-                )
944
-            );
945
-        }
946
-        $events_sub_total = EEH_Line_Item::get_event_line_item($grand_total, $event);
947
-        if (! $events_sub_total instanceof EE_Line_Item) {
948
-            throw new EE_Error(
949
-                sprintf(
950
-                    esc_html__(
951
-                        'There is no events sub-total for ticket %s on total line item %d',
952
-                        'event_espresso'
953
-                    ),
954
-                    $ticket->ID(),
955
-                    $grand_total->ID()
956
-                )
957
-            );
958
-        }
959
-        return $events_sub_total;
960
-    }
961
-
962
-
963
-    /**
964
-     * Gets the event line item
965
-     *
966
-     * @param EE_Line_Item  $grand_total
967
-     * @param EE_Event|null $event
968
-     * @return EE_Line_Item for the event subtotal which is a child of $grand_total
969
-     * @throws EE_Error
970
-     * @throws InvalidArgumentException
971
-     * @throws InvalidDataTypeException
972
-     * @throws InvalidInterfaceException
973
-     * @throws ReflectionException
974
-     */
975
-    public static function get_event_line_item(EE_Line_Item $grand_total, ?EE_Event $event = null): ?EE_Line_Item
976
-    {
977
-        /** @type EE_Event $event */
978
-        $event           = EEM_Event::instance()->ensure_is_obj($event, true);
979
-        $event_line_item = null;
980
-        $found           = false;
981
-        foreach (EEH_Line_Item::get_event_subtotals($grand_total) as $event_line_item) {
982
-            // default event subtotal, we should only ever find this the first time this method is called
983
-            if (! $event_line_item->OBJ_ID()) {
984
-                // let's use this! but first... set the event details
985
-                EEH_Line_Item::set_event_subtotal_details($event_line_item, $event);
986
-                $found = true;
987
-                break;
988
-            }
989
-            if ($event_line_item->OBJ_ID() === $event->ID()) {
990
-                // found existing line item for this event in the cart, so break out of loop and use this one
991
-                $found = true;
992
-                break;
993
-            }
994
-        }
995
-        if (! $found) {
996
-            // there is no event sub-total yet, so add it
997
-            $pre_tax_subtotal = EEH_Line_Item::get_pre_tax_subtotal($grand_total);
998
-            // create a new "event" subtotal below that
999
-            $event_line_item = EEH_Line_Item::create_event_subtotal($pre_tax_subtotal, null, $event);
1000
-            // and set the event details
1001
-            EEH_Line_Item::set_event_subtotal_details($event_line_item, $event);
1002
-        }
1003
-        return $event_line_item;
1004
-    }
1005
-
1006
-
1007
-    /**
1008
-     * Creates a default items subtotal line item
1009
-     *
1010
-     * @param EE_Line_Item        $event_line_item
1011
-     * @param EE_Event|null       $event
1012
-     * @param EE_Transaction|null $transaction
1013
-     * @return void
1014
-     * @throws EE_Error
1015
-     * @throws InvalidArgumentException
1016
-     * @throws InvalidDataTypeException
1017
-     * @throws InvalidInterfaceException
1018
-     * @throws ReflectionException
1019
-     */
1020
-    public static function set_event_subtotal_details(
1021
-        EE_Line_Item $event_line_item,
1022
-        EE_Event $event = null,
1023
-        ?EE_Transaction $transaction = null
1024
-    ) {
1025
-        if ($event instanceof EE_Event) {
1026
-            $event_line_item->set_code(self::get_event_code($event));
1027
-            $event_line_item->set_name(self::get_event_name($event));
1028
-            $event_line_item->set_desc(self::get_event_desc($event));
1029
-            $event_line_item->set_OBJ_ID($event->ID());
1030
-        }
1031
-        self::set_TXN_ID($event_line_item, $transaction);
1032
-    }
1033
-
1034
-
1035
-    /**
1036
-     * Finds what taxes should apply, adds them as tax line items under the taxes sub-total,
1037
-     * and recalculates the taxes sub-total and the grand total. Resets the taxes, so
1038
-     * any old taxes are removed
1039
-     *
1040
-     * @param EE_Line_Item $total_line_item of type EEM_Line_Item::type_total
1041
-     * @param bool         $update_txn_status
1042
-     * @return bool
1043
-     * @throws EE_Error
1044
-     * @throws InvalidArgumentException
1045
-     * @throws InvalidDataTypeException
1046
-     * @throws InvalidInterfaceException
1047
-     * @throws ReflectionException
1048
-     * @throws RuntimeException
1049
-     */
1050
-    public static function apply_taxes(EE_Line_Item $total_line_item, bool $update_txn_status = false): bool
1051
-    {
1052
-        $total_line_item       = EEH_Line_Item::find_transaction_grand_total_for_line_item($total_line_item);
1053
-        $taxes_line_item       = self::get_taxes_subtotal($total_line_item);
1054
-        $existing_global_taxes = $taxes_line_item->tax_descendants();
1055
-        $updates               = false;
1056
-        // loop thru taxes
1057
-        $global_taxes = EEH_Line_Item::getGlobalTaxes();
1058
-        foreach ($global_taxes as $order => $taxes) {
1059
-            foreach ($taxes as $tax) {
1060
-                if ($tax instanceof EE_Price) {
1061
-                    $found = false;
1062
-                    // check if this is already an existing tax
1063
-                    foreach ($existing_global_taxes as $existing_global_tax) {
1064
-                        if ($tax->ID() === $existing_global_tax->OBJ_ID()) {
1065
-                            // maybe update the tax rate in case it has changed
1066
-                            if ($existing_global_tax->percent() !== $tax->amount()) {
1067
-                                $existing_global_tax->set_percent($tax->amount());
1068
-                                $existing_global_tax->save();
1069
-                                $updates = true;
1070
-                            }
1071
-                            $found = true;
1072
-                            break;
1073
-                        }
1074
-                    }
1075
-                    if (! $found) {
1076
-                        // add a new line item for this global tax
1077
-                        $tax_line_item = apply_filters(
1078
-                            'FHEE__EEH_Line_Item__apply_taxes__tax_line_item',
1079
-                            EE_Line_Item::new_instance(
1080
-                                [
1081
-                                    'LIN_name'       => $tax->name(),
1082
-                                    'LIN_desc'       => $tax->desc(),
1083
-                                    'LIN_percent'    => $tax->amount(),
1084
-                                    'LIN_is_taxable' => false,
1085
-                                    'LIN_order'      => $order,
1086
-                                    'LIN_total'      => 0,
1087
-                                    'LIN_type'       => EEM_Line_Item::type_tax,
1088
-                                    'OBJ_type'       => EEM_Line_Item::OBJ_TYPE_PRICE,
1089
-                                    'OBJ_ID'         => $tax->ID(),
1090
-                                ]
1091
-                            )
1092
-                        );
1093
-                        $updates       = $taxes_line_item->add_child_line_item($tax_line_item) ? true : $updates;
1094
-                    }
1095
-                }
1096
-            }
1097
-        }
1098
-        // only recalculate totals if something changed
1099
-        if ($updates || $update_txn_status) {
1100
-            $total_line_item->recalculate_total_including_taxes($update_txn_status);
1101
-            return true;
1102
-        }
1103
-        return false;
1104
-    }
1105
-
1106
-
1107
-    /**
1108
-     * Ensures that taxes have been applied to the order, if not applies them.
1109
-     * Returns the total amount of tax
1110
-     *
1111
-     * @param EE_Line_Item|null $total_line_item of type EEM_Line_Item::type_total
1112
-     * @return float
1113
-     * @throws EE_Error
1114
-     * @throws InvalidArgumentException
1115
-     * @throws InvalidDataTypeException
1116
-     * @throws InvalidInterfaceException
1117
-     * @throws ReflectionException
1118
-     */
1119
-    public static function ensure_taxes_applied(?EE_Line_Item $total_line_item): float
1120
-    {
1121
-        $taxes_subtotal = self::get_taxes_subtotal($total_line_item);
1122
-        if (! $taxes_subtotal->children()) {
1123
-            self::apply_taxes($total_line_item);
1124
-        }
1125
-        return $taxes_subtotal->total();
1126
-    }
1127
-
1128
-
1129
-    /**
1130
-     * Deletes ALL children of the passed line item
1131
-     *
1132
-     * @param EE_Line_Item $parent_line_item
1133
-     * @return bool
1134
-     * @throws EE_Error
1135
-     * @throws InvalidArgumentException
1136
-     * @throws InvalidDataTypeException
1137
-     * @throws InvalidInterfaceException
1138
-     * @throws ReflectionException
1139
-     */
1140
-    public static function delete_all_child_items(EE_Line_Item $parent_line_item)
1141
-    {
1142
-        $deleted = 0;
1143
-        foreach ($parent_line_item->children() as $child_line_item) {
1144
-            if ($child_line_item instanceof EE_Line_Item) {
1145
-                $deleted += EEH_Line_Item::delete_all_child_items($child_line_item);
1146
-                if ($child_line_item->ID()) {
1147
-                    $child_line_item->delete();
1148
-                    unset($child_line_item);
1149
-                } else {
1150
-                    $parent_line_item->delete_child_line_item($child_line_item->code());
1151
-                }
1152
-                $deleted++;
1153
-            }
1154
-        }
1155
-        return $deleted;
1156
-    }
1157
-
1158
-
1159
-    /**
1160
-     * Deletes the line items as indicated by the line item code(s) provided,
1161
-     * regardless of where they're found in the line item tree. Automatically
1162
-     * re-calculates the line item totals and updates the related transaction. But
1163
-     * DOES NOT automatically upgrade the transaction's registrations' final prices (which
1164
-     * should probably change because of this).
1165
-     * You should call EE_Registration_Processor::calculate_reg_final_prices_per_line_item()
1166
-     * after using this, to keep the registration final prices in-sync with the transaction's total.
1167
-     *
1168
-     * @param EE_Line_Item      $total_line_item of type EEM_Line_Item::type_total
1169
-     * @param array|bool|string $line_item_codes
1170
-     * @return int number of items successfully removed
1171
-     * @throws EE_Error
1172
-     * @throws ReflectionException
1173
-     */
1174
-    public static function delete_items(EE_Line_Item $total_line_item, $line_item_codes = false)
1175
-    {
1176
-        if ($total_line_item->type() !== EEM_Line_Item::type_total) {
1177
-            EE_Error::doing_it_wrong(
1178
-                'EEH_Line_Item::delete_items',
1179
-                esc_html__(
1180
-                    'This static method should only be called with a TOTAL line item, otherwise we won\'t recalculate the totals correctly',
1181
-                    'event_espresso'
1182
-                ),
1183
-                '4.6.18'
1184
-            );
1185
-        }
1186
-
1187
-        // check if only a single line_item_id was passed
1188
-        if (! empty($line_item_codes) && ! is_array($line_item_codes)) {
1189
-            // place single line_item_id in an array to appear as multiple line_item_ids
1190
-            $line_item_codes = [$line_item_codes];
1191
-        }
1192
-        $removals = 0;
1193
-        // cycle thru line_item_ids
1194
-        foreach ($line_item_codes as $line_item_id) {
1195
-            $removals += $total_line_item->delete_child_line_item($line_item_id);
1196
-        }
1197
-
1198
-        if ($removals > 0) {
1199
-            $total_line_item->recalculate_taxes_and_tax_total();
1200
-            return $removals;
1201
-        } else {
1202
-            return false;
1203
-        }
1204
-    }
1205
-
1206
-
1207
-    /**
1208
-     * Overwrites the previous tax by clearing out the old taxes, and creates a new
1209
-     * tax and updates the total line item accordingly
1210
-     *
1211
-     * @param EE_Line_Item $total_line_item
1212
-     * @param float        $amount
1213
-     * @param string       $name
1214
-     * @param string       $description
1215
-     * @param string       $code
1216
-     * @param boolean      $add_to_existing_line_item
1217
-     *                          if true, and a duplicate line item with the same code is found,
1218
-     *                          $amount will be added onto it; otherwise will simply set the taxes to match $amount
1219
-     * @return EE_Line_Item the new tax line item created
1220
-     * @throws EE_Error
1221
-     * @throws InvalidArgumentException
1222
-     * @throws InvalidDataTypeException
1223
-     * @throws InvalidInterfaceException
1224
-     * @throws ReflectionException
1225
-     */
1226
-    public static function set_total_tax_to(
1227
-        EE_Line_Item $total_line_item,
1228
-        float $amount,
1229
-        string $name = '',
1230
-        string $description = '',
1231
-        string $code = '',
1232
-        bool $add_to_existing_line_item = false
1233
-    ): EE_Line_Item {
1234
-        $tax_subtotal  = self::get_taxes_subtotal($total_line_item);
1235
-        $taxable_total = $total_line_item->taxable_total();
1236
-
1237
-        if ($add_to_existing_line_item) {
1238
-            $new_tax = $tax_subtotal->get_child_line_item($code);
1239
-            EEM_Line_Item::instance()->delete(
1240
-                [['LIN_code' => ['!=', $code], 'LIN_parent' => $tax_subtotal->ID()]]
1241
-            );
1242
-        } else {
1243
-            $new_tax = null;
1244
-            $tax_subtotal->delete_children_line_items();
1245
-        }
1246
-        if ($new_tax) {
1247
-            $new_tax->set_total($new_tax->total() + $amount);
1248
-            $new_tax->set_percent($taxable_total ? $new_tax->total() / $taxable_total * 100 : 0);
1249
-        } else {
1250
-            // no existing tax item. Create it
1251
-            $new_tax = EE_Line_Item::new_instance(
1252
-                [
1253
-                    'TXN_ID'      => $total_line_item->TXN_ID(),
1254
-                    'LIN_name'    => $name ?: esc_html__('Tax', 'event_espresso'),
1255
-                    'LIN_desc'    => $description ?: '',
1256
-                    'LIN_percent' => $taxable_total ? ($amount / $taxable_total * 100) : 0,
1257
-                    'LIN_total'   => $amount,
1258
-                    'LIN_parent'  => $tax_subtotal->ID(),
1259
-                    'LIN_type'    => EEM_Line_Item::type_tax,
1260
-                    'LIN_code'    => $code,
1261
-                ]
1262
-            );
1263
-        }
1264
-
1265
-        $new_tax = apply_filters(
1266
-            'FHEE__EEH_Line_Item__set_total_tax_to__new_tax_subtotal',
1267
-            $new_tax,
1268
-            $total_line_item
1269
-        );
1270
-        $new_tax->save();
1271
-        $tax_subtotal->set_total($new_tax->total());
1272
-        $tax_subtotal->save();
1273
-        $total_line_item->recalculate_total_including_taxes();
1274
-        return $new_tax;
1275
-    }
1276
-
1277
-
1278
-    /**
1279
-     * Makes all the line items which are children of $line_item taxable (or not).
1280
-     * Does NOT save the line items
1281
-     *
1282
-     * @param EE_Line_Item $line_item
1283
-     * @param boolean      $taxable
1284
-     * @param string|null  $code_substring_for_whitelist if this string is part of the line item's code
1285
-     *                                                   it will be whitelisted (ie, except from becoming taxable)
1286
-     * @throws EE_Error
1287
-     * @throws ReflectionException
1288
-     */
1289
-    public static function set_line_items_taxable(
1290
-        EE_Line_Item $line_item,
1291
-        bool $taxable = true,
1292
-        ?string $code_substring_for_whitelist = null
1293
-    ) {
1294
-        $whitelisted = false;
1295
-        if ($code_substring_for_whitelist !== null) {
1296
-            $whitelisted = strpos($line_item->code(), $code_substring_for_whitelist) !== false;
1297
-        }
1298
-        if (! $whitelisted && $line_item->is_line_item()) {
1299
-            $line_item->set_is_taxable($taxable);
1300
-        }
1301
-        foreach ($line_item->children() as $child_line_item) {
1302
-            EEH_Line_Item::set_line_items_taxable(
1303
-                $child_line_item,
1304
-                $taxable,
1305
-                $code_substring_for_whitelist
1306
-            );
1307
-        }
1308
-    }
1309
-
1310
-
1311
-    /**
1312
-     * Gets all descendants that are event subtotals
1313
-     *
1314
-     * @param EE_Line_Item $parent_line_item - the line item to find descendants of
1315
-     * @return EE_Line_Item[]
1316
-     * @throws EE_Error
1317
-     * @throws ReflectionException
1318
-     * @uses  EEH_Line_Item::get_subtotals_of_object_type()
1319
-     */
1320
-    public static function get_event_subtotals(EE_Line_Item $parent_line_item): array
1321
-    {
1322
-        return self::get_subtotals_of_object_type($parent_line_item, EEM_Line_Item::OBJ_TYPE_EVENT);
1323
-    }
1324
-
1325
-
1326
-    /**
1327
-     * Gets all descendants subtotals that match the supplied object type
1328
-     *
1329
-     * @param EE_Line_Item $parent_line_item - the line item to find descendants of
1330
-     * @param string       $obj_type
1331
-     * @return EE_Line_Item[]
1332
-     * @throws EE_Error
1333
-     * @throws ReflectionException
1334
-     * @uses  EEH_Line_Item::_get_descendants_by_type_and_object_type()
1335
-     */
1336
-    public static function get_subtotals_of_object_type(EE_Line_Item $parent_line_item, string $obj_type = ''): array
1337
-    {
1338
-        return self::_get_descendants_by_type_and_object_type(
1339
-            $parent_line_item,
1340
-            EEM_Line_Item::type_sub_total,
1341
-            $obj_type
1342
-        );
1343
-    }
1344
-
1345
-
1346
-    /**
1347
-     * Gets all descendants that are tickets
1348
-     *
1349
-     * @param EE_Line_Item $parent_line_item - the line item to find descendants of
1350
-     * @return EE_Line_Item[]
1351
-     * @throws EE_Error
1352
-     * @throws ReflectionException
1353
-     * @uses  EEH_Line_Item::get_line_items_of_object_type()
1354
-     */
1355
-    public static function get_ticket_line_items(EE_Line_Item $parent_line_item): array
1356
-    {
1357
-        return self::get_line_items_of_object_type(
1358
-            $parent_line_item,
1359
-            EEM_Line_Item::OBJ_TYPE_TICKET
1360
-        );
1361
-    }
1362
-
1363
-
1364
-    /**
1365
-     * Gets all descendants subtotals that match the supplied object type
1366
-     *
1367
-     * @param EE_Line_Item $parent_line_item - the line item to find descendants of
1368
-     * @param string       $obj_type
1369
-     * @return EE_Line_Item[]
1370
-     * @throws EE_Error
1371
-     * @throws ReflectionException
1372
-     * @uses  EEH_Line_Item::_get_descendants_by_type_and_object_type()
1373
-     */
1374
-    public static function get_line_items_of_object_type(EE_Line_Item $parent_line_item, string $obj_type = ''): array
1375
-    {
1376
-        return self::_get_descendants_by_type_and_object_type(
1377
-            $parent_line_item,
1378
-            EEM_Line_Item::type_line_item,
1379
-            $obj_type
1380
-        );
1381
-    }
1382
-
1383
-
1384
-    /**
1385
-     * Gets all the descendants (ie, children or children of children etc) that are of the type 'tax'
1386
-     *
1387
-     * @param EE_Line_Item $parent_line_item - the line item to find descendants of
1388
-     * @return EE_Line_Item[]
1389
-     * @throws EE_Error
1390
-     * @throws ReflectionException
1391
-     * @uses  EEH_Line_Item::get_descendants_of_type()
1392
-     */
1393
-    public static function get_tax_descendants(EE_Line_Item $parent_line_item): array
1394
-    {
1395
-        return EEH_Line_Item::get_descendants_of_type(
1396
-            $parent_line_item,
1397
-            EEM_Line_Item::type_tax
1398
-        );
1399
-    }
1400
-
1401
-
1402
-    /**
1403
-     * Gets all the real items purchased which are children of this item
1404
-     *
1405
-     * @param EE_Line_Item $parent_line_item - the line item to find descendants of
1406
-     * @return EE_Line_Item[]
1407
-     * @throws EE_Error
1408
-     * @throws ReflectionException
1409
-     * @uses  EEH_Line_Item::get_descendants_of_type()
1410
-     */
1411
-    public static function get_line_item_descendants(EE_Line_Item $parent_line_item): array
1412
-    {
1413
-        return EEH_Line_Item::get_descendants_of_type(
1414
-            $parent_line_item,
1415
-            EEM_Line_Item::type_line_item
1416
-        );
1417
-    }
1418
-
1419
-
1420
-    /**
1421
-     * Gets all descendants of supplied line item that match the supplied line item type
1422
-     *
1423
-     * @param EE_Line_Item $parent_line_item - the line item to find descendants of
1424
-     * @param string       $line_item_type   one of the EEM_Line_Item constants
1425
-     * @return EE_Line_Item[]
1426
-     * @throws EE_Error
1427
-     * @throws ReflectionException
1428
-     * @uses  EEH_Line_Item::_get_descendants_by_type_and_object_type()
1429
-     */
1430
-    public static function get_descendants_of_type(EE_Line_Item $parent_line_item, string $line_item_type): array
1431
-    {
1432
-        return self::_get_descendants_by_type_and_object_type(
1433
-            $parent_line_item,
1434
-            $line_item_type
1435
-        );
1436
-    }
1437
-
1438
-
1439
-    /**
1440
-     * Gets all descendants of supplied line item that match the supplied line item type and possibly the object type
1441
-     * as well
1442
-     *
1443
-     * @param EE_Line_Item $parent_line_item  - the line item to find descendants of
1444
-     * @param string       $line_item_type    one of the EEM_Line_Item constants
1445
-     * @param string|null  $obj_type          object model class name (minus prefix) or NULL to ignore object type when
1446
-     *                                        searching
1447
-     * @return EE_Line_Item[]
1448
-     * @throws EE_Error
1449
-     * @throws ReflectionException
1450
-     */
1451
-    protected static function _get_descendants_by_type_and_object_type(
1452
-        EE_Line_Item $parent_line_item,
1453
-        string $line_item_type,
1454
-        ?string $obj_type = null
1455
-    ): array {
1456
-        $objects = [];
1457
-        foreach ($parent_line_item->children() as $child_line_item) {
1458
-            if ($child_line_item instanceof EE_Line_Item) {
1459
-                if (
1460
-                    $child_line_item->type() === $line_item_type
1461
-                    && (
1462
-                        $child_line_item->OBJ_type() === $obj_type || $obj_type === null
1463
-                    )
1464
-                ) {
1465
-                    $objects[] = $child_line_item;
1466
-                } else {
1467
-                    // go-through-all-its children looking for more matches
1468
-                    $objects = array_merge(
1469
-                        $objects,
1470
-                        self::_get_descendants_by_type_and_object_type(
1471
-                            $child_line_item,
1472
-                            $line_item_type,
1473
-                            $obj_type
1474
-                        )
1475
-                    );
1476
-                }
1477
-            }
1478
-        }
1479
-        return $objects;
1480
-    }
1481
-
1482
-
1483
-    /**
1484
-     * Gets all descendants subtotals that match the supplied object type
1485
-     *
1486
-     * @param EE_Line_Item $parent_line_item - the line item to find descendants of
1487
-     * @param string       $OBJ_type         object type (like Event)
1488
-     * @param array        $OBJ_IDs          array of OBJ_IDs
1489
-     * @return EE_Line_Item[]
1490
-     * @throws EE_Error
1491
-     * @throws ReflectionException
1492
-     * @uses  EEH_Line_Item::_get_descendants_by_type_and_object_type()
1493
-     */
1494
-    public static function get_line_items_by_object_type_and_IDs(
1495
-        EE_Line_Item $parent_line_item,
1496
-        string $OBJ_type = '',
1497
-        array $OBJ_IDs = []
1498
-    ): array {
1499
-        return self::_get_descendants_by_object_type_and_object_ID(
1500
-            $parent_line_item,
1501
-            $OBJ_type,
1502
-            $OBJ_IDs
1503
-        );
1504
-    }
1505
-
1506
-
1507
-    /**
1508
-     * Gets all descendants of supplied line item that match the supplied line item type and possibly the object type
1509
-     * as well
1510
-     *
1511
-     * @param EE_Line_Item $parent_line_item - the line item to find descendants of
1512
-     * @param string       $OBJ_type         object type (like Event)
1513
-     * @param array        $OBJ_IDs          array of OBJ_IDs
1514
-     * @return EE_Line_Item[]
1515
-     * @throws EE_Error
1516
-     * @throws ReflectionException
1517
-     */
1518
-    protected static function _get_descendants_by_object_type_and_object_ID(
1519
-        EE_Line_Item $parent_line_item,
1520
-        string $OBJ_type,
1521
-        array $OBJ_IDs
1522
-    ): array {
1523
-        $objects = [];
1524
-        foreach ($parent_line_item->children() as $child_line_item) {
1525
-            if ($child_line_item instanceof EE_Line_Item) {
1526
-                if (
1527
-                    $child_line_item->OBJ_type() === $OBJ_type
1528
-                    && in_array($child_line_item->OBJ_ID(), $OBJ_IDs)
1529
-                ) {
1530
-                    $objects[] = $child_line_item;
1531
-                } else {
1532
-                    // go-through-all-its children looking for more matches
1533
-                    $objects = array_merge(
1534
-                        $objects,
1535
-                        self::_get_descendants_by_object_type_and_object_ID(
1536
-                            $child_line_item,
1537
-                            $OBJ_type,
1538
-                            $OBJ_IDs
1539
-                        )
1540
-                    );
1541
-                }
1542
-            }
1543
-        }
1544
-        return $objects;
1545
-    }
1546
-
1547
-
1548
-    /**
1549
-     * Uses a breadth-first-search in order to find the nearest descendant of
1550
-     * the specified type and returns it, else NULL
1551
-     *
1552
-     * @param EE_Line_Item $parent_line_item - the line item to find descendants of
1553
-     * @param string       $type             like one of the EEM_Line_Item::type_*
1554
-     * @return EE_Line_Item
1555
-     * @throws EE_Error
1556
-     * @throws InvalidArgumentException
1557
-     * @throws InvalidDataTypeException
1558
-     * @throws InvalidInterfaceException
1559
-     * @throws ReflectionException
1560
-     * @uses  EEH_Line_Item::_get_nearest_descendant()
1561
-     */
1562
-    public static function get_nearest_descendant_of_type(EE_Line_Item $parent_line_item, string $type): ?EE_Line_Item
1563
-    {
1564
-        return self::_get_nearest_descendant($parent_line_item, 'LIN_type', $type);
1565
-    }
1566
-
1567
-
1568
-    /**
1569
-     * Uses a breadth-first-search in order to find the nearest descendant
1570
-     * having the specified LIN_code and returns it, else NULL
1571
-     *
1572
-     * @param EE_Line_Item $parent_line_item - the line item to find descendants of
1573
-     * @param string       $code             any value used for LIN_code
1574
-     * @return EE_Line_Item
1575
-     * @throws EE_Error
1576
-     * @throws InvalidArgumentException
1577
-     * @throws InvalidDataTypeException
1578
-     * @throws InvalidInterfaceException
1579
-     * @throws ReflectionException
1580
-     * @uses  EEH_Line_Item::_get_nearest_descendant()
1581
-     */
1582
-    public static function get_nearest_descendant_having_code(
1583
-        EE_Line_Item $parent_line_item,
1584
-        string $code
1585
-    ): ?EE_Line_Item {
1586
-        return self::_get_nearest_descendant($parent_line_item, 'LIN_code', $code);
1587
-    }
1588
-
1589
-
1590
-    /**
1591
-     * Uses a breadth-first-search in order to find the nearest descendant
1592
-     * having the specified LIN_code and returns it, else NULL
1593
-     *
1594
-     * @param EE_Line_Item $parent_line_item - the line item to find descendants of
1595
-     * @param string       $search_field     name of EE_Line_Item property
1596
-     * @param mixed        $value            any value stored in $search_field
1597
-     * @return EE_Line_Item
1598
-     * @throws EE_Error
1599
-     * @throws InvalidArgumentException
1600
-     * @throws InvalidDataTypeException
1601
-     * @throws InvalidInterfaceException
1602
-     * @throws ReflectionException
1603
-     */
1604
-    protected static function _get_nearest_descendant(
1605
-        EE_Line_Item $parent_line_item,
1606
-        string $search_field,
1607
-        $value
1608
-    ): ?EE_Line_Item {
1609
-        foreach ($parent_line_item->children() as $child) {
1610
-            if ($child->get($search_field) == $value) {
1611
-                return $child;
1612
-            }
1613
-        }
1614
-        foreach ($parent_line_item->children() as $child) {
1615
-            $descendant_found = self::_get_nearest_descendant(
1616
-                $child,
1617
-                $search_field,
1618
-                $value
1619
-            );
1620
-            if ($descendant_found) {
1621
-                return $descendant_found;
1622
-            }
1623
-        }
1624
-        return null;
1625
-    }
1626
-
1627
-
1628
-    /**
1629
-     * if passed line item has a TXN ID, uses that to jump directly to the grand total line item for the transaction,
1630
-     * else recursively walks up the line item tree until a parent of type total is found,
1631
-     *
1632
-     * @param EE_Line_Item $line_item
1633
-     * @return EE_Line_Item
1634
-     * @throws EE_Error
1635
-     * @throws ReflectionException
1636
-     */
1637
-    public static function find_transaction_grand_total_for_line_item(EE_Line_Item $line_item): EE_Line_Item
1638
-    {
1639
-        if ($line_item->is_total()) {
1640
-            return $line_item;
1641
-        }
1642
-        if ($line_item->TXN_ID()) {
1643
-            $total_line_item = $line_item->transaction()->total_line_item(false);
1644
-            if ($total_line_item instanceof EE_Line_Item) {
1645
-                return $total_line_item;
1646
-            }
1647
-        } else {
1648
-            $line_item_parent = $line_item->parent();
1649
-            if ($line_item_parent instanceof EE_Line_Item) {
1650
-                if ($line_item_parent->is_total()) {
1651
-                    return $line_item_parent;
1652
-                }
1653
-                return EEH_Line_Item::find_transaction_grand_total_for_line_item($line_item_parent);
1654
-            }
1655
-        }
1656
-        throw new EE_Error(
1657
-            sprintf(
1658
-                esc_html__(
1659
-                    'A valid grand total for line item %1$d was not found.',
1660
-                    'event_espresso'
1661
-                ),
1662
-                $line_item->ID()
1663
-            )
1664
-        );
1665
-    }
1666
-
1667
-
1668
-    /**
1669
-     * Prints out a representation of the line item tree
1670
-     *
1671
-     * @param EE_Line_Item $line_item
1672
-     * @param int          $indentation
1673
-     * @param bool         $top_level
1674
-     * @return void
1675
-     * @throws EE_Error
1676
-     * @throws ReflectionException
1677
-     */
1678
-    public static function visualize(EE_Line_Item $line_item, int $indentation = 0, bool $top_level = true)
1679
-    {
1680
-        if (! defined('WP_DEBUG') || ! WP_DEBUG) {
1681
-            return;
1682
-        }
1683
-        $testing  = defined('EE_TESTS_DIR');
1684
-        $new_line = $testing ? "\n" : '<br />';
1685
-        if ($top_level && ! $testing) {
1686
-            echo '<div style="position: relative; z-index: 9999; margin: 2rem;">';
1687
-            echo '<pre style="padding: 2rem 3rem; color: #00CCFF; background: #363636;">';
1688
-        }
1689
-        if ($top_level || $indentation) {
1690
-            echo $new_line;
1691
-        }
1692
-        echo str_repeat('. ', $indentation);
1693
-        $breakdown = '';
1694
-        if ($line_item->is_line_item() || $line_item->is_sub_line_item() || $line_item->isSubTax()) {
1695
-            if ($line_item->is_percent()) {
1696
-                $breakdown = "{$line_item->percent()}%";
1697
-            } else {
1698
-                $breakdown = "\${$line_item->unit_price()} x {$line_item->quantity()}";
1699
-            }
1700
-        }
1701
-        echo wp_kses($line_item->name(), AllowedTags::getAllowedTags());
1702
-        echo " [ ID:{$line_item->ID()} | qty:{$line_item->quantity()} ] {$line_item->type()}";
1703
-        echo " : \${$line_item->total()} : \${$line_item->pretaxTotal()}";
1704
-        if ($breakdown) {
1705
-            echo " ( $breakdown )";
1706
-        }
1707
-        if ($line_item->is_taxable()) {
1708
-            echo '  * taxable';
1709
-        }
1710
-        if ($line_item->children()) {
1711
-            foreach ($line_item->children() as $child) {
1712
-                self::visualize($child, $indentation + 1, false);
1713
-            }
1714
-        }
1715
-        if ($top_level && ! $testing) {
1716
-            echo $new_line;
1717
-            echo '</pre></div>';
1718
-        }
1719
-    }
1720
-
1721
-
1722
-    /**
1723
-     * Calculates the registration's final price, taking into account that they
1724
-     * need to not only help pay for their OWN ticket, but also any transaction-wide surcharges and taxes,
1725
-     * and receive a portion of any transaction-wide discounts.
1726
-     * eg1, if I buy a $1 ticket and brent buys a $9 ticket, and we receive a $5 discount
1727
-     * then I'll get 1/10 of that $5 discount, which is $0.50, and brent will get
1728
-     * 9/10ths of that $5 discount, which is $4.50. So my final price should be $0.50
1729
-     * and brent's final price should be $5.50.
1730
-     * In order to do this, we basically need to traverse the line item tree calculating
1731
-     * the running totals (just as if we were recalculating the total), but when we identify
1732
-     * regular line items, we need to keep track of their share of the grand total.
1733
-     * Also, we need to keep track of the TAXABLE total for each ticket purchase, so
1734
-     * we can know how to apply taxes to it. (Note: "taxable total" does not equal the "pretax total"
1735
-     * when there are non-taxable items; otherwise they would be the same)
1736
-     *
1737
-     * @param EE_Line_Item $line_item
1738
-     * @param array        $billable_ticket_quantities          array of EE_Ticket IDs and their corresponding quantity
1739
-     *                                                          that can be included in price calculations at this
1740
-     *                                                          moment
1741
-     * @return array        keys are line items for tickets IDs and values are their share of the running total,
1742
-     *                                                          plus the key 'total', and 'taxable' which also has keys
1743
-     *                                                          of all the ticket IDs. Eg array(
1744
-     *                                                          12 => 4.3
1745
-     *                                                          23 => 8.0
1746
-     *                                                          'total' => 16.6,
1747
-     *                                                          'taxable' => array(
1748
-     *                                                          12 => 10,
1749
-     *                                                          23 => 4
1750
-     *                                                          ).
1751
-     *                                                          So to find which registrations have which final price,
1752
-     *                                                          we need to find which line item is theirs, which can be
1753
-     *                                                          done with
1754
-     *                                                          `EEM_Line_Item::instance()->get_line_item_for_registration(
1755
-     *                                                          $registration );`
1756
-     * @throws EE_Error
1757
-     * @throws InvalidArgumentException
1758
-     * @throws InvalidDataTypeException
1759
-     * @throws InvalidInterfaceException
1760
-     * @throws ReflectionException
1761
-     */
1762
-    public static function calculate_reg_final_prices_per_line_item(
1763
-        EE_Line_Item $line_item,
1764
-        array $billable_ticket_quantities = []
1765
-    ): array {
1766
-        $running_totals = [
1767
-            'total'   => 0,
1768
-            'taxable' => ['total' => 0],
1769
-        ];
1770
-        foreach ($line_item->children() as $child_line_item) {
1771
-            switch ($child_line_item->type()) {
1772
-                case EEM_Line_Item::type_sub_total:
1773
-                    $running_totals_from_subtotal = EEH_Line_Item::calculate_reg_final_prices_per_line_item(
1774
-                        $child_line_item,
1775
-                        $billable_ticket_quantities
1776
-                    );
1777
-                    // combine arrays but preserve numeric keys
1778
-                    $running_totals                     = array_replace_recursive(
1779
-                        $running_totals_from_subtotal,
1780
-                        $running_totals
1781
-                    );
1782
-                    $running_totals['total']            += $running_totals_from_subtotal['total'];
1783
-                    $running_totals['taxable']['total'] += $running_totals_from_subtotal['taxable']['total'];
1784
-                    break;
1785
-
1786
-                case EEM_Line_Item::type_tax_sub_total:
1787
-                    // find how much the taxes percentage is
1788
-                    if ($child_line_item->percent() !== 0.0) {
1789
-                        $tax_percent_decimal = $child_line_item->percent() / 100;
1790
-                    } else {
1791
-                        $tax_percent_decimal = EE_Taxes::get_total_taxes_percentage() / 100;
1792
-                    }
1793
-                    // and apply to all the taxable totals, and add to the pretax totals
1794
-                    foreach ($running_totals as $line_item_id => $this_running_total) {
1795
-                        // "total" and "taxable" array key is an exception
1796
-                        if ($line_item_id === 'taxable') {
1797
-                            continue;
1798
-                        }
1799
-                        $taxable_total                   = $running_totals['taxable'][ $line_item_id ];
1800
-                        $running_totals[ $line_item_id ] += ($taxable_total * $tax_percent_decimal);
1801
-                    }
1802
-                    break;
1803
-
1804
-                case EEM_Line_Item::type_line_item:
1805
-                    // ticket line items or ????
1806
-                    if ($child_line_item->OBJ_type() === EEM_Line_Item::OBJ_TYPE_TICKET) {
1807
-                        // kk it's a ticket
1808
-                        if (isset($running_totals[ $child_line_item->ID() ])) {
1809
-                            // huh? that shouldn't happen.
1810
-                            $running_totals['total'] += $child_line_item->total();
1811
-                        } else {
1812
-                            // it's not in our running totals yet. great.
1813
-                            if ($child_line_item->is_taxable()) {
1814
-                                $taxable_amount = $child_line_item->unit_price();
1815
-                            } else {
1816
-                                $taxable_amount = 0;
1817
-                            }
1818
-                            // are we only calculating totals for some tickets?
1819
-                            if (isset($billable_ticket_quantities[ $child_line_item->OBJ_ID() ])) {
1820
-                                $quantity = $billable_ticket_quantities[ $child_line_item->OBJ_ID() ];
1821
-
1822
-                                $running_totals[ $child_line_item->ID() ]            = $quantity
1823
-                                    ? $child_line_item->unit_price()
1824
-                                    : 0;
1825
-                                $running_totals['taxable'][ $child_line_item->ID() ] = $quantity
1826
-                                    ? $taxable_amount
1827
-                                    : 0;
1828
-                            } else {
1829
-                                $quantity                                            = $child_line_item->quantity();
1830
-                                $running_totals[ $child_line_item->ID() ]            = $child_line_item->unit_price();
1831
-                                $running_totals['taxable'][ $child_line_item->ID() ] = $taxable_amount;
1832
-                            }
1833
-                            $running_totals['taxable']['total'] += $taxable_amount * $quantity;
1834
-                            $running_totals['total']            += $child_line_item->unit_price() * $quantity;
1835
-                        }
1836
-                    } else {
1837
-                        // it's some other type of item added to the cart
1838
-                        // it should affect the running totals
1839
-                        // basically we want to convert it into a PERCENT modifier. Because
1840
-                        // more clearly affect all registration's final price equally
1841
-                        $line_items_percent_of_running_total = $running_totals['total'] > 0
1842
-                            ? ($child_line_item->total() / $running_totals['total']) + 1
1843
-                            : 1;
1844
-                        foreach ($running_totals as $line_item_id => $this_running_total) {
1845
-                            // the "taxable" array key is an exception
1846
-                            if ($line_item_id === 'taxable') {
1847
-                                continue;
1848
-                            }
1849
-                            // update the running totals
1850
-                            // yes this actually even works for the running grand total!
1851
-                            $running_totals[ $line_item_id ] =
1852
-                                $line_items_percent_of_running_total * $this_running_total;
1853
-
1854
-                            if ($child_line_item->is_taxable()) {
1855
-                                $running_totals['taxable'][ $line_item_id ] =
1856
-                                    $line_items_percent_of_running_total * $running_totals['taxable'][ $line_item_id ];
1857
-                            }
1858
-                        }
1859
-                    }
1860
-                    break;
1861
-            }
1862
-        }
1863
-        return $running_totals;
1864
-    }
1865
-
1866
-
1867
-    /**
1868
-     * @param EE_Line_Item $total_line_item
1869
-     * @param EE_Line_Item $ticket_line_item
1870
-     * @return float | null
1871
-     * @throws EE_Error
1872
-     * @throws InvalidArgumentException
1873
-     * @throws InvalidDataTypeException
1874
-     * @throws InvalidInterfaceException
1875
-     * @throws OutOfRangeException
1876
-     * @throws ReflectionException
1877
-     */
1878
-    public static function calculate_final_price_for_ticket_line_item(
1879
-        EE_Line_Item $total_line_item,
1880
-        EE_Line_Item $ticket_line_item
1881
-    ): ?float {
1882
-        static $final_prices_per_ticket_line_item = [];
1883
-        if (
1884
-            empty($final_prices_per_ticket_line_item)
1885
-            || empty($final_prices_per_ticket_line_item[ $total_line_item->ID() ])
1886
-        ) {
1887
-            $final_prices_per_ticket_line_item[ $total_line_item->ID() ] =
1888
-                EEH_Line_Item::calculate_reg_final_prices_per_line_item(
1889
-                    $total_line_item
1890
-                );
1891
-        }
1892
-        // ok now find this new registration's final price
1893
-        if (isset($final_prices_per_ticket_line_item[ $total_line_item->ID() ][ $ticket_line_item->ID() ])) {
1894
-            return $final_prices_per_ticket_line_item[ $total_line_item->ID() ][ $ticket_line_item->ID() ];
1895
-        }
1896
-        $message = sprintf(
1897
-            esc_html__(
1898
-                'The final price for the ticket line item (ID:%1$d) on the total line item (ID:%2$d) could not be calculated.',
1899
-                'event_espresso'
1900
-            ),
1901
-            $ticket_line_item->ID(),
1902
-            $total_line_item->ID()
1903
-        );
1904
-        if (WP_DEBUG) {
1905
-            $message .= '<br>' . print_r($final_prices_per_ticket_line_item, true);
1906
-            throw new OutOfRangeException($message);
1907
-        }
1908
-        EE_Log::instance()->log(__CLASS__, __FUNCTION__, $message);
1909
-        return null;
1910
-    }
1911
-
1912
-
1913
-    /**
1914
-     * Creates a duplicate of the line item tree, except only includes billable items
1915
-     * and the portion of line items attributed to billable things
1916
-     *
1917
-     * @param EE_Line_Item      $line_item
1918
-     * @param EE_Registration[] $registrations
1919
-     * @return EE_Line_Item
1920
-     * @throws EE_Error
1921
-     * @throws InvalidArgumentException
1922
-     * @throws InvalidDataTypeException
1923
-     * @throws InvalidInterfaceException
1924
-     * @throws ReflectionException
1925
-     */
1926
-    public static function billable_line_item_tree(EE_Line_Item $line_item, array $registrations): EE_Line_Item
1927
-    {
1928
-        $copy_li = EEH_Line_Item::billable_line_item($line_item, $registrations);
1929
-        foreach ($line_item->children() as $child_li) {
1930
-            $copy_li->add_child_line_item(
1931
-                EEH_Line_Item::billable_line_item_tree($child_li, $registrations)
1932
-            );
1933
-        }
1934
-        // if this is the grand total line item, make sure the totals all add up
1935
-        // (we could have duplicated this logic AS we copied the line items, but
1936
-        // it seems DRYer this way)
1937
-        if ($copy_li->type() === EEM_Line_Item::type_total) {
1938
-            $copy_li->recalculate_total_including_taxes();
1939
-        }
1940
-        return $copy_li;
1941
-    }
1942
-
1943
-
1944
-    /**
1945
-     * Creates a new, unsaved line item from $line_item that factors in the
1946
-     * number of billable registrations on $registrations.
1947
-     *
1948
-     * @param EE_Line_Item      $line_item
1949
-     * @param EE_Registration[] $registrations
1950
-     * @return EE_Line_Item
1951
-     * @throws EE_Error
1952
-     * @throws InvalidArgumentException
1953
-     * @throws InvalidDataTypeException
1954
-     * @throws InvalidInterfaceException
1955
-     * @throws ReflectionException
1956
-     */
1957
-    public static function billable_line_item(EE_Line_Item $line_item, array $registrations): EE_Line_Item
1958
-    {
1959
-        $new_li_fields = $line_item->model_field_array();
1960
-        if (
1961
-            $line_item->type() === EEM_Line_Item::type_line_item &&
1962
-            $line_item->OBJ_type() === EEM_Line_Item::OBJ_TYPE_TICKET
1963
-        ) {
1964
-            $count = 0;
1965
-            foreach ($registrations as $registration) {
1966
-                if (
1967
-                    $line_item->OBJ_ID() === $registration->ticket_ID() &&
1968
-                    in_array(
1969
-                        $registration->status_ID(),
1970
-                        EEM_Registration::reg_statuses_that_allow_payment(),
1971
-                        true
1972
-                    )
1973
-                ) {
1974
-                    $count++;
1975
-                }
1976
-            }
1977
-            $new_li_fields['LIN_quantity'] = $count;
1978
-        }
1979
-        // don't set the total. We'll leave that up to the code that calculates it
1980
-        unset($new_li_fields['LIN_ID'], $new_li_fields['LIN_parent'], $new_li_fields['LIN_total']);
1981
-        return EE_Line_Item::new_instance($new_li_fields);
1982
-    }
1983
-
1984
-
1985
-    /**
1986
-     * Returns a modified line item tree where all the subtotals which have a total of 0
1987
-     * are removed, and line items with a quantity of 0
1988
-     *
1989
-     * @param EE_Line_Item $line_item |null
1990
-     * @return EE_Line_Item|null
1991
-     * @throws EE_Error
1992
-     * @throws InvalidArgumentException
1993
-     * @throws InvalidDataTypeException
1994
-     * @throws InvalidInterfaceException
1995
-     * @throws ReflectionException
1996
-     */
1997
-    public static function non_empty_line_items(EE_Line_Item $line_item): ?EE_Line_Item
1998
-    {
1999
-        $copied_li = EEH_Line_Item::non_empty_line_item($line_item);
2000
-        if ($copied_li === null) {
2001
-            return null;
2002
-        }
2003
-        // if this is an event subtotal, we want to only include it if it
2004
-        // has a non-zero total and at least one ticket line item child
2005
-        $ticket_children = 0;
2006
-        foreach ($line_item->children() as $child_li) {
2007
-            $child_li_copy = EEH_Line_Item::non_empty_line_items($child_li);
2008
-            if ($child_li_copy !== null) {
2009
-                $copied_li->add_child_line_item($child_li_copy);
2010
-                if (
2011
-                    $child_li_copy->type() === EEM_Line_Item::type_line_item &&
2012
-                    $child_li_copy->OBJ_type() === EEM_Line_Item::OBJ_TYPE_TICKET
2013
-                ) {
2014
-                    $ticket_children++;
2015
-                }
2016
-            }
2017
-        }
2018
-        // if this is an event subtotal with NO ticket children
2019
-        // we basically want to ignore it
2020
-        if (
2021
-            $ticket_children === 0
2022
-            && $line_item->type() === EEM_Line_Item::type_sub_total
2023
-            && $line_item->OBJ_type() === EEM_Line_Item::OBJ_TYPE_EVENT
2024
-            && $line_item->total() === 0.0
2025
-        ) {
2026
-            return null;
2027
-        }
2028
-        return $copied_li;
2029
-    }
2030
-
2031
-
2032
-    /**
2033
-     * Creates a new, unsaved line item, but if it's a ticket line item
2034
-     * with a total of 0, or a subtotal of 0, returns null instead
2035
-     *
2036
-     * @param EE_Line_Item $line_item
2037
-     * @return EE_Line_Item
2038
-     * @throws EE_Error
2039
-     * @throws InvalidArgumentException
2040
-     * @throws InvalidDataTypeException
2041
-     * @throws InvalidInterfaceException
2042
-     * @throws ReflectionException
2043
-     */
2044
-    public static function non_empty_line_item(EE_Line_Item $line_item): ?EE_Line_Item
2045
-    {
2046
-        if (
2047
-            $line_item->type() === EEM_Line_Item::type_line_item
2048
-            && $line_item->OBJ_type() === EEM_Line_Item::OBJ_TYPE_TICKET
2049
-            && $line_item->quantity() === 0
2050
-        ) {
2051
-            return null;
2052
-        }
2053
-        $new_li_fields = $line_item->model_field_array();
2054
-        // don't set the total. We'll leave that up to the code that calculates it
2055
-        unset($new_li_fields['LIN_ID'], $new_li_fields['LIN_parent']);
2056
-        return EE_Line_Item::new_instance($new_li_fields);
2057
-    }
2058
-
2059
-
2060
-    /**
2061
-     * Cycles through all the ticket line items for the supplied total line item
2062
-     * and ensures that the line item's "is_taxable" field matches that of its corresponding ticket
2063
-     *
2064
-     * @param EE_Line_Item $total_line_item
2065
-     * @throws EE_Error
2066
-     * @throws InvalidArgumentException
2067
-     * @throws InvalidDataTypeException
2068
-     * @throws InvalidInterfaceException
2069
-     * @throws ReflectionException
2070
-     * @since 4.9.79.p
2071
-     */
2072
-    public static function resetIsTaxableForTickets(EE_Line_Item $total_line_item)
2073
-    {
2074
-        $ticket_line_items = self::get_ticket_line_items($total_line_item);
2075
-        foreach ($ticket_line_items as $ticket_line_item) {
2076
-            if (
2077
-                $ticket_line_item instanceof EE_Line_Item
2078
-                && $ticket_line_item->OBJ_type() === EEM_Line_Item::OBJ_TYPE_TICKET
2079
-            ) {
2080
-                $ticket = $ticket_line_item->ticket();
2081
-                if ($ticket instanceof EE_Ticket && $ticket->taxable() !== $ticket_line_item->is_taxable()) {
2082
-                    $ticket_line_item->set_is_taxable($ticket->taxable());
2083
-                    $ticket_line_item->save();
2084
-                }
2085
-            }
2086
-        }
2087
-    }
2088
-
2089
-
2090
-    /**
2091
-     * @return EE_Line_Item[]
2092
-     * @throws EE_Error
2093
-     * @throws ReflectionException
2094
-     * @since   5.0.0.p
2095
-     */
2096
-    private static function getGlobalTaxes(): array
2097
-    {
2098
-        if (EEH_Line_Item::$global_taxes === null) {
2099
-            /** @type EEM_Price $EEM_Price */
2100
-            $EEM_Price = EE_Registry::instance()->load_model('Price');
2101
-            // get array of taxes via Price Model
2102
-            EEH_Line_Item::$global_taxes = $EEM_Price->get_all_prices_that_are_taxes();
2103
-            ksort(EEH_Line_Item::$global_taxes);
2104
-        }
2105
-        return EEH_Line_Item::$global_taxes;
2106
-    }
2107
-
2108
-
2109
-
2110
-    /**************************************** @DEPRECATED METHODS *************************************** */
2111
-    /**
2112
-     * @param EE_Line_Item $total_line_item
2113
-     * @return EE_Line_Item
2114
-     * @throws EE_Error
2115
-     * @throws InvalidArgumentException
2116
-     * @throws InvalidDataTypeException
2117
-     * @throws InvalidInterfaceException
2118
-     * @throws ReflectionException
2119
-     * @deprecated
2120
-     */
2121
-    public static function get_items_subtotal(EE_Line_Item $total_line_item): EE_Line_Item
2122
-    {
2123
-        EE_Error::doing_it_wrong(
2124
-            'EEH_Line_Item::get_items_subtotal()',
2125
-            sprintf(
2126
-                esc_html__('Method replaced with %1$s', 'event_espresso'),
2127
-                'EEH_Line_Item::get_pre_tax_subtotal()'
2128
-            ),
2129
-            '4.6.0'
2130
-        );
2131
-        return self::get_pre_tax_subtotal($total_line_item);
2132
-    }
2133
-
2134
-
2135
-    /**
2136
-     * @param EE_Transaction|null $transaction
2137
-     * @return EE_Line_Item
2138
-     * @throws EE_Error
2139
-     * @throws InvalidArgumentException
2140
-     * @throws InvalidDataTypeException
2141
-     * @throws InvalidInterfaceException
2142
-     * @throws ReflectionException
2143
-     * @deprecated
2144
-     */
2145
-    public static function create_default_total_line_item(?EE_Transaction $transaction = null): EE_Line_Item
2146
-    {
2147
-        EE_Error::doing_it_wrong(
2148
-            'EEH_Line_Item::create_default_total_line_item()',
2149
-            sprintf(
2150
-                esc_html__('Method replaced with %1$s', 'event_espresso'),
2151
-                'EEH_Line_Item::create_total_line_item()'
2152
-            ),
2153
-            '4.6.0'
2154
-        );
2155
-        return self::create_total_line_item($transaction);
2156
-    }
2157
-
2158
-
2159
-    /**
2160
-     * @param EE_Line_Item        $total_line_item
2161
-     * @param EE_Transaction|null $transaction
2162
-     * @return EE_Line_Item
2163
-     * @throws EE_Error
2164
-     * @throws InvalidArgumentException
2165
-     * @throws InvalidDataTypeException
2166
-     * @throws InvalidInterfaceException
2167
-     * @throws ReflectionException
2168
-     * @deprecated
2169
-     */
2170
-    public static function create_default_tickets_subtotal(
2171
-        EE_Line_Item $total_line_item,
2172
-        ?EE_Transaction $transaction = null
2173
-    ): EE_Line_Item {
2174
-        EE_Error::doing_it_wrong(
2175
-            'EEH_Line_Item::create_default_tickets_subtotal()',
2176
-            sprintf(
2177
-                esc_html__('Method replaced with %1$s', 'event_espresso'),
2178
-                'EEH_Line_Item::create_pre_tax_subtotal()'
2179
-            ),
2180
-            '4.6.0'
2181
-        );
2182
-        return self::create_pre_tax_subtotal($total_line_item, $transaction);
2183
-    }
2184
-
2185
-
2186
-    /**
2187
-     * @param EE_Line_Item        $total_line_item
2188
-     * @param EE_Transaction|null $transaction
2189
-     * @return EE_Line_Item
2190
-     * @throws EE_Error
2191
-     * @throws InvalidArgumentException
2192
-     * @throws InvalidDataTypeException
2193
-     * @throws InvalidInterfaceException
2194
-     * @throws ReflectionException
2195
-     * @deprecated
2196
-     */
2197
-    public static function create_default_taxes_subtotal(
2198
-        EE_Line_Item $total_line_item,
2199
-        ?EE_Transaction $transaction = null
2200
-    ): EE_Line_Item {
2201
-        EE_Error::doing_it_wrong(
2202
-            'EEH_Line_Item::create_default_taxes_subtotal()',
2203
-            sprintf(
2204
-                esc_html__('Method replaced with %1$s', 'event_espresso'),
2205
-                'EEH_Line_Item::create_taxes_subtotal()'
2206
-            ),
2207
-            '4.6.0'
2208
-        );
2209
-        return self::create_taxes_subtotal($total_line_item, $transaction);
2210
-    }
2211
-
2212
-
2213
-    /**
2214
-     * @param EE_Line_Item        $total_line_item
2215
-     * @param EE_Transaction|null $transaction
2216
-     * @return EE_Line_Item
2217
-     * @throws EE_Error
2218
-     * @throws InvalidArgumentException
2219
-     * @throws InvalidDataTypeException
2220
-     * @throws InvalidInterfaceException
2221
-     * @throws ReflectionException
2222
-     * @deprecated
2223
-     */
2224
-    public static function create_default_event_subtotal(
2225
-        EE_Line_Item $total_line_item,
2226
-        ?EE_Transaction $transaction = null
2227
-    ): EE_Line_Item {
2228
-        EE_Error::doing_it_wrong(
2229
-            'EEH_Line_Item::create_default_event_subtotal()',
2230
-            sprintf(
2231
-                esc_html__('Method replaced with %1$s', 'event_espresso'),
2232
-                'EEH_Line_Item::create_event_subtotal()'
2233
-            ),
2234
-            '4.6.0'
2235
-        );
2236
-        return self::create_event_subtotal($total_line_item, $transaction);
2237
-    }
24
+	/**
25
+	 * @var EE_Line_Item[]|null
26
+	 */
27
+	private static ?array $global_taxes = null;
28
+
29
+
30
+	/**
31
+	 * Adds a simple item (unrelated to any other model object) to the provided PARENT line item.
32
+	 * Does NOT automatically re-calculate the line item totals or update the related transaction.
33
+	 * You should call recalculate_total_including_taxes() on the grant total line item after this
34
+	 * to update the subtotals, and EE_Registration_Processor::calculate_reg_final_prices_per_line_item()
35
+	 * to keep the registration final prices in-sync with the transaction's total.
36
+	 *
37
+	 * @param EE_Line_Item $parent_line_item
38
+	 * @param string       $name
39
+	 * @param float        $unit_price
40
+	 * @param string       $description
41
+	 * @param int          $quantity
42
+	 * @param boolean      $taxable
43
+	 * @param string|null  $code if set to a value, ensures there is only one line item with that code
44
+	 * @param bool         $return_item
45
+	 * @param bool         $recalculate_totals
46
+	 * @return boolean|EE_Line_Item success
47
+	 * @throws EE_Error
48
+	 * @throws ReflectionException
49
+	 */
50
+	public static function add_unrelated_item(
51
+		EE_Line_Item $parent_line_item,
52
+		string $name,
53
+		float $unit_price,
54
+		string $description = '',
55
+		int $quantity = 1,
56
+		bool $taxable = false,
57
+		?string $code = null,
58
+		bool $return_item = false,
59
+		bool $recalculate_totals = true
60
+	) {
61
+		$items_subtotal = self::get_pre_tax_subtotal($parent_line_item);
62
+		$line_item      = EE_Line_Item::new_instance(
63
+			[
64
+				'LIN_name'       => $name,
65
+				'LIN_desc'       => $description,
66
+				'LIN_unit_price' => $unit_price,
67
+				'LIN_quantity'   => $quantity,
68
+				'LIN_percent'    => null,
69
+				'LIN_is_taxable' => $taxable,
70
+				'LIN_order'      => count($items_subtotal->children()),
71
+				'LIN_total'      => $unit_price * $quantity,
72
+				'LIN_type'       => EEM_Line_Item::type_line_item,
73
+				'LIN_code'       => $code,
74
+			]
75
+		);
76
+		$line_item      = apply_filters(
77
+			'FHEE__EEH_Line_Item__add_unrelated_item__line_item',
78
+			$line_item,
79
+			$parent_line_item
80
+		);
81
+		$added          = self::add_item($parent_line_item, $line_item, $recalculate_totals);
82
+		return $return_item ? $line_item : $added;
83
+	}
84
+
85
+
86
+	/**
87
+	 * Adds a simple item ( unrelated to any other model object) to the total line item,
88
+	 * in the correct spot in the line item tree. Does not automatically
89
+	 * re-calculate the line item totals, nor update the related transaction, nor upgrade the transaction's
90
+	 * registrations' final prices (which should probably change because of this).
91
+	 * You should call recalculate_total_including_taxes() on the grand total line item, then
92
+	 * update the transaction's total, and EE_Registration_Processor::update_registration_final_prices()
93
+	 * after using this, to keep the registration final prices in-sync with the transaction's total.
94
+	 *
95
+	 * @param EE_Line_Item $parent_line_item
96
+	 * @param string       $name
97
+	 * @param float        $percentage_amount
98
+	 * @param string       $description
99
+	 * @param boolean      $taxable
100
+	 * @param string|null  $code
101
+	 * @param bool         $return_item
102
+	 * @return boolean|EE_Line_Item success
103
+	 * @throws EE_Error
104
+	 * @throws ReflectionException
105
+	 */
106
+	public static function add_percentage_based_item(
107
+		EE_Line_Item $parent_line_item,
108
+		string $name,
109
+		float $percentage_amount,
110
+		string $description = '',
111
+		bool $taxable = false,
112
+		?string $code = null,
113
+		bool $return_item = false
114
+	) {
115
+		$total     = $percentage_amount * $parent_line_item->total() / 100;
116
+		$line_item = EE_Line_Item::new_instance(
117
+			[
118
+				'LIN_name'       => $name,
119
+				'LIN_desc'       => $description,
120
+				'LIN_unit_price' => 0,
121
+				'LIN_percent'    => $percentage_amount,
122
+				'LIN_quantity'   => 1,
123
+				'LIN_is_taxable' => $taxable,
124
+				'LIN_total'      => $total,
125
+				'LIN_type'       => EEM_Line_Item::type_line_item,
126
+				'LIN_parent'     => $parent_line_item->ID(),
127
+				'LIN_code'       => $code,
128
+			]
129
+		);
130
+		$line_item = apply_filters(
131
+			'FHEE__EEH_Line_Item__add_percentage_based_item__line_item',
132
+			$line_item
133
+		);
134
+		$added     = $parent_line_item->add_child_line_item($line_item, false);
135
+		return $return_item ? $line_item : $added;
136
+	}
137
+
138
+
139
+	/**
140
+	 * Returns the new line item created by adding a purchase of the ticket
141
+	 * ensures that ticket line item is saved, and that cart total has been recalculated.
142
+	 * If this ticket has already been purchased, just increments its count.
143
+	 * Automatically re-calculates the line item totals and updates the related transaction. But
144
+	 * DOES NOT automatically upgrade the transaction's registrations' final prices (which
145
+	 * should probably change because of this).
146
+	 * You should call EE_Registration_Processor::calculate_reg_final_prices_per_line_item()
147
+	 * after using this, to keep the registration final prices in-sync with the transaction's total.
148
+	 *
149
+	 * @param EE_Line_Item|null $total_line_item grand total line item of type EEM_Line_Item::type_total
150
+	 * @param EE_Ticket         $ticket
151
+	 * @param int               $qty
152
+	 * @param bool              $recalculate_totals
153
+	 * @return EE_Line_Item
154
+	 * @throws EE_Error
155
+	 * @throws ReflectionException
156
+	 */
157
+	public static function add_ticket_purchase(
158
+		?EE_Line_Item $total_line_item,
159
+		EE_Ticket $ticket,
160
+		int $qty = 1,
161
+		bool $recalculate_totals = true
162
+	): ?EE_Line_Item {
163
+		if (! $total_line_item instanceof EE_Line_Item || ! $total_line_item->is_total()) {
164
+			throw new EE_Error(
165
+				sprintf(
166
+					esc_html__(
167
+						'A valid line item total is required in order to add tickets. A line item of type "%s" was passed.',
168
+						'event_espresso'
169
+					),
170
+					$ticket->ID(),
171
+					$total_line_item->ID()
172
+				)
173
+			);
174
+		}
175
+		// either increment the qty for an existing ticket
176
+		$line_item = self::increment_ticket_qty_if_already_in_cart($total_line_item, $ticket, $qty);
177
+		// or add a new one
178
+		if (! $line_item instanceof EE_Line_Item) {
179
+			$line_item = self::create_ticket_line_item($total_line_item, $ticket, $qty);
180
+		}
181
+		if ($recalculate_totals) {
182
+			$total_line_item->recalculate_total_including_taxes();
183
+		}
184
+		return $line_item;
185
+	}
186
+
187
+
188
+	/**
189
+	 * Returns the new line item created by adding a purchase of the ticket
190
+	 *
191
+	 * @param EE_Line_Item|null $total_line_item
192
+	 * @param EE_Ticket         $ticket
193
+	 * @param int               $qty
194
+	 * @return EE_Line_Item
195
+	 * @throws EE_Error
196
+	 * @throws InvalidArgumentException
197
+	 * @throws InvalidDataTypeException
198
+	 * @throws InvalidInterfaceException
199
+	 * @throws ReflectionException
200
+	 */
201
+	public static function increment_ticket_qty_if_already_in_cart(
202
+		?EE_Line_Item $total_line_item,
203
+		EE_Ticket $ticket,
204
+		int $qty = 1
205
+	): ?EE_Line_Item {
206
+		$line_item = null;
207
+		if ($total_line_item instanceof EE_Line_Item && $total_line_item->is_total()) {
208
+			$ticket_line_items = EEH_Line_Item::get_ticket_line_items($total_line_item);
209
+			foreach ($ticket_line_items as $ticket_line_item) {
210
+				if (
211
+					$ticket_line_item instanceof EE_Line_Item
212
+					&& $ticket_line_item->OBJ_ID() === $ticket->ID()
213
+				) {
214
+					$line_item = $ticket_line_item;
215
+					break;
216
+				}
217
+			}
218
+		}
219
+		if ($line_item instanceof EE_Line_Item) {
220
+			EEH_Line_Item::increment_quantity($line_item, $qty);
221
+			return $line_item;
222
+		}
223
+		return null;
224
+	}
225
+
226
+
227
+	/**
228
+	 * Increments the line item and all its children's quantity by $qty (but percent line items are unaffected).
229
+	 * Does NOT save or recalculate other line items totals
230
+	 *
231
+	 * @param EE_Line_Item $line_item
232
+	 * @param int          $qty
233
+	 * @return void
234
+	 * @throws EE_Error
235
+	 * @throws InvalidArgumentException
236
+	 * @throws InvalidDataTypeException
237
+	 * @throws InvalidInterfaceException
238
+	 * @throws ReflectionException
239
+	 */
240
+	public static function increment_quantity(EE_Line_Item $line_item, int $qty = 1)
241
+	{
242
+		if (! $line_item->is_percent()) {
243
+			$qty += $line_item->quantity();
244
+			$line_item->set_quantity($qty);
245
+			$line_item->set_total($line_item->unit_price() * $qty);
246
+			$line_item->save();
247
+		}
248
+		foreach ($line_item->children() as $child) {
249
+			if ($child->is_sub_line_item()) {
250
+				EEH_Line_Item::update_quantity($child, $qty);
251
+			}
252
+		}
253
+	}
254
+
255
+
256
+	/**
257
+	 * Decrements the line item and all its children's quantity by $qty (but percent line items are unaffected).
258
+	 * Does NOT save or recalculate other line items totals
259
+	 *
260
+	 * @param EE_Line_Item $line_item
261
+	 * @param int          $qty
262
+	 * @return void
263
+	 * @throws EE_Error
264
+	 * @throws InvalidArgumentException
265
+	 * @throws InvalidDataTypeException
266
+	 * @throws InvalidInterfaceException
267
+	 * @throws ReflectionException
268
+	 */
269
+	public static function decrement_quantity(EE_Line_Item $line_item, int $qty = 1)
270
+	{
271
+		if (! $line_item->is_percent()) {
272
+			$qty = $line_item->quantity() - $qty;
273
+			$qty = max($qty, 0);
274
+			$line_item->set_quantity($qty);
275
+			$line_item->set_total($line_item->unit_price() * $qty);
276
+			$line_item->save();
277
+		}
278
+		foreach ($line_item->children() as $child) {
279
+			if ($child->is_sub_line_item()) {
280
+				EEH_Line_Item::update_quantity($child, $qty);
281
+			}
282
+		}
283
+	}
284
+
285
+
286
+	/**
287
+	 * Updates the line item and its children's quantities to the specified number.
288
+	 * Does NOT save them or recalculate totals.
289
+	 *
290
+	 * @param EE_Line_Item $line_item
291
+	 * @param int          $new_quantity
292
+	 * @throws EE_Error
293
+	 * @throws InvalidArgumentException
294
+	 * @throws InvalidDataTypeException
295
+	 * @throws InvalidInterfaceException
296
+	 * @throws ReflectionException
297
+	 */
298
+	public static function update_quantity(EE_Line_Item $line_item, int $new_quantity)
299
+	{
300
+		if (! $line_item->is_percent()) {
301
+			$line_item->set_quantity($new_quantity);
302
+			$line_item->set_total($line_item->unit_price() * $new_quantity);
303
+			$line_item->save();
304
+		}
305
+		foreach ($line_item->children() as $child) {
306
+			if ($child->is_sub_line_item()) {
307
+				EEH_Line_Item::update_quantity($child, $new_quantity);
308
+			}
309
+		}
310
+	}
311
+
312
+
313
+	/**
314
+	 * Returns the new line item created by adding a purchase of the ticket
315
+	 *
316
+	 * @param EE_Line_Item $total_line_item of type EEM_Line_Item::type_total
317
+	 * @param EE_Ticket    $ticket
318
+	 * @param int          $qty
319
+	 * @return EE_Line_Item
320
+	 * @throws EE_Error
321
+	 * @throws InvalidArgumentException
322
+	 * @throws InvalidDataTypeException
323
+	 * @throws InvalidInterfaceException
324
+	 * @throws ReflectionException
325
+	 */
326
+	public static function create_ticket_line_item(
327
+		EE_Line_Item $total_line_item,
328
+		EE_Ticket $ticket,
329
+		int $qty = 1
330
+	): EE_Line_Item {
331
+		$datetimes           = $ticket->datetimes();
332
+		$first_datetime      = reset($datetimes);
333
+		$first_datetime_name = esc_html__('Event', 'event_espresso');
334
+		if ($first_datetime instanceof EE_Datetime && $first_datetime->event() instanceof EE_Event) {
335
+			$first_datetime_name = $first_datetime->event()->name();
336
+		}
337
+		$event = sprintf(_x('(For %1$s)', '(For Event Name)', 'event_espresso'), $first_datetime_name);
338
+		// get event subtotal line
339
+		$events_sub_total = self::get_event_line_item_for_ticket($total_line_item, $ticket);
340
+		$taxes            = $ticket->tax_price_modifiers();
341
+		// add $ticket to cart
342
+		$line_item = EE_Line_Item::new_instance(
343
+			[
344
+				'LIN_name'       => $ticket->name(),
345
+				'LIN_desc'       => $ticket->description() !== '' ? $ticket->description() . ' ' . $event : $event,
346
+				'LIN_unit_price' => $ticket->price(),
347
+				'LIN_quantity'   => $qty,
348
+				'LIN_is_taxable' => empty($taxes) && $ticket->taxable(),
349
+				'LIN_order'      => count($events_sub_total->children()),
350
+				'LIN_total'      => $ticket->price() * $qty,
351
+				'LIN_type'       => EEM_Line_Item::type_line_item,
352
+				'OBJ_ID'         => $ticket->ID(),
353
+				'OBJ_type'       => EEM_Line_Item::OBJ_TYPE_TICKET,
354
+			]
355
+		);
356
+		$line_item = apply_filters(
357
+			'FHEE__EEH_Line_Item__create_ticket_line_item__line_item',
358
+			$line_item
359
+		);
360
+		if (! $line_item instanceof EE_Line_Item) {
361
+			throw new DomainException(
362
+				esc_html__('Invalid EE_Line_Item received.', 'event_espresso')
363
+			);
364
+		}
365
+		$events_sub_total->add_child_line_item($line_item);
366
+		// now add the sub-line items
367
+		$running_pre_tax_total = 0;
368
+		$prices                = $ticket->prices();
369
+		if (empty($prices)) {
370
+			// WUT?!?! NO PRICES??? Well, just create a default price then.
371
+			$default_price = EEM_Price::instance()->get_new_price();
372
+			if ($default_price->amount() !== $ticket->price()) {
373
+				$default_price->set_amount($ticket->price());
374
+			}
375
+			$default_price->save();
376
+			$ticket->_add_relation_to($default_price, 'Price');
377
+			$ticket->save();
378
+			$prices = [$default_price];
379
+		}
380
+		foreach ($prices as $price) {
381
+			$sign        = $price->is_discount() ? -1 : 1;
382
+			$price_total = $price->is_percent()
383
+				? $running_pre_tax_total * $price->amount() / 100
384
+				: $price->amount() * $qty;
385
+			if ($price->is_percent()) {
386
+				$percent    = $sign * $price->amount();
387
+				$unit_price = 0;
388
+			} else {
389
+				$percent    = 0;
390
+				$unit_price = $sign * $price->amount();
391
+			}
392
+
393
+			$price_desc = $price->desc();
394
+			$price_type = $price->type_obj();
395
+			$price_desc = $price_desc === '' && $price_type instanceof EE_Price_Type
396
+				? $price_type->name()
397
+				: $price_desc;
398
+
399
+			$sub_line_item         = EE_Line_Item::new_instance(
400
+				[
401
+					'LIN_name'       => $price->name(),
402
+					'LIN_desc'       => $price_desc,
403
+					'LIN_quantity'   => $price->is_percent() ? null : $qty,
404
+					'LIN_is_taxable' => false,
405
+					'LIN_order'      => $price->order(),
406
+					'LIN_total'      => $price_total,
407
+					'LIN_pretax'     => 0,
408
+					'LIN_unit_price' => $unit_price,
409
+					'LIN_percent'    => $percent,
410
+					'LIN_type'       => $price->is_tax() ? EEM_Line_Item::type_sub_tax
411
+						: EEM_Line_Item::type_sub_line_item,
412
+					'OBJ_ID'         => $price->ID(),
413
+					'OBJ_type'       => EEM_Line_Item::OBJ_TYPE_PRICE,
414
+				]
415
+			);
416
+			$sub_line_item         = apply_filters(
417
+				'FHEE__EEH_Line_Item__create_ticket_line_item__sub_line_item',
418
+				$sub_line_item
419
+			);
420
+			$running_pre_tax_total += ! $price->is_tax() ? $sign * $price_total : 0;
421
+			$line_item->add_child_line_item($sub_line_item);
422
+		}
423
+		$line_item->setPretaxTotal($running_pre_tax_total);
424
+		return $line_item;
425
+	}
426
+
427
+
428
+	/**
429
+	 * Adds the specified item under the pre-tax-sub-total line item. Automatically
430
+	 * re-calculates the line item totals and updates the related transaction. But
431
+	 * DOES NOT automatically upgrade the transaction's registrations' final prices (which
432
+	 * should probably change because of this).
433
+	 * You should call EE_Registration_Processor::calculate_reg_final_prices_per_line_item()
434
+	 * after using this, to keep the registration final prices in-sync with the transaction's total.
435
+	 *
436
+	 * @param EE_Line_Item $total_line_item
437
+	 * @param EE_Line_Item $item to be added
438
+	 * @param bool         $recalculate_totals
439
+	 * @return boolean
440
+	 * @throws EE_Error
441
+	 * @throws InvalidArgumentException
442
+	 * @throws InvalidDataTypeException
443
+	 * @throws InvalidInterfaceException
444
+	 * @throws ReflectionException
445
+	 */
446
+	public static function add_item(
447
+		EE_Line_Item $total_line_item,
448
+		EE_Line_Item $item,
449
+		bool $recalculate_totals = true
450
+	): bool {
451
+		$pre_tax_subtotal = self::get_pre_tax_subtotal($total_line_item);
452
+		$success          = $pre_tax_subtotal->add_child_line_item($item);
453
+		if ($recalculate_totals) {
454
+			$total_line_item->recalculate_total_including_taxes();
455
+		}
456
+		return $success;
457
+	}
458
+
459
+
460
+	/**
461
+	 * cancels an existing ticket line item,
462
+	 * by decrementing its quantity by 1 and adding a new "type_cancellation" sub-line-item.
463
+	 * ALL totals and subtotals will NEED TO BE UPDATED after performing this action
464
+	 *
465
+	 * @param EE_Line_Item $ticket_line_item
466
+	 * @param int          $qty
467
+	 * @return bool success
468
+	 * @throws EE_Error
469
+	 * @throws InvalidArgumentException
470
+	 * @throws InvalidDataTypeException
471
+	 * @throws InvalidInterfaceException
472
+	 * @throws ReflectionException
473
+	 */
474
+	public static function cancel_ticket_line_item(EE_Line_Item $ticket_line_item, int $qty = 1): bool
475
+	{
476
+		// validate incoming line_item
477
+		if ($ticket_line_item->OBJ_type() !== EEM_Line_Item::OBJ_TYPE_TICKET) {
478
+			throw new EE_Error(
479
+				sprintf(
480
+					esc_html__(
481
+						'The supplied line item must have an Object Type of "Ticket", not %1$s.',
482
+						'event_espresso'
483
+					),
484
+					$ticket_line_item->type()
485
+				)
486
+			);
487
+		}
488
+		if ($ticket_line_item->quantity() < $qty) {
489
+			throw new EE_Error(
490
+				sprintf(
491
+					esc_html__(
492
+						'Can not cancel %1$d ticket(s) because the supplied line item has a quantity of %2$d.',
493
+						'event_espresso'
494
+					),
495
+					$qty,
496
+					$ticket_line_item->quantity()
497
+				)
498
+			);
499
+		}
500
+		// decrement ticket quantity; don't rely on auto-fixing when recalculating totals to do this
501
+		$ticket_line_item->set_quantity($ticket_line_item->quantity() - $qty);
502
+		foreach ($ticket_line_item->children() as $child_line_item) {
503
+			if (
504
+				$child_line_item->is_sub_line_item()
505
+				&& ! $child_line_item->is_percent()
506
+				&& ! $child_line_item->is_cancellation()
507
+			) {
508
+				$child_line_item->set_quantity($child_line_item->quantity() - $qty);
509
+			}
510
+		}
511
+		// get cancellation sub line item
512
+		$cancellation_line_item = EEH_Line_Item::get_descendants_of_type(
513
+			$ticket_line_item,
514
+			EEM_Line_Item::type_cancellation
515
+		);
516
+		$cancellation_line_item = reset($cancellation_line_item);
517
+		// verify that this ticket was indeed previously cancelled
518
+		if ($cancellation_line_item instanceof EE_Line_Item) {
519
+			// increment cancelled quantity
520
+			$cancellation_line_item->set_quantity($cancellation_line_item->quantity() + $qty);
521
+		} else {
522
+			// create cancellation sub line item
523
+			$cancellation_line_item = EE_Line_Item::new_instance(
524
+				[
525
+					'LIN_name'       => esc_html__('Cancellation', 'event_espresso'),
526
+					'LIN_desc'       => sprintf(
527
+						esc_html_x(
528
+							'Cancelled %1$s : %2$s',
529
+							'Cancelled Ticket Name : 2015-01-01 11:11',
530
+							'event_espresso'
531
+						),
532
+						$ticket_line_item->name(),
533
+						current_time(get_option('date_format') . ' ' . get_option('time_format'))
534
+					),
535
+					'LIN_unit_price' => 0, // $ticket_line_item->unit_price()
536
+					'LIN_quantity'   => $qty,
537
+					'LIN_is_taxable' => $ticket_line_item->is_taxable(),
538
+					'LIN_order'      => count($ticket_line_item->children()),
539
+					'LIN_total'      => 0, // $ticket_line_item->unit_price()
540
+					'LIN_type'       => EEM_Line_Item::type_cancellation,
541
+				]
542
+			);
543
+			$ticket_line_item->add_child_line_item($cancellation_line_item);
544
+		}
545
+		if ($ticket_line_item->save_this_and_descendants() > 0) {
546
+			// decrement parent line item quantity
547
+			$event_line_item = $ticket_line_item->parent();
548
+			if (
549
+				$event_line_item instanceof EE_Line_Item
550
+				&& $event_line_item->OBJ_type() === EEM_Line_Item::OBJ_TYPE_EVENT
551
+			) {
552
+				$event_line_item->set_quantity($event_line_item->quantity() - $qty);
553
+				$event_line_item->save();
554
+			}
555
+			EEH_Line_Item::get_grand_total_and_recalculate_everything($ticket_line_item);
556
+			return true;
557
+		}
558
+		return false;
559
+	}
560
+
561
+
562
+	/**
563
+	 * reinstates (un-cancels?) a previously canceled ticket line item,
564
+	 * by incrementing its quantity by 1, and decrementing its "type_cancellation" sub-line-item.
565
+	 * ALL totals and subtotals will NEED TO BE UPDATED after performing this action
566
+	 *
567
+	 * @param EE_Line_Item $ticket_line_item
568
+	 * @param int          $qty
569
+	 * @return bool success
570
+	 * @throws EE_Error
571
+	 * @throws InvalidArgumentException
572
+	 * @throws InvalidDataTypeException
573
+	 * @throws InvalidInterfaceException
574
+	 * @throws ReflectionException
575
+	 */
576
+	public static function reinstate_canceled_ticket_line_item(EE_Line_Item $ticket_line_item, int $qty = 1): bool
577
+	{
578
+		// validate incoming line_item
579
+		if ($ticket_line_item->OBJ_type() !== EEM_Line_Item::OBJ_TYPE_TICKET) {
580
+			throw new EE_Error(
581
+				sprintf(
582
+					esc_html__(
583
+						'The supplied line item must have an Object Type of "Ticket", not %1$s.',
584
+						'event_espresso'
585
+					),
586
+					$ticket_line_item->type()
587
+				)
588
+			);
589
+		}
590
+		// get cancellation sub line item
591
+		$cancellation_line_item = EEH_Line_Item::get_descendants_of_type(
592
+			$ticket_line_item,
593
+			EEM_Line_Item::type_cancellation
594
+		);
595
+		$cancellation_line_item = reset($cancellation_line_item);
596
+		// verify that this ticket was indeed previously cancelled
597
+		if (! $cancellation_line_item instanceof EE_Line_Item) {
598
+			return false;
599
+		}
600
+		if ($cancellation_line_item->quantity() > $qty) {
601
+			// decrement cancelled quantity
602
+			$cancellation_line_item->set_quantity($cancellation_line_item->quantity() - $qty);
603
+		} elseif ($cancellation_line_item->quantity() === $qty) {
604
+			// decrement cancelled quantity in case anyone still has the object kicking around
605
+			$cancellation_line_item->set_quantity($cancellation_line_item->quantity() - $qty);
606
+			// delete because quantity will end up as 0
607
+			$cancellation_line_item->delete();
608
+			// and attempt to destroy the object,
609
+			// even though PHP won't actually destroy it until it needs the memory
610
+			unset($cancellation_line_item);
611
+		} else {
612
+			// what ?!?! negative quantity ?!?!
613
+			throw new EE_Error(
614
+				sprintf(
615
+					esc_html__(
616
+						'Can not reinstate %1$d cancelled ticket(s) because the cancelled ticket quantity is only %2$d.',
617
+						'event_espresso'
618
+					),
619
+					$qty,
620
+					$cancellation_line_item->quantity()
621
+				)
622
+			);
623
+		}
624
+		// increment ticket quantity
625
+		$ticket_line_item->set_quantity($ticket_line_item->quantity() + $qty);
626
+		if ($ticket_line_item->save_this_and_descendants() > 0) {
627
+			// increment parent line item quantity
628
+			$event_line_item = $ticket_line_item->parent();
629
+			if (
630
+				$event_line_item instanceof EE_Line_Item
631
+				&& $event_line_item->OBJ_type() === EEM_Line_Item::OBJ_TYPE_EVENT
632
+			) {
633
+				$event_line_item->set_quantity($event_line_item->quantity() + $qty);
634
+			}
635
+			EEH_Line_Item::get_grand_total_and_recalculate_everything($ticket_line_item);
636
+			return true;
637
+		}
638
+		return false;
639
+	}
640
+
641
+
642
+	/**
643
+	 * calls EEH_Line_Item::find_transaction_grand_total_for_line_item()
644
+	 * then EE_Line_Item::recalculate_total_including_taxes() on the result
645
+	 *
646
+	 * @param EE_Line_Item $line_item
647
+	 * @return float
648
+	 * @throws EE_Error
649
+	 * @throws InvalidArgumentException
650
+	 * @throws InvalidDataTypeException
651
+	 * @throws InvalidInterfaceException
652
+	 * @throws ReflectionException
653
+	 */
654
+	public static function get_grand_total_and_recalculate_everything(EE_Line_Item $line_item): float
655
+	{
656
+		$grand_total_line_item = EEH_Line_Item::find_transaction_grand_total_for_line_item($line_item);
657
+		return $grand_total_line_item->recalculate_total_including_taxes();
658
+	}
659
+
660
+
661
+	/**
662
+	 * Gets the line item which contains the subtotal of all the items
663
+	 *
664
+	 * @param EE_Line_Item $total_line_item of type EEM_Line_Item::type_total
665
+	 * @return EE_Line_Item
666
+	 * @throws EE_Error
667
+	 * @throws InvalidArgumentException
668
+	 * @throws InvalidDataTypeException
669
+	 * @throws InvalidInterfaceException
670
+	 * @throws ReflectionException
671
+	 */
672
+	public static function get_pre_tax_subtotal(EE_Line_Item $total_line_item): EE_Line_Item
673
+	{
674
+		$pre_tax_subtotal = $total_line_item->get_child_line_item('pre-tax-subtotal');
675
+		return $pre_tax_subtotal instanceof EE_Line_Item
676
+			? $pre_tax_subtotal
677
+			: self::create_pre_tax_subtotal($total_line_item);
678
+	}
679
+
680
+
681
+	/**
682
+	 * Gets the line item for the taxes subtotal
683
+	 *
684
+	 * @param EE_Line_Item $total_line_item of type EEM_Line_Item::type_total
685
+	 * @return EE_Line_Item
686
+	 * @throws EE_Error
687
+	 * @throws InvalidArgumentException
688
+	 * @throws InvalidDataTypeException
689
+	 * @throws InvalidInterfaceException
690
+	 * @throws ReflectionException
691
+	 */
692
+	public static function get_taxes_subtotal(EE_Line_Item $total_line_item): EE_Line_Item
693
+	{
694
+		$taxes = $total_line_item->get_child_line_item('taxes');
695
+		return $taxes ?: self::create_taxes_subtotal($total_line_item);
696
+	}
697
+
698
+
699
+	/**
700
+	 * sets the TXN ID on an EE_Line_Item if passed a valid EE_Transaction object
701
+	 *
702
+	 * @param EE_Line_Item        $line_item
703
+	 * @param EE_Transaction|null $transaction
704
+	 * @return void
705
+	 * @throws EE_Error
706
+	 * @throws InvalidArgumentException
707
+	 * @throws InvalidDataTypeException
708
+	 * @throws InvalidInterfaceException
709
+	 * @throws ReflectionException
710
+	 */
711
+	public static function set_TXN_ID(EE_Line_Item $line_item, ?EE_Transaction $transaction = null)
712
+	{
713
+		if ($transaction) {
714
+			/** @type EEM_Transaction $EEM_Transaction */
715
+			$EEM_Transaction = EE_Registry::instance()->load_model('Transaction');
716
+			$TXN_ID          = $EEM_Transaction->ensure_is_ID($transaction);
717
+			$line_item->set_TXN_ID($TXN_ID);
718
+		}
719
+	}
720
+
721
+
722
+	/**
723
+	 * Creates a new default total line item for the transaction,
724
+	 * and its tickets subtotal and taxes subtotal line items (and adds the
725
+	 * existing taxes as children of the taxes subtotal line item)
726
+	 *
727
+	 * @param EE_Transaction|null $transaction
728
+	 * @return EE_Line_Item of type total
729
+	 * @throws EE_Error
730
+	 * @throws InvalidArgumentException
731
+	 * @throws InvalidDataTypeException
732
+	 * @throws InvalidInterfaceException
733
+	 * @throws ReflectionException
734
+	 */
735
+	public static function create_total_line_item(?EE_Transaction $transaction = null): EE_Line_Item
736
+	{
737
+		$total_line_item = EE_Line_Item::new_instance(
738
+			[
739
+				'LIN_code' => 'total',
740
+				'LIN_name' => esc_html__('Grand Total', 'event_espresso'),
741
+				'LIN_type' => EEM_Line_Item::type_total,
742
+				'OBJ_type' => EEM_Line_Item::OBJ_TYPE_TRANSACTION,
743
+			]
744
+		);
745
+		$total_line_item = apply_filters(
746
+			'FHEE__EEH_Line_Item__create_total_line_item__total_line_item',
747
+			$total_line_item
748
+		);
749
+		self::set_TXN_ID($total_line_item, $transaction);
750
+		self::create_pre_tax_subtotal($total_line_item, $transaction);
751
+		self::create_taxes_subtotal($total_line_item, $transaction);
752
+		return $total_line_item;
753
+	}
754
+
755
+
756
+	/**
757
+	 * Creates a default items subtotal line item
758
+	 *
759
+	 * @param EE_Line_Item        $total_line_item
760
+	 * @param EE_Transaction|null $transaction
761
+	 * @return EE_Line_Item
762
+	 * @throws EE_Error
763
+	 * @throws InvalidArgumentException
764
+	 * @throws InvalidDataTypeException
765
+	 * @throws InvalidInterfaceException
766
+	 * @throws ReflectionException
767
+	 */
768
+	protected static function create_pre_tax_subtotal(
769
+		EE_Line_Item $total_line_item,
770
+		?EE_Transaction $transaction = null
771
+	): EE_Line_Item {
772
+		$pre_tax_line_item = EE_Line_Item::new_instance(
773
+			[
774
+				'LIN_code' => 'pre-tax-subtotal',
775
+				'LIN_name' => esc_html__('Pre-Tax Subtotal', 'event_espresso'),
776
+				'LIN_type' => EEM_Line_Item::type_sub_total,
777
+			]
778
+		);
779
+		$pre_tax_line_item = apply_filters(
780
+			'FHEE__EEH_Line_Item__create_pre_tax_subtotal__pre_tax_line_item',
781
+			$pre_tax_line_item
782
+		);
783
+		self::set_TXN_ID($pre_tax_line_item, $transaction);
784
+		$total_line_item->add_child_line_item($pre_tax_line_item);
785
+		self::create_event_subtotal($pre_tax_line_item, $transaction);
786
+		return $pre_tax_line_item;
787
+	}
788
+
789
+
790
+	/**
791
+	 * Creates a line item for the taxes subtotal and finds all the tax prices
792
+	 * and applies taxes to it
793
+	 *
794
+	 * @param EE_Line_Item        $total_line_item of type EEM_Line_Item::type_total
795
+	 * @param EE_Transaction|null $transaction
796
+	 * @return EE_Line_Item
797
+	 * @throws EE_Error
798
+	 * @throws InvalidArgumentException
799
+	 * @throws InvalidDataTypeException
800
+	 * @throws InvalidInterfaceException
801
+	 * @throws ReflectionException
802
+	 */
803
+	protected static function create_taxes_subtotal(
804
+		EE_Line_Item $total_line_item,
805
+		?EE_Transaction $transaction = null
806
+	): EE_Line_Item {
807
+		$tax_line_item = EE_Line_Item::new_instance(
808
+			[
809
+				'LIN_code'  => 'taxes',
810
+				'LIN_name'  => esc_html__('Taxes', 'event_espresso'),
811
+				'LIN_type'  => EEM_Line_Item::type_tax_sub_total,
812
+				'LIN_order' => 1000,// this should always come last
813
+			]
814
+		);
815
+		$tax_line_item = apply_filters(
816
+			'FHEE__EEH_Line_Item__create_taxes_subtotal__tax_line_item',
817
+			$tax_line_item
818
+		);
819
+		self::set_TXN_ID($tax_line_item, $transaction);
820
+		$total_line_item->add_child_line_item($tax_line_item);
821
+		// and lastly, add the actual taxes
822
+		self::apply_taxes($total_line_item);
823
+		return $tax_line_item;
824
+	}
825
+
826
+
827
+	/**
828
+	 * Creates a default items subtotal line item
829
+	 *
830
+	 * @param EE_Line_Item        $pre_tax_line_item
831
+	 * @param EE_Transaction|null $transaction
832
+	 * @param EE_Event|null       $event
833
+	 * @return EE_Line_Item
834
+	 * @throws EE_Error
835
+	 * @throws InvalidArgumentException
836
+	 * @throws InvalidDataTypeException
837
+	 * @throws InvalidInterfaceException
838
+	 * @throws ReflectionException
839
+	 */
840
+	public static function create_event_subtotal(
841
+		EE_Line_Item $pre_tax_line_item,
842
+		?EE_Transaction $transaction = null,
843
+		?EE_Event $event = null
844
+	): EE_Line_Item {
845
+		$event_line_item = EE_Line_Item::new_instance(
846
+			[
847
+				'LIN_code' => self::get_event_code($event),
848
+				'LIN_name' => self::get_event_name($event),
849
+				'LIN_desc' => self::get_event_desc($event),
850
+				'LIN_type' => EEM_Line_Item::type_sub_total,
851
+				'OBJ_type' => EEM_Line_Item::OBJ_TYPE_EVENT,
852
+				'OBJ_ID'   => $event instanceof EE_Event ? $event->ID() : 0,
853
+			]
854
+		);
855
+		$event_line_item = apply_filters(
856
+			'FHEE__EEH_Line_Item__create_event_subtotal__event_line_item',
857
+			$event_line_item
858
+		);
859
+		self::set_TXN_ID($event_line_item, $transaction);
860
+		$pre_tax_line_item->add_child_line_item($event_line_item);
861
+		return $event_line_item;
862
+	}
863
+
864
+
865
+	/**
866
+	 * Gets what the event ticket's code SHOULD be
867
+	 *
868
+	 * @param EE_Event|null $event
869
+	 * @return string
870
+	 * @throws EE_Error
871
+	 * @throws ReflectionException
872
+	 */
873
+	public static function get_event_code(?EE_Event $event = null): string
874
+	{
875
+		return 'event-' . ($event instanceof EE_Event ? $event->ID() : '0');
876
+	}
877
+
878
+
879
+	/**
880
+	 * Gets the event name
881
+	 *
882
+	 * @param EE_Event|null $event
883
+	 * @return string
884
+	 * @throws EE_Error
885
+	 * @throws ReflectionException
886
+	 */
887
+	public static function get_event_name(?EE_Event $event = null): string
888
+	{
889
+		return $event instanceof EE_Event
890
+			? mb_substr($event->name(), 0, 245)
891
+			: esc_html__('Event', 'event_espresso');
892
+	}
893
+
894
+
895
+	/**
896
+	 * Gets the event excerpt
897
+	 *
898
+	 * @param EE_Event|null $event
899
+	 * @return string
900
+	 * @throws EE_Error
901
+	 * @throws ReflectionException
902
+	 */
903
+	public static function get_event_desc(?EE_Event $event = null): string
904
+	{
905
+		return $event instanceof EE_Event ? $event->short_description() : '';
906
+	}
907
+
908
+
909
+	/**
910
+	 * Given the grand total line item and a ticket, finds the event sub-total
911
+	 * line item the ticket's purchase should be added onto
912
+	 *
913
+	 * @access public
914
+	 * @param EE_Line_Item $grand_total the grand total line item
915
+	 * @param EE_Ticket    $ticket
916
+	 * @return EE_Line_Item
917
+	 * @throws EE_Error
918
+	 * @throws InvalidArgumentException
919
+	 * @throws InvalidDataTypeException
920
+	 * @throws InvalidInterfaceException
921
+	 * @throws ReflectionException
922
+	 */
923
+	public static function get_event_line_item_for_ticket(EE_Line_Item $grand_total, EE_Ticket $ticket): EE_Line_Item
924
+	{
925
+		$first_datetime = $ticket->first_datetime();
926
+		if (! $first_datetime instanceof EE_Datetime) {
927
+			throw new EE_Error(
928
+				sprintf(
929
+					esc_html__('The supplied ticket (ID %d) has no datetimes', 'event_espresso'),
930
+					$ticket->ID()
931
+				)
932
+			);
933
+		}
934
+		$event = $first_datetime->event();
935
+		if (! $event instanceof EE_Event) {
936
+			throw new EE_Error(
937
+				sprintf(
938
+					esc_html__(
939
+						'The supplied ticket (ID %d) has no event data associated with it.',
940
+						'event_espresso'
941
+					),
942
+					$ticket->ID()
943
+				)
944
+			);
945
+		}
946
+		$events_sub_total = EEH_Line_Item::get_event_line_item($grand_total, $event);
947
+		if (! $events_sub_total instanceof EE_Line_Item) {
948
+			throw new EE_Error(
949
+				sprintf(
950
+					esc_html__(
951
+						'There is no events sub-total for ticket %s on total line item %d',
952
+						'event_espresso'
953
+					),
954
+					$ticket->ID(),
955
+					$grand_total->ID()
956
+				)
957
+			);
958
+		}
959
+		return $events_sub_total;
960
+	}
961
+
962
+
963
+	/**
964
+	 * Gets the event line item
965
+	 *
966
+	 * @param EE_Line_Item  $grand_total
967
+	 * @param EE_Event|null $event
968
+	 * @return EE_Line_Item for the event subtotal which is a child of $grand_total
969
+	 * @throws EE_Error
970
+	 * @throws InvalidArgumentException
971
+	 * @throws InvalidDataTypeException
972
+	 * @throws InvalidInterfaceException
973
+	 * @throws ReflectionException
974
+	 */
975
+	public static function get_event_line_item(EE_Line_Item $grand_total, ?EE_Event $event = null): ?EE_Line_Item
976
+	{
977
+		/** @type EE_Event $event */
978
+		$event           = EEM_Event::instance()->ensure_is_obj($event, true);
979
+		$event_line_item = null;
980
+		$found           = false;
981
+		foreach (EEH_Line_Item::get_event_subtotals($grand_total) as $event_line_item) {
982
+			// default event subtotal, we should only ever find this the first time this method is called
983
+			if (! $event_line_item->OBJ_ID()) {
984
+				// let's use this! but first... set the event details
985
+				EEH_Line_Item::set_event_subtotal_details($event_line_item, $event);
986
+				$found = true;
987
+				break;
988
+			}
989
+			if ($event_line_item->OBJ_ID() === $event->ID()) {
990
+				// found existing line item for this event in the cart, so break out of loop and use this one
991
+				$found = true;
992
+				break;
993
+			}
994
+		}
995
+		if (! $found) {
996
+			// there is no event sub-total yet, so add it
997
+			$pre_tax_subtotal = EEH_Line_Item::get_pre_tax_subtotal($grand_total);
998
+			// create a new "event" subtotal below that
999
+			$event_line_item = EEH_Line_Item::create_event_subtotal($pre_tax_subtotal, null, $event);
1000
+			// and set the event details
1001
+			EEH_Line_Item::set_event_subtotal_details($event_line_item, $event);
1002
+		}
1003
+		return $event_line_item;
1004
+	}
1005
+
1006
+
1007
+	/**
1008
+	 * Creates a default items subtotal line item
1009
+	 *
1010
+	 * @param EE_Line_Item        $event_line_item
1011
+	 * @param EE_Event|null       $event
1012
+	 * @param EE_Transaction|null $transaction
1013
+	 * @return void
1014
+	 * @throws EE_Error
1015
+	 * @throws InvalidArgumentException
1016
+	 * @throws InvalidDataTypeException
1017
+	 * @throws InvalidInterfaceException
1018
+	 * @throws ReflectionException
1019
+	 */
1020
+	public static function set_event_subtotal_details(
1021
+		EE_Line_Item $event_line_item,
1022
+		EE_Event $event = null,
1023
+		?EE_Transaction $transaction = null
1024
+	) {
1025
+		if ($event instanceof EE_Event) {
1026
+			$event_line_item->set_code(self::get_event_code($event));
1027
+			$event_line_item->set_name(self::get_event_name($event));
1028
+			$event_line_item->set_desc(self::get_event_desc($event));
1029
+			$event_line_item->set_OBJ_ID($event->ID());
1030
+		}
1031
+		self::set_TXN_ID($event_line_item, $transaction);
1032
+	}
1033
+
1034
+
1035
+	/**
1036
+	 * Finds what taxes should apply, adds them as tax line items under the taxes sub-total,
1037
+	 * and recalculates the taxes sub-total and the grand total. Resets the taxes, so
1038
+	 * any old taxes are removed
1039
+	 *
1040
+	 * @param EE_Line_Item $total_line_item of type EEM_Line_Item::type_total
1041
+	 * @param bool         $update_txn_status
1042
+	 * @return bool
1043
+	 * @throws EE_Error
1044
+	 * @throws InvalidArgumentException
1045
+	 * @throws InvalidDataTypeException
1046
+	 * @throws InvalidInterfaceException
1047
+	 * @throws ReflectionException
1048
+	 * @throws RuntimeException
1049
+	 */
1050
+	public static function apply_taxes(EE_Line_Item $total_line_item, bool $update_txn_status = false): bool
1051
+	{
1052
+		$total_line_item       = EEH_Line_Item::find_transaction_grand_total_for_line_item($total_line_item);
1053
+		$taxes_line_item       = self::get_taxes_subtotal($total_line_item);
1054
+		$existing_global_taxes = $taxes_line_item->tax_descendants();
1055
+		$updates               = false;
1056
+		// loop thru taxes
1057
+		$global_taxes = EEH_Line_Item::getGlobalTaxes();
1058
+		foreach ($global_taxes as $order => $taxes) {
1059
+			foreach ($taxes as $tax) {
1060
+				if ($tax instanceof EE_Price) {
1061
+					$found = false;
1062
+					// check if this is already an existing tax
1063
+					foreach ($existing_global_taxes as $existing_global_tax) {
1064
+						if ($tax->ID() === $existing_global_tax->OBJ_ID()) {
1065
+							// maybe update the tax rate in case it has changed
1066
+							if ($existing_global_tax->percent() !== $tax->amount()) {
1067
+								$existing_global_tax->set_percent($tax->amount());
1068
+								$existing_global_tax->save();
1069
+								$updates = true;
1070
+							}
1071
+							$found = true;
1072
+							break;
1073
+						}
1074
+					}
1075
+					if (! $found) {
1076
+						// add a new line item for this global tax
1077
+						$tax_line_item = apply_filters(
1078
+							'FHEE__EEH_Line_Item__apply_taxes__tax_line_item',
1079
+							EE_Line_Item::new_instance(
1080
+								[
1081
+									'LIN_name'       => $tax->name(),
1082
+									'LIN_desc'       => $tax->desc(),
1083
+									'LIN_percent'    => $tax->amount(),
1084
+									'LIN_is_taxable' => false,
1085
+									'LIN_order'      => $order,
1086
+									'LIN_total'      => 0,
1087
+									'LIN_type'       => EEM_Line_Item::type_tax,
1088
+									'OBJ_type'       => EEM_Line_Item::OBJ_TYPE_PRICE,
1089
+									'OBJ_ID'         => $tax->ID(),
1090
+								]
1091
+							)
1092
+						);
1093
+						$updates       = $taxes_line_item->add_child_line_item($tax_line_item) ? true : $updates;
1094
+					}
1095
+				}
1096
+			}
1097
+		}
1098
+		// only recalculate totals if something changed
1099
+		if ($updates || $update_txn_status) {
1100
+			$total_line_item->recalculate_total_including_taxes($update_txn_status);
1101
+			return true;
1102
+		}
1103
+		return false;
1104
+	}
1105
+
1106
+
1107
+	/**
1108
+	 * Ensures that taxes have been applied to the order, if not applies them.
1109
+	 * Returns the total amount of tax
1110
+	 *
1111
+	 * @param EE_Line_Item|null $total_line_item of type EEM_Line_Item::type_total
1112
+	 * @return float
1113
+	 * @throws EE_Error
1114
+	 * @throws InvalidArgumentException
1115
+	 * @throws InvalidDataTypeException
1116
+	 * @throws InvalidInterfaceException
1117
+	 * @throws ReflectionException
1118
+	 */
1119
+	public static function ensure_taxes_applied(?EE_Line_Item $total_line_item): float
1120
+	{
1121
+		$taxes_subtotal = self::get_taxes_subtotal($total_line_item);
1122
+		if (! $taxes_subtotal->children()) {
1123
+			self::apply_taxes($total_line_item);
1124
+		}
1125
+		return $taxes_subtotal->total();
1126
+	}
1127
+
1128
+
1129
+	/**
1130
+	 * Deletes ALL children of the passed line item
1131
+	 *
1132
+	 * @param EE_Line_Item $parent_line_item
1133
+	 * @return bool
1134
+	 * @throws EE_Error
1135
+	 * @throws InvalidArgumentException
1136
+	 * @throws InvalidDataTypeException
1137
+	 * @throws InvalidInterfaceException
1138
+	 * @throws ReflectionException
1139
+	 */
1140
+	public static function delete_all_child_items(EE_Line_Item $parent_line_item)
1141
+	{
1142
+		$deleted = 0;
1143
+		foreach ($parent_line_item->children() as $child_line_item) {
1144
+			if ($child_line_item instanceof EE_Line_Item) {
1145
+				$deleted += EEH_Line_Item::delete_all_child_items($child_line_item);
1146
+				if ($child_line_item->ID()) {
1147
+					$child_line_item->delete();
1148
+					unset($child_line_item);
1149
+				} else {
1150
+					$parent_line_item->delete_child_line_item($child_line_item->code());
1151
+				}
1152
+				$deleted++;
1153
+			}
1154
+		}
1155
+		return $deleted;
1156
+	}
1157
+
1158
+
1159
+	/**
1160
+	 * Deletes the line items as indicated by the line item code(s) provided,
1161
+	 * regardless of where they're found in the line item tree. Automatically
1162
+	 * re-calculates the line item totals and updates the related transaction. But
1163
+	 * DOES NOT automatically upgrade the transaction's registrations' final prices (which
1164
+	 * should probably change because of this).
1165
+	 * You should call EE_Registration_Processor::calculate_reg_final_prices_per_line_item()
1166
+	 * after using this, to keep the registration final prices in-sync with the transaction's total.
1167
+	 *
1168
+	 * @param EE_Line_Item      $total_line_item of type EEM_Line_Item::type_total
1169
+	 * @param array|bool|string $line_item_codes
1170
+	 * @return int number of items successfully removed
1171
+	 * @throws EE_Error
1172
+	 * @throws ReflectionException
1173
+	 */
1174
+	public static function delete_items(EE_Line_Item $total_line_item, $line_item_codes = false)
1175
+	{
1176
+		if ($total_line_item->type() !== EEM_Line_Item::type_total) {
1177
+			EE_Error::doing_it_wrong(
1178
+				'EEH_Line_Item::delete_items',
1179
+				esc_html__(
1180
+					'This static method should only be called with a TOTAL line item, otherwise we won\'t recalculate the totals correctly',
1181
+					'event_espresso'
1182
+				),
1183
+				'4.6.18'
1184
+			);
1185
+		}
1186
+
1187
+		// check if only a single line_item_id was passed
1188
+		if (! empty($line_item_codes) && ! is_array($line_item_codes)) {
1189
+			// place single line_item_id in an array to appear as multiple line_item_ids
1190
+			$line_item_codes = [$line_item_codes];
1191
+		}
1192
+		$removals = 0;
1193
+		// cycle thru line_item_ids
1194
+		foreach ($line_item_codes as $line_item_id) {
1195
+			$removals += $total_line_item->delete_child_line_item($line_item_id);
1196
+		}
1197
+
1198
+		if ($removals > 0) {
1199
+			$total_line_item->recalculate_taxes_and_tax_total();
1200
+			return $removals;
1201
+		} else {
1202
+			return false;
1203
+		}
1204
+	}
1205
+
1206
+
1207
+	/**
1208
+	 * Overwrites the previous tax by clearing out the old taxes, and creates a new
1209
+	 * tax and updates the total line item accordingly
1210
+	 *
1211
+	 * @param EE_Line_Item $total_line_item
1212
+	 * @param float        $amount
1213
+	 * @param string       $name
1214
+	 * @param string       $description
1215
+	 * @param string       $code
1216
+	 * @param boolean      $add_to_existing_line_item
1217
+	 *                          if true, and a duplicate line item with the same code is found,
1218
+	 *                          $amount will be added onto it; otherwise will simply set the taxes to match $amount
1219
+	 * @return EE_Line_Item the new tax line item created
1220
+	 * @throws EE_Error
1221
+	 * @throws InvalidArgumentException
1222
+	 * @throws InvalidDataTypeException
1223
+	 * @throws InvalidInterfaceException
1224
+	 * @throws ReflectionException
1225
+	 */
1226
+	public static function set_total_tax_to(
1227
+		EE_Line_Item $total_line_item,
1228
+		float $amount,
1229
+		string $name = '',
1230
+		string $description = '',
1231
+		string $code = '',
1232
+		bool $add_to_existing_line_item = false
1233
+	): EE_Line_Item {
1234
+		$tax_subtotal  = self::get_taxes_subtotal($total_line_item);
1235
+		$taxable_total = $total_line_item->taxable_total();
1236
+
1237
+		if ($add_to_existing_line_item) {
1238
+			$new_tax = $tax_subtotal->get_child_line_item($code);
1239
+			EEM_Line_Item::instance()->delete(
1240
+				[['LIN_code' => ['!=', $code], 'LIN_parent' => $tax_subtotal->ID()]]
1241
+			);
1242
+		} else {
1243
+			$new_tax = null;
1244
+			$tax_subtotal->delete_children_line_items();
1245
+		}
1246
+		if ($new_tax) {
1247
+			$new_tax->set_total($new_tax->total() + $amount);
1248
+			$new_tax->set_percent($taxable_total ? $new_tax->total() / $taxable_total * 100 : 0);
1249
+		} else {
1250
+			// no existing tax item. Create it
1251
+			$new_tax = EE_Line_Item::new_instance(
1252
+				[
1253
+					'TXN_ID'      => $total_line_item->TXN_ID(),
1254
+					'LIN_name'    => $name ?: esc_html__('Tax', 'event_espresso'),
1255
+					'LIN_desc'    => $description ?: '',
1256
+					'LIN_percent' => $taxable_total ? ($amount / $taxable_total * 100) : 0,
1257
+					'LIN_total'   => $amount,
1258
+					'LIN_parent'  => $tax_subtotal->ID(),
1259
+					'LIN_type'    => EEM_Line_Item::type_tax,
1260
+					'LIN_code'    => $code,
1261
+				]
1262
+			);
1263
+		}
1264
+
1265
+		$new_tax = apply_filters(
1266
+			'FHEE__EEH_Line_Item__set_total_tax_to__new_tax_subtotal',
1267
+			$new_tax,
1268
+			$total_line_item
1269
+		);
1270
+		$new_tax->save();
1271
+		$tax_subtotal->set_total($new_tax->total());
1272
+		$tax_subtotal->save();
1273
+		$total_line_item->recalculate_total_including_taxes();
1274
+		return $new_tax;
1275
+	}
1276
+
1277
+
1278
+	/**
1279
+	 * Makes all the line items which are children of $line_item taxable (or not).
1280
+	 * Does NOT save the line items
1281
+	 *
1282
+	 * @param EE_Line_Item $line_item
1283
+	 * @param boolean      $taxable
1284
+	 * @param string|null  $code_substring_for_whitelist if this string is part of the line item's code
1285
+	 *                                                   it will be whitelisted (ie, except from becoming taxable)
1286
+	 * @throws EE_Error
1287
+	 * @throws ReflectionException
1288
+	 */
1289
+	public static function set_line_items_taxable(
1290
+		EE_Line_Item $line_item,
1291
+		bool $taxable = true,
1292
+		?string $code_substring_for_whitelist = null
1293
+	) {
1294
+		$whitelisted = false;
1295
+		if ($code_substring_for_whitelist !== null) {
1296
+			$whitelisted = strpos($line_item->code(), $code_substring_for_whitelist) !== false;
1297
+		}
1298
+		if (! $whitelisted && $line_item->is_line_item()) {
1299
+			$line_item->set_is_taxable($taxable);
1300
+		}
1301
+		foreach ($line_item->children() as $child_line_item) {
1302
+			EEH_Line_Item::set_line_items_taxable(
1303
+				$child_line_item,
1304
+				$taxable,
1305
+				$code_substring_for_whitelist
1306
+			);
1307
+		}
1308
+	}
1309
+
1310
+
1311
+	/**
1312
+	 * Gets all descendants that are event subtotals
1313
+	 *
1314
+	 * @param EE_Line_Item $parent_line_item - the line item to find descendants of
1315
+	 * @return EE_Line_Item[]
1316
+	 * @throws EE_Error
1317
+	 * @throws ReflectionException
1318
+	 * @uses  EEH_Line_Item::get_subtotals_of_object_type()
1319
+	 */
1320
+	public static function get_event_subtotals(EE_Line_Item $parent_line_item): array
1321
+	{
1322
+		return self::get_subtotals_of_object_type($parent_line_item, EEM_Line_Item::OBJ_TYPE_EVENT);
1323
+	}
1324
+
1325
+
1326
+	/**
1327
+	 * Gets all descendants subtotals that match the supplied object type
1328
+	 *
1329
+	 * @param EE_Line_Item $parent_line_item - the line item to find descendants of
1330
+	 * @param string       $obj_type
1331
+	 * @return EE_Line_Item[]
1332
+	 * @throws EE_Error
1333
+	 * @throws ReflectionException
1334
+	 * @uses  EEH_Line_Item::_get_descendants_by_type_and_object_type()
1335
+	 */
1336
+	public static function get_subtotals_of_object_type(EE_Line_Item $parent_line_item, string $obj_type = ''): array
1337
+	{
1338
+		return self::_get_descendants_by_type_and_object_type(
1339
+			$parent_line_item,
1340
+			EEM_Line_Item::type_sub_total,
1341
+			$obj_type
1342
+		);
1343
+	}
1344
+
1345
+
1346
+	/**
1347
+	 * Gets all descendants that are tickets
1348
+	 *
1349
+	 * @param EE_Line_Item $parent_line_item - the line item to find descendants of
1350
+	 * @return EE_Line_Item[]
1351
+	 * @throws EE_Error
1352
+	 * @throws ReflectionException
1353
+	 * @uses  EEH_Line_Item::get_line_items_of_object_type()
1354
+	 */
1355
+	public static function get_ticket_line_items(EE_Line_Item $parent_line_item): array
1356
+	{
1357
+		return self::get_line_items_of_object_type(
1358
+			$parent_line_item,
1359
+			EEM_Line_Item::OBJ_TYPE_TICKET
1360
+		);
1361
+	}
1362
+
1363
+
1364
+	/**
1365
+	 * Gets all descendants subtotals that match the supplied object type
1366
+	 *
1367
+	 * @param EE_Line_Item $parent_line_item - the line item to find descendants of
1368
+	 * @param string       $obj_type
1369
+	 * @return EE_Line_Item[]
1370
+	 * @throws EE_Error
1371
+	 * @throws ReflectionException
1372
+	 * @uses  EEH_Line_Item::_get_descendants_by_type_and_object_type()
1373
+	 */
1374
+	public static function get_line_items_of_object_type(EE_Line_Item $parent_line_item, string $obj_type = ''): array
1375
+	{
1376
+		return self::_get_descendants_by_type_and_object_type(
1377
+			$parent_line_item,
1378
+			EEM_Line_Item::type_line_item,
1379
+			$obj_type
1380
+		);
1381
+	}
1382
+
1383
+
1384
+	/**
1385
+	 * Gets all the descendants (ie, children or children of children etc) that are of the type 'tax'
1386
+	 *
1387
+	 * @param EE_Line_Item $parent_line_item - the line item to find descendants of
1388
+	 * @return EE_Line_Item[]
1389
+	 * @throws EE_Error
1390
+	 * @throws ReflectionException
1391
+	 * @uses  EEH_Line_Item::get_descendants_of_type()
1392
+	 */
1393
+	public static function get_tax_descendants(EE_Line_Item $parent_line_item): array
1394
+	{
1395
+		return EEH_Line_Item::get_descendants_of_type(
1396
+			$parent_line_item,
1397
+			EEM_Line_Item::type_tax
1398
+		);
1399
+	}
1400
+
1401
+
1402
+	/**
1403
+	 * Gets all the real items purchased which are children of this item
1404
+	 *
1405
+	 * @param EE_Line_Item $parent_line_item - the line item to find descendants of
1406
+	 * @return EE_Line_Item[]
1407
+	 * @throws EE_Error
1408
+	 * @throws ReflectionException
1409
+	 * @uses  EEH_Line_Item::get_descendants_of_type()
1410
+	 */
1411
+	public static function get_line_item_descendants(EE_Line_Item $parent_line_item): array
1412
+	{
1413
+		return EEH_Line_Item::get_descendants_of_type(
1414
+			$parent_line_item,
1415
+			EEM_Line_Item::type_line_item
1416
+		);
1417
+	}
1418
+
1419
+
1420
+	/**
1421
+	 * Gets all descendants of supplied line item that match the supplied line item type
1422
+	 *
1423
+	 * @param EE_Line_Item $parent_line_item - the line item to find descendants of
1424
+	 * @param string       $line_item_type   one of the EEM_Line_Item constants
1425
+	 * @return EE_Line_Item[]
1426
+	 * @throws EE_Error
1427
+	 * @throws ReflectionException
1428
+	 * @uses  EEH_Line_Item::_get_descendants_by_type_and_object_type()
1429
+	 */
1430
+	public static function get_descendants_of_type(EE_Line_Item $parent_line_item, string $line_item_type): array
1431
+	{
1432
+		return self::_get_descendants_by_type_and_object_type(
1433
+			$parent_line_item,
1434
+			$line_item_type
1435
+		);
1436
+	}
1437
+
1438
+
1439
+	/**
1440
+	 * Gets all descendants of supplied line item that match the supplied line item type and possibly the object type
1441
+	 * as well
1442
+	 *
1443
+	 * @param EE_Line_Item $parent_line_item  - the line item to find descendants of
1444
+	 * @param string       $line_item_type    one of the EEM_Line_Item constants
1445
+	 * @param string|null  $obj_type          object model class name (minus prefix) or NULL to ignore object type when
1446
+	 *                                        searching
1447
+	 * @return EE_Line_Item[]
1448
+	 * @throws EE_Error
1449
+	 * @throws ReflectionException
1450
+	 */
1451
+	protected static function _get_descendants_by_type_and_object_type(
1452
+		EE_Line_Item $parent_line_item,
1453
+		string $line_item_type,
1454
+		?string $obj_type = null
1455
+	): array {
1456
+		$objects = [];
1457
+		foreach ($parent_line_item->children() as $child_line_item) {
1458
+			if ($child_line_item instanceof EE_Line_Item) {
1459
+				if (
1460
+					$child_line_item->type() === $line_item_type
1461
+					&& (
1462
+						$child_line_item->OBJ_type() === $obj_type || $obj_type === null
1463
+					)
1464
+				) {
1465
+					$objects[] = $child_line_item;
1466
+				} else {
1467
+					// go-through-all-its children looking for more matches
1468
+					$objects = array_merge(
1469
+						$objects,
1470
+						self::_get_descendants_by_type_and_object_type(
1471
+							$child_line_item,
1472
+							$line_item_type,
1473
+							$obj_type
1474
+						)
1475
+					);
1476
+				}
1477
+			}
1478
+		}
1479
+		return $objects;
1480
+	}
1481
+
1482
+
1483
+	/**
1484
+	 * Gets all descendants subtotals that match the supplied object type
1485
+	 *
1486
+	 * @param EE_Line_Item $parent_line_item - the line item to find descendants of
1487
+	 * @param string       $OBJ_type         object type (like Event)
1488
+	 * @param array        $OBJ_IDs          array of OBJ_IDs
1489
+	 * @return EE_Line_Item[]
1490
+	 * @throws EE_Error
1491
+	 * @throws ReflectionException
1492
+	 * @uses  EEH_Line_Item::_get_descendants_by_type_and_object_type()
1493
+	 */
1494
+	public static function get_line_items_by_object_type_and_IDs(
1495
+		EE_Line_Item $parent_line_item,
1496
+		string $OBJ_type = '',
1497
+		array $OBJ_IDs = []
1498
+	): array {
1499
+		return self::_get_descendants_by_object_type_and_object_ID(
1500
+			$parent_line_item,
1501
+			$OBJ_type,
1502
+			$OBJ_IDs
1503
+		);
1504
+	}
1505
+
1506
+
1507
+	/**
1508
+	 * Gets all descendants of supplied line item that match the supplied line item type and possibly the object type
1509
+	 * as well
1510
+	 *
1511
+	 * @param EE_Line_Item $parent_line_item - the line item to find descendants of
1512
+	 * @param string       $OBJ_type         object type (like Event)
1513
+	 * @param array        $OBJ_IDs          array of OBJ_IDs
1514
+	 * @return EE_Line_Item[]
1515
+	 * @throws EE_Error
1516
+	 * @throws ReflectionException
1517
+	 */
1518
+	protected static function _get_descendants_by_object_type_and_object_ID(
1519
+		EE_Line_Item $parent_line_item,
1520
+		string $OBJ_type,
1521
+		array $OBJ_IDs
1522
+	): array {
1523
+		$objects = [];
1524
+		foreach ($parent_line_item->children() as $child_line_item) {
1525
+			if ($child_line_item instanceof EE_Line_Item) {
1526
+				if (
1527
+					$child_line_item->OBJ_type() === $OBJ_type
1528
+					&& in_array($child_line_item->OBJ_ID(), $OBJ_IDs)
1529
+				) {
1530
+					$objects[] = $child_line_item;
1531
+				} else {
1532
+					// go-through-all-its children looking for more matches
1533
+					$objects = array_merge(
1534
+						$objects,
1535
+						self::_get_descendants_by_object_type_and_object_ID(
1536
+							$child_line_item,
1537
+							$OBJ_type,
1538
+							$OBJ_IDs
1539
+						)
1540
+					);
1541
+				}
1542
+			}
1543
+		}
1544
+		return $objects;
1545
+	}
1546
+
1547
+
1548
+	/**
1549
+	 * Uses a breadth-first-search in order to find the nearest descendant of
1550
+	 * the specified type and returns it, else NULL
1551
+	 *
1552
+	 * @param EE_Line_Item $parent_line_item - the line item to find descendants of
1553
+	 * @param string       $type             like one of the EEM_Line_Item::type_*
1554
+	 * @return EE_Line_Item
1555
+	 * @throws EE_Error
1556
+	 * @throws InvalidArgumentException
1557
+	 * @throws InvalidDataTypeException
1558
+	 * @throws InvalidInterfaceException
1559
+	 * @throws ReflectionException
1560
+	 * @uses  EEH_Line_Item::_get_nearest_descendant()
1561
+	 */
1562
+	public static function get_nearest_descendant_of_type(EE_Line_Item $parent_line_item, string $type): ?EE_Line_Item
1563
+	{
1564
+		return self::_get_nearest_descendant($parent_line_item, 'LIN_type', $type);
1565
+	}
1566
+
1567
+
1568
+	/**
1569
+	 * Uses a breadth-first-search in order to find the nearest descendant
1570
+	 * having the specified LIN_code and returns it, else NULL
1571
+	 *
1572
+	 * @param EE_Line_Item $parent_line_item - the line item to find descendants of
1573
+	 * @param string       $code             any value used for LIN_code
1574
+	 * @return EE_Line_Item
1575
+	 * @throws EE_Error
1576
+	 * @throws InvalidArgumentException
1577
+	 * @throws InvalidDataTypeException
1578
+	 * @throws InvalidInterfaceException
1579
+	 * @throws ReflectionException
1580
+	 * @uses  EEH_Line_Item::_get_nearest_descendant()
1581
+	 */
1582
+	public static function get_nearest_descendant_having_code(
1583
+		EE_Line_Item $parent_line_item,
1584
+		string $code
1585
+	): ?EE_Line_Item {
1586
+		return self::_get_nearest_descendant($parent_line_item, 'LIN_code', $code);
1587
+	}
1588
+
1589
+
1590
+	/**
1591
+	 * Uses a breadth-first-search in order to find the nearest descendant
1592
+	 * having the specified LIN_code and returns it, else NULL
1593
+	 *
1594
+	 * @param EE_Line_Item $parent_line_item - the line item to find descendants of
1595
+	 * @param string       $search_field     name of EE_Line_Item property
1596
+	 * @param mixed        $value            any value stored in $search_field
1597
+	 * @return EE_Line_Item
1598
+	 * @throws EE_Error
1599
+	 * @throws InvalidArgumentException
1600
+	 * @throws InvalidDataTypeException
1601
+	 * @throws InvalidInterfaceException
1602
+	 * @throws ReflectionException
1603
+	 */
1604
+	protected static function _get_nearest_descendant(
1605
+		EE_Line_Item $parent_line_item,
1606
+		string $search_field,
1607
+		$value
1608
+	): ?EE_Line_Item {
1609
+		foreach ($parent_line_item->children() as $child) {
1610
+			if ($child->get($search_field) == $value) {
1611
+				return $child;
1612
+			}
1613
+		}
1614
+		foreach ($parent_line_item->children() as $child) {
1615
+			$descendant_found = self::_get_nearest_descendant(
1616
+				$child,
1617
+				$search_field,
1618
+				$value
1619
+			);
1620
+			if ($descendant_found) {
1621
+				return $descendant_found;
1622
+			}
1623
+		}
1624
+		return null;
1625
+	}
1626
+
1627
+
1628
+	/**
1629
+	 * if passed line item has a TXN ID, uses that to jump directly to the grand total line item for the transaction,
1630
+	 * else recursively walks up the line item tree until a parent of type total is found,
1631
+	 *
1632
+	 * @param EE_Line_Item $line_item
1633
+	 * @return EE_Line_Item
1634
+	 * @throws EE_Error
1635
+	 * @throws ReflectionException
1636
+	 */
1637
+	public static function find_transaction_grand_total_for_line_item(EE_Line_Item $line_item): EE_Line_Item
1638
+	{
1639
+		if ($line_item->is_total()) {
1640
+			return $line_item;
1641
+		}
1642
+		if ($line_item->TXN_ID()) {
1643
+			$total_line_item = $line_item->transaction()->total_line_item(false);
1644
+			if ($total_line_item instanceof EE_Line_Item) {
1645
+				return $total_line_item;
1646
+			}
1647
+		} else {
1648
+			$line_item_parent = $line_item->parent();
1649
+			if ($line_item_parent instanceof EE_Line_Item) {
1650
+				if ($line_item_parent->is_total()) {
1651
+					return $line_item_parent;
1652
+				}
1653
+				return EEH_Line_Item::find_transaction_grand_total_for_line_item($line_item_parent);
1654
+			}
1655
+		}
1656
+		throw new EE_Error(
1657
+			sprintf(
1658
+				esc_html__(
1659
+					'A valid grand total for line item %1$d was not found.',
1660
+					'event_espresso'
1661
+				),
1662
+				$line_item->ID()
1663
+			)
1664
+		);
1665
+	}
1666
+
1667
+
1668
+	/**
1669
+	 * Prints out a representation of the line item tree
1670
+	 *
1671
+	 * @param EE_Line_Item $line_item
1672
+	 * @param int          $indentation
1673
+	 * @param bool         $top_level
1674
+	 * @return void
1675
+	 * @throws EE_Error
1676
+	 * @throws ReflectionException
1677
+	 */
1678
+	public static function visualize(EE_Line_Item $line_item, int $indentation = 0, bool $top_level = true)
1679
+	{
1680
+		if (! defined('WP_DEBUG') || ! WP_DEBUG) {
1681
+			return;
1682
+		}
1683
+		$testing  = defined('EE_TESTS_DIR');
1684
+		$new_line = $testing ? "\n" : '<br />';
1685
+		if ($top_level && ! $testing) {
1686
+			echo '<div style="position: relative; z-index: 9999; margin: 2rem;">';
1687
+			echo '<pre style="padding: 2rem 3rem; color: #00CCFF; background: #363636;">';
1688
+		}
1689
+		if ($top_level || $indentation) {
1690
+			echo $new_line;
1691
+		}
1692
+		echo str_repeat('. ', $indentation);
1693
+		$breakdown = '';
1694
+		if ($line_item->is_line_item() || $line_item->is_sub_line_item() || $line_item->isSubTax()) {
1695
+			if ($line_item->is_percent()) {
1696
+				$breakdown = "{$line_item->percent()}%";
1697
+			} else {
1698
+				$breakdown = "\${$line_item->unit_price()} x {$line_item->quantity()}";
1699
+			}
1700
+		}
1701
+		echo wp_kses($line_item->name(), AllowedTags::getAllowedTags());
1702
+		echo " [ ID:{$line_item->ID()} | qty:{$line_item->quantity()} ] {$line_item->type()}";
1703
+		echo " : \${$line_item->total()} : \${$line_item->pretaxTotal()}";
1704
+		if ($breakdown) {
1705
+			echo " ( $breakdown )";
1706
+		}
1707
+		if ($line_item->is_taxable()) {
1708
+			echo '  * taxable';
1709
+		}
1710
+		if ($line_item->children()) {
1711
+			foreach ($line_item->children() as $child) {
1712
+				self::visualize($child, $indentation + 1, false);
1713
+			}
1714
+		}
1715
+		if ($top_level && ! $testing) {
1716
+			echo $new_line;
1717
+			echo '</pre></div>';
1718
+		}
1719
+	}
1720
+
1721
+
1722
+	/**
1723
+	 * Calculates the registration's final price, taking into account that they
1724
+	 * need to not only help pay for their OWN ticket, but also any transaction-wide surcharges and taxes,
1725
+	 * and receive a portion of any transaction-wide discounts.
1726
+	 * eg1, if I buy a $1 ticket and brent buys a $9 ticket, and we receive a $5 discount
1727
+	 * then I'll get 1/10 of that $5 discount, which is $0.50, and brent will get
1728
+	 * 9/10ths of that $5 discount, which is $4.50. So my final price should be $0.50
1729
+	 * and brent's final price should be $5.50.
1730
+	 * In order to do this, we basically need to traverse the line item tree calculating
1731
+	 * the running totals (just as if we were recalculating the total), but when we identify
1732
+	 * regular line items, we need to keep track of their share of the grand total.
1733
+	 * Also, we need to keep track of the TAXABLE total for each ticket purchase, so
1734
+	 * we can know how to apply taxes to it. (Note: "taxable total" does not equal the "pretax total"
1735
+	 * when there are non-taxable items; otherwise they would be the same)
1736
+	 *
1737
+	 * @param EE_Line_Item $line_item
1738
+	 * @param array        $billable_ticket_quantities          array of EE_Ticket IDs and their corresponding quantity
1739
+	 *                                                          that can be included in price calculations at this
1740
+	 *                                                          moment
1741
+	 * @return array        keys are line items for tickets IDs and values are their share of the running total,
1742
+	 *                                                          plus the key 'total', and 'taxable' which also has keys
1743
+	 *                                                          of all the ticket IDs. Eg array(
1744
+	 *                                                          12 => 4.3
1745
+	 *                                                          23 => 8.0
1746
+	 *                                                          'total' => 16.6,
1747
+	 *                                                          'taxable' => array(
1748
+	 *                                                          12 => 10,
1749
+	 *                                                          23 => 4
1750
+	 *                                                          ).
1751
+	 *                                                          So to find which registrations have which final price,
1752
+	 *                                                          we need to find which line item is theirs, which can be
1753
+	 *                                                          done with
1754
+	 *                                                          `EEM_Line_Item::instance()->get_line_item_for_registration(
1755
+	 *                                                          $registration );`
1756
+	 * @throws EE_Error
1757
+	 * @throws InvalidArgumentException
1758
+	 * @throws InvalidDataTypeException
1759
+	 * @throws InvalidInterfaceException
1760
+	 * @throws ReflectionException
1761
+	 */
1762
+	public static function calculate_reg_final_prices_per_line_item(
1763
+		EE_Line_Item $line_item,
1764
+		array $billable_ticket_quantities = []
1765
+	): array {
1766
+		$running_totals = [
1767
+			'total'   => 0,
1768
+			'taxable' => ['total' => 0],
1769
+		];
1770
+		foreach ($line_item->children() as $child_line_item) {
1771
+			switch ($child_line_item->type()) {
1772
+				case EEM_Line_Item::type_sub_total:
1773
+					$running_totals_from_subtotal = EEH_Line_Item::calculate_reg_final_prices_per_line_item(
1774
+						$child_line_item,
1775
+						$billable_ticket_quantities
1776
+					);
1777
+					// combine arrays but preserve numeric keys
1778
+					$running_totals                     = array_replace_recursive(
1779
+						$running_totals_from_subtotal,
1780
+						$running_totals
1781
+					);
1782
+					$running_totals['total']            += $running_totals_from_subtotal['total'];
1783
+					$running_totals['taxable']['total'] += $running_totals_from_subtotal['taxable']['total'];
1784
+					break;
1785
+
1786
+				case EEM_Line_Item::type_tax_sub_total:
1787
+					// find how much the taxes percentage is
1788
+					if ($child_line_item->percent() !== 0.0) {
1789
+						$tax_percent_decimal = $child_line_item->percent() / 100;
1790
+					} else {
1791
+						$tax_percent_decimal = EE_Taxes::get_total_taxes_percentage() / 100;
1792
+					}
1793
+					// and apply to all the taxable totals, and add to the pretax totals
1794
+					foreach ($running_totals as $line_item_id => $this_running_total) {
1795
+						// "total" and "taxable" array key is an exception
1796
+						if ($line_item_id === 'taxable') {
1797
+							continue;
1798
+						}
1799
+						$taxable_total                   = $running_totals['taxable'][ $line_item_id ];
1800
+						$running_totals[ $line_item_id ] += ($taxable_total * $tax_percent_decimal);
1801
+					}
1802
+					break;
1803
+
1804
+				case EEM_Line_Item::type_line_item:
1805
+					// ticket line items or ????
1806
+					if ($child_line_item->OBJ_type() === EEM_Line_Item::OBJ_TYPE_TICKET) {
1807
+						// kk it's a ticket
1808
+						if (isset($running_totals[ $child_line_item->ID() ])) {
1809
+							// huh? that shouldn't happen.
1810
+							$running_totals['total'] += $child_line_item->total();
1811
+						} else {
1812
+							// it's not in our running totals yet. great.
1813
+							if ($child_line_item->is_taxable()) {
1814
+								$taxable_amount = $child_line_item->unit_price();
1815
+							} else {
1816
+								$taxable_amount = 0;
1817
+							}
1818
+							// are we only calculating totals for some tickets?
1819
+							if (isset($billable_ticket_quantities[ $child_line_item->OBJ_ID() ])) {
1820
+								$quantity = $billable_ticket_quantities[ $child_line_item->OBJ_ID() ];
1821
+
1822
+								$running_totals[ $child_line_item->ID() ]            = $quantity
1823
+									? $child_line_item->unit_price()
1824
+									: 0;
1825
+								$running_totals['taxable'][ $child_line_item->ID() ] = $quantity
1826
+									? $taxable_amount
1827
+									: 0;
1828
+							} else {
1829
+								$quantity                                            = $child_line_item->quantity();
1830
+								$running_totals[ $child_line_item->ID() ]            = $child_line_item->unit_price();
1831
+								$running_totals['taxable'][ $child_line_item->ID() ] = $taxable_amount;
1832
+							}
1833
+							$running_totals['taxable']['total'] += $taxable_amount * $quantity;
1834
+							$running_totals['total']            += $child_line_item->unit_price() * $quantity;
1835
+						}
1836
+					} else {
1837
+						// it's some other type of item added to the cart
1838
+						// it should affect the running totals
1839
+						// basically we want to convert it into a PERCENT modifier. Because
1840
+						// more clearly affect all registration's final price equally
1841
+						$line_items_percent_of_running_total = $running_totals['total'] > 0
1842
+							? ($child_line_item->total() / $running_totals['total']) + 1
1843
+							: 1;
1844
+						foreach ($running_totals as $line_item_id => $this_running_total) {
1845
+							// the "taxable" array key is an exception
1846
+							if ($line_item_id === 'taxable') {
1847
+								continue;
1848
+							}
1849
+							// update the running totals
1850
+							// yes this actually even works for the running grand total!
1851
+							$running_totals[ $line_item_id ] =
1852
+								$line_items_percent_of_running_total * $this_running_total;
1853
+
1854
+							if ($child_line_item->is_taxable()) {
1855
+								$running_totals['taxable'][ $line_item_id ] =
1856
+									$line_items_percent_of_running_total * $running_totals['taxable'][ $line_item_id ];
1857
+							}
1858
+						}
1859
+					}
1860
+					break;
1861
+			}
1862
+		}
1863
+		return $running_totals;
1864
+	}
1865
+
1866
+
1867
+	/**
1868
+	 * @param EE_Line_Item $total_line_item
1869
+	 * @param EE_Line_Item $ticket_line_item
1870
+	 * @return float | null
1871
+	 * @throws EE_Error
1872
+	 * @throws InvalidArgumentException
1873
+	 * @throws InvalidDataTypeException
1874
+	 * @throws InvalidInterfaceException
1875
+	 * @throws OutOfRangeException
1876
+	 * @throws ReflectionException
1877
+	 */
1878
+	public static function calculate_final_price_for_ticket_line_item(
1879
+		EE_Line_Item $total_line_item,
1880
+		EE_Line_Item $ticket_line_item
1881
+	): ?float {
1882
+		static $final_prices_per_ticket_line_item = [];
1883
+		if (
1884
+			empty($final_prices_per_ticket_line_item)
1885
+			|| empty($final_prices_per_ticket_line_item[ $total_line_item->ID() ])
1886
+		) {
1887
+			$final_prices_per_ticket_line_item[ $total_line_item->ID() ] =
1888
+				EEH_Line_Item::calculate_reg_final_prices_per_line_item(
1889
+					$total_line_item
1890
+				);
1891
+		}
1892
+		// ok now find this new registration's final price
1893
+		if (isset($final_prices_per_ticket_line_item[ $total_line_item->ID() ][ $ticket_line_item->ID() ])) {
1894
+			return $final_prices_per_ticket_line_item[ $total_line_item->ID() ][ $ticket_line_item->ID() ];
1895
+		}
1896
+		$message = sprintf(
1897
+			esc_html__(
1898
+				'The final price for the ticket line item (ID:%1$d) on the total line item (ID:%2$d) could not be calculated.',
1899
+				'event_espresso'
1900
+			),
1901
+			$ticket_line_item->ID(),
1902
+			$total_line_item->ID()
1903
+		);
1904
+		if (WP_DEBUG) {
1905
+			$message .= '<br>' . print_r($final_prices_per_ticket_line_item, true);
1906
+			throw new OutOfRangeException($message);
1907
+		}
1908
+		EE_Log::instance()->log(__CLASS__, __FUNCTION__, $message);
1909
+		return null;
1910
+	}
1911
+
1912
+
1913
+	/**
1914
+	 * Creates a duplicate of the line item tree, except only includes billable items
1915
+	 * and the portion of line items attributed to billable things
1916
+	 *
1917
+	 * @param EE_Line_Item      $line_item
1918
+	 * @param EE_Registration[] $registrations
1919
+	 * @return EE_Line_Item
1920
+	 * @throws EE_Error
1921
+	 * @throws InvalidArgumentException
1922
+	 * @throws InvalidDataTypeException
1923
+	 * @throws InvalidInterfaceException
1924
+	 * @throws ReflectionException
1925
+	 */
1926
+	public static function billable_line_item_tree(EE_Line_Item $line_item, array $registrations): EE_Line_Item
1927
+	{
1928
+		$copy_li = EEH_Line_Item::billable_line_item($line_item, $registrations);
1929
+		foreach ($line_item->children() as $child_li) {
1930
+			$copy_li->add_child_line_item(
1931
+				EEH_Line_Item::billable_line_item_tree($child_li, $registrations)
1932
+			);
1933
+		}
1934
+		// if this is the grand total line item, make sure the totals all add up
1935
+		// (we could have duplicated this logic AS we copied the line items, but
1936
+		// it seems DRYer this way)
1937
+		if ($copy_li->type() === EEM_Line_Item::type_total) {
1938
+			$copy_li->recalculate_total_including_taxes();
1939
+		}
1940
+		return $copy_li;
1941
+	}
1942
+
1943
+
1944
+	/**
1945
+	 * Creates a new, unsaved line item from $line_item that factors in the
1946
+	 * number of billable registrations on $registrations.
1947
+	 *
1948
+	 * @param EE_Line_Item      $line_item
1949
+	 * @param EE_Registration[] $registrations
1950
+	 * @return EE_Line_Item
1951
+	 * @throws EE_Error
1952
+	 * @throws InvalidArgumentException
1953
+	 * @throws InvalidDataTypeException
1954
+	 * @throws InvalidInterfaceException
1955
+	 * @throws ReflectionException
1956
+	 */
1957
+	public static function billable_line_item(EE_Line_Item $line_item, array $registrations): EE_Line_Item
1958
+	{
1959
+		$new_li_fields = $line_item->model_field_array();
1960
+		if (
1961
+			$line_item->type() === EEM_Line_Item::type_line_item &&
1962
+			$line_item->OBJ_type() === EEM_Line_Item::OBJ_TYPE_TICKET
1963
+		) {
1964
+			$count = 0;
1965
+			foreach ($registrations as $registration) {
1966
+				if (
1967
+					$line_item->OBJ_ID() === $registration->ticket_ID() &&
1968
+					in_array(
1969
+						$registration->status_ID(),
1970
+						EEM_Registration::reg_statuses_that_allow_payment(),
1971
+						true
1972
+					)
1973
+				) {
1974
+					$count++;
1975
+				}
1976
+			}
1977
+			$new_li_fields['LIN_quantity'] = $count;
1978
+		}
1979
+		// don't set the total. We'll leave that up to the code that calculates it
1980
+		unset($new_li_fields['LIN_ID'], $new_li_fields['LIN_parent'], $new_li_fields['LIN_total']);
1981
+		return EE_Line_Item::new_instance($new_li_fields);
1982
+	}
1983
+
1984
+
1985
+	/**
1986
+	 * Returns a modified line item tree where all the subtotals which have a total of 0
1987
+	 * are removed, and line items with a quantity of 0
1988
+	 *
1989
+	 * @param EE_Line_Item $line_item |null
1990
+	 * @return EE_Line_Item|null
1991
+	 * @throws EE_Error
1992
+	 * @throws InvalidArgumentException
1993
+	 * @throws InvalidDataTypeException
1994
+	 * @throws InvalidInterfaceException
1995
+	 * @throws ReflectionException
1996
+	 */
1997
+	public static function non_empty_line_items(EE_Line_Item $line_item): ?EE_Line_Item
1998
+	{
1999
+		$copied_li = EEH_Line_Item::non_empty_line_item($line_item);
2000
+		if ($copied_li === null) {
2001
+			return null;
2002
+		}
2003
+		// if this is an event subtotal, we want to only include it if it
2004
+		// has a non-zero total and at least one ticket line item child
2005
+		$ticket_children = 0;
2006
+		foreach ($line_item->children() as $child_li) {
2007
+			$child_li_copy = EEH_Line_Item::non_empty_line_items($child_li);
2008
+			if ($child_li_copy !== null) {
2009
+				$copied_li->add_child_line_item($child_li_copy);
2010
+				if (
2011
+					$child_li_copy->type() === EEM_Line_Item::type_line_item &&
2012
+					$child_li_copy->OBJ_type() === EEM_Line_Item::OBJ_TYPE_TICKET
2013
+				) {
2014
+					$ticket_children++;
2015
+				}
2016
+			}
2017
+		}
2018
+		// if this is an event subtotal with NO ticket children
2019
+		// we basically want to ignore it
2020
+		if (
2021
+			$ticket_children === 0
2022
+			&& $line_item->type() === EEM_Line_Item::type_sub_total
2023
+			&& $line_item->OBJ_type() === EEM_Line_Item::OBJ_TYPE_EVENT
2024
+			&& $line_item->total() === 0.0
2025
+		) {
2026
+			return null;
2027
+		}
2028
+		return $copied_li;
2029
+	}
2030
+
2031
+
2032
+	/**
2033
+	 * Creates a new, unsaved line item, but if it's a ticket line item
2034
+	 * with a total of 0, or a subtotal of 0, returns null instead
2035
+	 *
2036
+	 * @param EE_Line_Item $line_item
2037
+	 * @return EE_Line_Item
2038
+	 * @throws EE_Error
2039
+	 * @throws InvalidArgumentException
2040
+	 * @throws InvalidDataTypeException
2041
+	 * @throws InvalidInterfaceException
2042
+	 * @throws ReflectionException
2043
+	 */
2044
+	public static function non_empty_line_item(EE_Line_Item $line_item): ?EE_Line_Item
2045
+	{
2046
+		if (
2047
+			$line_item->type() === EEM_Line_Item::type_line_item
2048
+			&& $line_item->OBJ_type() === EEM_Line_Item::OBJ_TYPE_TICKET
2049
+			&& $line_item->quantity() === 0
2050
+		) {
2051
+			return null;
2052
+		}
2053
+		$new_li_fields = $line_item->model_field_array();
2054
+		// don't set the total. We'll leave that up to the code that calculates it
2055
+		unset($new_li_fields['LIN_ID'], $new_li_fields['LIN_parent']);
2056
+		return EE_Line_Item::new_instance($new_li_fields);
2057
+	}
2058
+
2059
+
2060
+	/**
2061
+	 * Cycles through all the ticket line items for the supplied total line item
2062
+	 * and ensures that the line item's "is_taxable" field matches that of its corresponding ticket
2063
+	 *
2064
+	 * @param EE_Line_Item $total_line_item
2065
+	 * @throws EE_Error
2066
+	 * @throws InvalidArgumentException
2067
+	 * @throws InvalidDataTypeException
2068
+	 * @throws InvalidInterfaceException
2069
+	 * @throws ReflectionException
2070
+	 * @since 4.9.79.p
2071
+	 */
2072
+	public static function resetIsTaxableForTickets(EE_Line_Item $total_line_item)
2073
+	{
2074
+		$ticket_line_items = self::get_ticket_line_items($total_line_item);
2075
+		foreach ($ticket_line_items as $ticket_line_item) {
2076
+			if (
2077
+				$ticket_line_item instanceof EE_Line_Item
2078
+				&& $ticket_line_item->OBJ_type() === EEM_Line_Item::OBJ_TYPE_TICKET
2079
+			) {
2080
+				$ticket = $ticket_line_item->ticket();
2081
+				if ($ticket instanceof EE_Ticket && $ticket->taxable() !== $ticket_line_item->is_taxable()) {
2082
+					$ticket_line_item->set_is_taxable($ticket->taxable());
2083
+					$ticket_line_item->save();
2084
+				}
2085
+			}
2086
+		}
2087
+	}
2088
+
2089
+
2090
+	/**
2091
+	 * @return EE_Line_Item[]
2092
+	 * @throws EE_Error
2093
+	 * @throws ReflectionException
2094
+	 * @since   5.0.0.p
2095
+	 */
2096
+	private static function getGlobalTaxes(): array
2097
+	{
2098
+		if (EEH_Line_Item::$global_taxes === null) {
2099
+			/** @type EEM_Price $EEM_Price */
2100
+			$EEM_Price = EE_Registry::instance()->load_model('Price');
2101
+			// get array of taxes via Price Model
2102
+			EEH_Line_Item::$global_taxes = $EEM_Price->get_all_prices_that_are_taxes();
2103
+			ksort(EEH_Line_Item::$global_taxes);
2104
+		}
2105
+		return EEH_Line_Item::$global_taxes;
2106
+	}
2107
+
2108
+
2109
+
2110
+	/**************************************** @DEPRECATED METHODS *************************************** */
2111
+	/**
2112
+	 * @param EE_Line_Item $total_line_item
2113
+	 * @return EE_Line_Item
2114
+	 * @throws EE_Error
2115
+	 * @throws InvalidArgumentException
2116
+	 * @throws InvalidDataTypeException
2117
+	 * @throws InvalidInterfaceException
2118
+	 * @throws ReflectionException
2119
+	 * @deprecated
2120
+	 */
2121
+	public static function get_items_subtotal(EE_Line_Item $total_line_item): EE_Line_Item
2122
+	{
2123
+		EE_Error::doing_it_wrong(
2124
+			'EEH_Line_Item::get_items_subtotal()',
2125
+			sprintf(
2126
+				esc_html__('Method replaced with %1$s', 'event_espresso'),
2127
+				'EEH_Line_Item::get_pre_tax_subtotal()'
2128
+			),
2129
+			'4.6.0'
2130
+		);
2131
+		return self::get_pre_tax_subtotal($total_line_item);
2132
+	}
2133
+
2134
+
2135
+	/**
2136
+	 * @param EE_Transaction|null $transaction
2137
+	 * @return EE_Line_Item
2138
+	 * @throws EE_Error
2139
+	 * @throws InvalidArgumentException
2140
+	 * @throws InvalidDataTypeException
2141
+	 * @throws InvalidInterfaceException
2142
+	 * @throws ReflectionException
2143
+	 * @deprecated
2144
+	 */
2145
+	public static function create_default_total_line_item(?EE_Transaction $transaction = null): EE_Line_Item
2146
+	{
2147
+		EE_Error::doing_it_wrong(
2148
+			'EEH_Line_Item::create_default_total_line_item()',
2149
+			sprintf(
2150
+				esc_html__('Method replaced with %1$s', 'event_espresso'),
2151
+				'EEH_Line_Item::create_total_line_item()'
2152
+			),
2153
+			'4.6.0'
2154
+		);
2155
+		return self::create_total_line_item($transaction);
2156
+	}
2157
+
2158
+
2159
+	/**
2160
+	 * @param EE_Line_Item        $total_line_item
2161
+	 * @param EE_Transaction|null $transaction
2162
+	 * @return EE_Line_Item
2163
+	 * @throws EE_Error
2164
+	 * @throws InvalidArgumentException
2165
+	 * @throws InvalidDataTypeException
2166
+	 * @throws InvalidInterfaceException
2167
+	 * @throws ReflectionException
2168
+	 * @deprecated
2169
+	 */
2170
+	public static function create_default_tickets_subtotal(
2171
+		EE_Line_Item $total_line_item,
2172
+		?EE_Transaction $transaction = null
2173
+	): EE_Line_Item {
2174
+		EE_Error::doing_it_wrong(
2175
+			'EEH_Line_Item::create_default_tickets_subtotal()',
2176
+			sprintf(
2177
+				esc_html__('Method replaced with %1$s', 'event_espresso'),
2178
+				'EEH_Line_Item::create_pre_tax_subtotal()'
2179
+			),
2180
+			'4.6.0'
2181
+		);
2182
+		return self::create_pre_tax_subtotal($total_line_item, $transaction);
2183
+	}
2184
+
2185
+
2186
+	/**
2187
+	 * @param EE_Line_Item        $total_line_item
2188
+	 * @param EE_Transaction|null $transaction
2189
+	 * @return EE_Line_Item
2190
+	 * @throws EE_Error
2191
+	 * @throws InvalidArgumentException
2192
+	 * @throws InvalidDataTypeException
2193
+	 * @throws InvalidInterfaceException
2194
+	 * @throws ReflectionException
2195
+	 * @deprecated
2196
+	 */
2197
+	public static function create_default_taxes_subtotal(
2198
+		EE_Line_Item $total_line_item,
2199
+		?EE_Transaction $transaction = null
2200
+	): EE_Line_Item {
2201
+		EE_Error::doing_it_wrong(
2202
+			'EEH_Line_Item::create_default_taxes_subtotal()',
2203
+			sprintf(
2204
+				esc_html__('Method replaced with %1$s', 'event_espresso'),
2205
+				'EEH_Line_Item::create_taxes_subtotal()'
2206
+			),
2207
+			'4.6.0'
2208
+		);
2209
+		return self::create_taxes_subtotal($total_line_item, $transaction);
2210
+	}
2211
+
2212
+
2213
+	/**
2214
+	 * @param EE_Line_Item        $total_line_item
2215
+	 * @param EE_Transaction|null $transaction
2216
+	 * @return EE_Line_Item
2217
+	 * @throws EE_Error
2218
+	 * @throws InvalidArgumentException
2219
+	 * @throws InvalidDataTypeException
2220
+	 * @throws InvalidInterfaceException
2221
+	 * @throws ReflectionException
2222
+	 * @deprecated
2223
+	 */
2224
+	public static function create_default_event_subtotal(
2225
+		EE_Line_Item $total_line_item,
2226
+		?EE_Transaction $transaction = null
2227
+	): EE_Line_Item {
2228
+		EE_Error::doing_it_wrong(
2229
+			'EEH_Line_Item::create_default_event_subtotal()',
2230
+			sprintf(
2231
+				esc_html__('Method replaced with %1$s', 'event_espresso'),
2232
+				'EEH_Line_Item::create_event_subtotal()'
2233
+			),
2234
+			'4.6.0'
2235
+		);
2236
+		return self::create_event_subtotal($total_line_item, $transaction);
2237
+	}
2238 2238
 }
Please login to merge, or discard this patch.
Spacing   +46 added lines, -46 removed lines patch added patch discarded remove patch
@@ -24,7 +24,7 @@  discard block
 block discarded – undo
24 24
     /**
25 25
      * @var EE_Line_Item[]|null
26 26
      */
27
-    private static ?array $global_taxes = null;
27
+    private static ? array $global_taxes = null;
28 28
 
29 29
 
30 30
     /**
@@ -73,12 +73,12 @@  discard block
 block discarded – undo
73 73
                 'LIN_code'       => $code,
74 74
             ]
75 75
         );
76
-        $line_item      = apply_filters(
76
+        $line_item = apply_filters(
77 77
             'FHEE__EEH_Line_Item__add_unrelated_item__line_item',
78 78
             $line_item,
79 79
             $parent_line_item
80 80
         );
81
-        $added          = self::add_item($parent_line_item, $line_item, $recalculate_totals);
81
+        $added = self::add_item($parent_line_item, $line_item, $recalculate_totals);
82 82
         return $return_item ? $line_item : $added;
83 83
     }
84 84
 
@@ -131,7 +131,7 @@  discard block
 block discarded – undo
131 131
             'FHEE__EEH_Line_Item__add_percentage_based_item__line_item',
132 132
             $line_item
133 133
         );
134
-        $added     = $parent_line_item->add_child_line_item($line_item, false);
134
+        $added = $parent_line_item->add_child_line_item($line_item, false);
135 135
         return $return_item ? $line_item : $added;
136 136
     }
137 137
 
@@ -160,7 +160,7 @@  discard block
 block discarded – undo
160 160
         int $qty = 1,
161 161
         bool $recalculate_totals = true
162 162
     ): ?EE_Line_Item {
163
-        if (! $total_line_item instanceof EE_Line_Item || ! $total_line_item->is_total()) {
163
+        if ( ! $total_line_item instanceof EE_Line_Item || ! $total_line_item->is_total()) {
164 164
             throw new EE_Error(
165 165
                 sprintf(
166 166
                     esc_html__(
@@ -175,7 +175,7 @@  discard block
 block discarded – undo
175 175
         // either increment the qty for an existing ticket
176 176
         $line_item = self::increment_ticket_qty_if_already_in_cart($total_line_item, $ticket, $qty);
177 177
         // or add a new one
178
-        if (! $line_item instanceof EE_Line_Item) {
178
+        if ( ! $line_item instanceof EE_Line_Item) {
179 179
             $line_item = self::create_ticket_line_item($total_line_item, $ticket, $qty);
180 180
         }
181 181
         if ($recalculate_totals) {
@@ -239,7 +239,7 @@  discard block
 block discarded – undo
239 239
      */
240 240
     public static function increment_quantity(EE_Line_Item $line_item, int $qty = 1)
241 241
     {
242
-        if (! $line_item->is_percent()) {
242
+        if ( ! $line_item->is_percent()) {
243 243
             $qty += $line_item->quantity();
244 244
             $line_item->set_quantity($qty);
245 245
             $line_item->set_total($line_item->unit_price() * $qty);
@@ -268,7 +268,7 @@  discard block
 block discarded – undo
268 268
      */
269 269
     public static function decrement_quantity(EE_Line_Item $line_item, int $qty = 1)
270 270
     {
271
-        if (! $line_item->is_percent()) {
271
+        if ( ! $line_item->is_percent()) {
272 272
             $qty = $line_item->quantity() - $qty;
273 273
             $qty = max($qty, 0);
274 274
             $line_item->set_quantity($qty);
@@ -297,7 +297,7 @@  discard block
 block discarded – undo
297 297
      */
298 298
     public static function update_quantity(EE_Line_Item $line_item, int $new_quantity)
299 299
     {
300
-        if (! $line_item->is_percent()) {
300
+        if ( ! $line_item->is_percent()) {
301 301
             $line_item->set_quantity($new_quantity);
302 302
             $line_item->set_total($line_item->unit_price() * $new_quantity);
303 303
             $line_item->save();
@@ -342,7 +342,7 @@  discard block
 block discarded – undo
342 342
         $line_item = EE_Line_Item::new_instance(
343 343
             [
344 344
                 'LIN_name'       => $ticket->name(),
345
-                'LIN_desc'       => $ticket->description() !== '' ? $ticket->description() . ' ' . $event : $event,
345
+                'LIN_desc'       => $ticket->description() !== '' ? $ticket->description().' '.$event : $event,
346 346
                 'LIN_unit_price' => $ticket->price(),
347 347
                 'LIN_quantity'   => $qty,
348 348
                 'LIN_is_taxable' => empty($taxes) && $ticket->taxable(),
@@ -357,7 +357,7 @@  discard block
 block discarded – undo
357 357
             'FHEE__EEH_Line_Item__create_ticket_line_item__line_item',
358 358
             $line_item
359 359
         );
360
-        if (! $line_item instanceof EE_Line_Item) {
360
+        if ( ! $line_item instanceof EE_Line_Item) {
361 361
             throw new DomainException(
362 362
                 esc_html__('Invalid EE_Line_Item received.', 'event_espresso')
363 363
             );
@@ -396,7 +396,7 @@  discard block
 block discarded – undo
396 396
                 ? $price_type->name()
397 397
                 : $price_desc;
398 398
 
399
-            $sub_line_item         = EE_Line_Item::new_instance(
399
+            $sub_line_item = EE_Line_Item::new_instance(
400 400
                 [
401 401
                     'LIN_name'       => $price->name(),
402 402
                     'LIN_desc'       => $price_desc,
@@ -413,7 +413,7 @@  discard block
 block discarded – undo
413 413
                     'OBJ_type'       => EEM_Line_Item::OBJ_TYPE_PRICE,
414 414
                 ]
415 415
             );
416
-            $sub_line_item         = apply_filters(
416
+            $sub_line_item = apply_filters(
417 417
                 'FHEE__EEH_Line_Item__create_ticket_line_item__sub_line_item',
418 418
                 $sub_line_item
419 419
             );
@@ -530,7 +530,7 @@  discard block
 block discarded – undo
530 530
                             'event_espresso'
531 531
                         ),
532 532
                         $ticket_line_item->name(),
533
-                        current_time(get_option('date_format') . ' ' . get_option('time_format'))
533
+                        current_time(get_option('date_format').' '.get_option('time_format'))
534 534
                     ),
535 535
                     'LIN_unit_price' => 0, // $ticket_line_item->unit_price()
536 536
                     'LIN_quantity'   => $qty,
@@ -594,7 +594,7 @@  discard block
 block discarded – undo
594 594
         );
595 595
         $cancellation_line_item = reset($cancellation_line_item);
596 596
         // verify that this ticket was indeed previously cancelled
597
-        if (! $cancellation_line_item instanceof EE_Line_Item) {
597
+        if ( ! $cancellation_line_item instanceof EE_Line_Item) {
598 598
             return false;
599 599
         }
600 600
         if ($cancellation_line_item->quantity() > $qty) {
@@ -809,7 +809,7 @@  discard block
 block discarded – undo
809 809
                 'LIN_code'  => 'taxes',
810 810
                 'LIN_name'  => esc_html__('Taxes', 'event_espresso'),
811 811
                 'LIN_type'  => EEM_Line_Item::type_tax_sub_total,
812
-                'LIN_order' => 1000,// this should always come last
812
+                'LIN_order' => 1000, // this should always come last
813 813
             ]
814 814
         );
815 815
         $tax_line_item = apply_filters(
@@ -872,7 +872,7 @@  discard block
 block discarded – undo
872 872
      */
873 873
     public static function get_event_code(?EE_Event $event = null): string
874 874
     {
875
-        return 'event-' . ($event instanceof EE_Event ? $event->ID() : '0');
875
+        return 'event-'.($event instanceof EE_Event ? $event->ID() : '0');
876 876
     }
877 877
 
878 878
 
@@ -923,7 +923,7 @@  discard block
 block discarded – undo
923 923
     public static function get_event_line_item_for_ticket(EE_Line_Item $grand_total, EE_Ticket $ticket): EE_Line_Item
924 924
     {
925 925
         $first_datetime = $ticket->first_datetime();
926
-        if (! $first_datetime instanceof EE_Datetime) {
926
+        if ( ! $first_datetime instanceof EE_Datetime) {
927 927
             throw new EE_Error(
928 928
                 sprintf(
929 929
                     esc_html__('The supplied ticket (ID %d) has no datetimes', 'event_espresso'),
@@ -932,7 +932,7 @@  discard block
 block discarded – undo
932 932
             );
933 933
         }
934 934
         $event = $first_datetime->event();
935
-        if (! $event instanceof EE_Event) {
935
+        if ( ! $event instanceof EE_Event) {
936 936
             throw new EE_Error(
937 937
                 sprintf(
938 938
                     esc_html__(
@@ -944,7 +944,7 @@  discard block
 block discarded – undo
944 944
             );
945 945
         }
946 946
         $events_sub_total = EEH_Line_Item::get_event_line_item($grand_total, $event);
947
-        if (! $events_sub_total instanceof EE_Line_Item) {
947
+        if ( ! $events_sub_total instanceof EE_Line_Item) {
948 948
             throw new EE_Error(
949 949
                 sprintf(
950 950
                     esc_html__(
@@ -980,7 +980,7 @@  discard block
 block discarded – undo
980 980
         $found           = false;
981 981
         foreach (EEH_Line_Item::get_event_subtotals($grand_total) as $event_line_item) {
982 982
             // default event subtotal, we should only ever find this the first time this method is called
983
-            if (! $event_line_item->OBJ_ID()) {
983
+            if ( ! $event_line_item->OBJ_ID()) {
984 984
                 // let's use this! but first... set the event details
985 985
                 EEH_Line_Item::set_event_subtotal_details($event_line_item, $event);
986 986
                 $found = true;
@@ -992,7 +992,7 @@  discard block
 block discarded – undo
992 992
                 break;
993 993
             }
994 994
         }
995
-        if (! $found) {
995
+        if ( ! $found) {
996 996
             // there is no event sub-total yet, so add it
997 997
             $pre_tax_subtotal = EEH_Line_Item::get_pre_tax_subtotal($grand_total);
998 998
             // create a new "event" subtotal below that
@@ -1072,7 +1072,7 @@  discard block
 block discarded – undo
1072 1072
                             break;
1073 1073
                         }
1074 1074
                     }
1075
-                    if (! $found) {
1075
+                    if ( ! $found) {
1076 1076
                         // add a new line item for this global tax
1077 1077
                         $tax_line_item = apply_filters(
1078 1078
                             'FHEE__EEH_Line_Item__apply_taxes__tax_line_item',
@@ -1090,7 +1090,7 @@  discard block
 block discarded – undo
1090 1090
                                 ]
1091 1091
                             )
1092 1092
                         );
1093
-                        $updates       = $taxes_line_item->add_child_line_item($tax_line_item) ? true : $updates;
1093
+                        $updates = $taxes_line_item->add_child_line_item($tax_line_item) ? true : $updates;
1094 1094
                     }
1095 1095
                 }
1096 1096
             }
@@ -1119,7 +1119,7 @@  discard block
 block discarded – undo
1119 1119
     public static function ensure_taxes_applied(?EE_Line_Item $total_line_item): float
1120 1120
     {
1121 1121
         $taxes_subtotal = self::get_taxes_subtotal($total_line_item);
1122
-        if (! $taxes_subtotal->children()) {
1122
+        if ( ! $taxes_subtotal->children()) {
1123 1123
             self::apply_taxes($total_line_item);
1124 1124
         }
1125 1125
         return $taxes_subtotal->total();
@@ -1185,7 +1185,7 @@  discard block
 block discarded – undo
1185 1185
         }
1186 1186
 
1187 1187
         // check if only a single line_item_id was passed
1188
-        if (! empty($line_item_codes) && ! is_array($line_item_codes)) {
1188
+        if ( ! empty($line_item_codes) && ! is_array($line_item_codes)) {
1189 1189
             // place single line_item_id in an array to appear as multiple line_item_ids
1190 1190
             $line_item_codes = [$line_item_codes];
1191 1191
         }
@@ -1295,7 +1295,7 @@  discard block
 block discarded – undo
1295 1295
         if ($code_substring_for_whitelist !== null) {
1296 1296
             $whitelisted = strpos($line_item->code(), $code_substring_for_whitelist) !== false;
1297 1297
         }
1298
-        if (! $whitelisted && $line_item->is_line_item()) {
1298
+        if ( ! $whitelisted && $line_item->is_line_item()) {
1299 1299
             $line_item->set_is_taxable($taxable);
1300 1300
         }
1301 1301
         foreach ($line_item->children() as $child_line_item) {
@@ -1677,7 +1677,7 @@  discard block
 block discarded – undo
1677 1677
      */
1678 1678
     public static function visualize(EE_Line_Item $line_item, int $indentation = 0, bool $top_level = true)
1679 1679
     {
1680
-        if (! defined('WP_DEBUG') || ! WP_DEBUG) {
1680
+        if ( ! defined('WP_DEBUG') || ! WP_DEBUG) {
1681 1681
             return;
1682 1682
         }
1683 1683
         $testing  = defined('EE_TESTS_DIR');
@@ -1775,7 +1775,7 @@  discard block
 block discarded – undo
1775 1775
                         $billable_ticket_quantities
1776 1776
                     );
1777 1777
                     // combine arrays but preserve numeric keys
1778
-                    $running_totals                     = array_replace_recursive(
1778
+                    $running_totals = array_replace_recursive(
1779 1779
                         $running_totals_from_subtotal,
1780 1780
                         $running_totals
1781 1781
                     );
@@ -1796,8 +1796,8 @@  discard block
 block discarded – undo
1796 1796
                         if ($line_item_id === 'taxable') {
1797 1797
                             continue;
1798 1798
                         }
1799
-                        $taxable_total                   = $running_totals['taxable'][ $line_item_id ];
1800
-                        $running_totals[ $line_item_id ] += ($taxable_total * $tax_percent_decimal);
1799
+                        $taxable_total = $running_totals['taxable'][$line_item_id];
1800
+                        $running_totals[$line_item_id] += ($taxable_total * $tax_percent_decimal);
1801 1801
                     }
1802 1802
                     break;
1803 1803
 
@@ -1805,7 +1805,7 @@  discard block
 block discarded – undo
1805 1805
                     // ticket line items or ????
1806 1806
                     if ($child_line_item->OBJ_type() === EEM_Line_Item::OBJ_TYPE_TICKET) {
1807 1807
                         // kk it's a ticket
1808
-                        if (isset($running_totals[ $child_line_item->ID() ])) {
1808
+                        if (isset($running_totals[$child_line_item->ID()])) {
1809 1809
                             // huh? that shouldn't happen.
1810 1810
                             $running_totals['total'] += $child_line_item->total();
1811 1811
                         } else {
@@ -1816,19 +1816,19 @@  discard block
 block discarded – undo
1816 1816
                                 $taxable_amount = 0;
1817 1817
                             }
1818 1818
                             // are we only calculating totals for some tickets?
1819
-                            if (isset($billable_ticket_quantities[ $child_line_item->OBJ_ID() ])) {
1820
-                                $quantity = $billable_ticket_quantities[ $child_line_item->OBJ_ID() ];
1819
+                            if (isset($billable_ticket_quantities[$child_line_item->OBJ_ID()])) {
1820
+                                $quantity = $billable_ticket_quantities[$child_line_item->OBJ_ID()];
1821 1821
 
1822
-                                $running_totals[ $child_line_item->ID() ]            = $quantity
1822
+                                $running_totals[$child_line_item->ID()]            = $quantity
1823 1823
                                     ? $child_line_item->unit_price()
1824 1824
                                     : 0;
1825
-                                $running_totals['taxable'][ $child_line_item->ID() ] = $quantity
1825
+                                $running_totals['taxable'][$child_line_item->ID()] = $quantity
1826 1826
                                     ? $taxable_amount
1827 1827
                                     : 0;
1828 1828
                             } else {
1829 1829
                                 $quantity                                            = $child_line_item->quantity();
1830
-                                $running_totals[ $child_line_item->ID() ]            = $child_line_item->unit_price();
1831
-                                $running_totals['taxable'][ $child_line_item->ID() ] = $taxable_amount;
1830
+                                $running_totals[$child_line_item->ID()]            = $child_line_item->unit_price();
1831
+                                $running_totals['taxable'][$child_line_item->ID()] = $taxable_amount;
1832 1832
                             }
1833 1833
                             $running_totals['taxable']['total'] += $taxable_amount * $quantity;
1834 1834
                             $running_totals['total']            += $child_line_item->unit_price() * $quantity;
@@ -1848,12 +1848,12 @@  discard block
 block discarded – undo
1848 1848
                             }
1849 1849
                             // update the running totals
1850 1850
                             // yes this actually even works for the running grand total!
1851
-                            $running_totals[ $line_item_id ] =
1851
+                            $running_totals[$line_item_id] =
1852 1852
                                 $line_items_percent_of_running_total * $this_running_total;
1853 1853
 
1854 1854
                             if ($child_line_item->is_taxable()) {
1855
-                                $running_totals['taxable'][ $line_item_id ] =
1856
-                                    $line_items_percent_of_running_total * $running_totals['taxable'][ $line_item_id ];
1855
+                                $running_totals['taxable'][$line_item_id] =
1856
+                                    $line_items_percent_of_running_total * $running_totals['taxable'][$line_item_id];
1857 1857
                             }
1858 1858
                         }
1859 1859
                     }
@@ -1882,16 +1882,16 @@  discard block
 block discarded – undo
1882 1882
         static $final_prices_per_ticket_line_item = [];
1883 1883
         if (
1884 1884
             empty($final_prices_per_ticket_line_item)
1885
-            || empty($final_prices_per_ticket_line_item[ $total_line_item->ID() ])
1885
+            || empty($final_prices_per_ticket_line_item[$total_line_item->ID()])
1886 1886
         ) {
1887
-            $final_prices_per_ticket_line_item[ $total_line_item->ID() ] =
1887
+            $final_prices_per_ticket_line_item[$total_line_item->ID()] =
1888 1888
                 EEH_Line_Item::calculate_reg_final_prices_per_line_item(
1889 1889
                     $total_line_item
1890 1890
                 );
1891 1891
         }
1892 1892
         // ok now find this new registration's final price
1893
-        if (isset($final_prices_per_ticket_line_item[ $total_line_item->ID() ][ $ticket_line_item->ID() ])) {
1894
-            return $final_prices_per_ticket_line_item[ $total_line_item->ID() ][ $ticket_line_item->ID() ];
1893
+        if (isset($final_prices_per_ticket_line_item[$total_line_item->ID()][$ticket_line_item->ID()])) {
1894
+            return $final_prices_per_ticket_line_item[$total_line_item->ID()][$ticket_line_item->ID()];
1895 1895
         }
1896 1896
         $message = sprintf(
1897 1897
             esc_html__(
@@ -1902,7 +1902,7 @@  discard block
 block discarded – undo
1902 1902
             $total_line_item->ID()
1903 1903
         );
1904 1904
         if (WP_DEBUG) {
1905
-            $message .= '<br>' . print_r($final_prices_per_ticket_line_item, true);
1905
+            $message .= '<br>'.print_r($final_prices_per_ticket_line_item, true);
1906 1906
             throw new OutOfRangeException($message);
1907 1907
         }
1908 1908
         EE_Log::instance()->log(__CLASS__, __FUNCTION__, $message);
Please login to merge, or discard this patch.
core/helpers/EEH_Parse_Shortcodes.helper.php 1 patch
Indentation   +263 added lines, -263 removed lines patch added patch discarded remove patch
@@ -11,267 +11,267 @@
 block discarded – undo
11 11
  */
12 12
 class EEH_Parse_Shortcodes
13 13
 {
14
-    /**
15
-     * holds the template
16
-     *
17
-     * @access private
18
-     * @var mixed (string|array)
19
-     */
20
-    private $_template;
21
-
22
-
23
-    /**
24
-     * holds the incoming data object
25
-     *
26
-     * @access private
27
-     * @var object
28
-     */
29
-    private $_data;
30
-
31
-
32
-    /**
33
-     * will hold an array of EE_Shortcodes library objects.
34
-     *
35
-     * @access private
36
-     * @var EE_Shortcodes[]
37
-     */
38
-    private $_shortcode_objs = array();
39
-
40
-
41
-    public function __construct()
42
-    {
43
-    }
44
-
45
-
46
-    /**
47
-     * This kicks off the parsing of shortcodes in message templates
48
-     *
49
-     * @param  string                $template         This is the incoming string to be parsed
50
-     * @param  EE_Messages_Addressee $data             This is the incoming data object
51
-     * @param  array                 $valid_shortcodes An array of strings that correspond to EE_Shortcode libraries
52
-     * @param EE_message_type        $message_type     The message type that called the parser
53
-     * @param EE_messenger           $messenger        The active messenger for this parsing session.
54
-     * @param EE_Message             $message
55
-     * @return string                   The parsed template string
56
-     */
57
-    public function parse_message_template(
58
-        $template,
59
-        EE_Messages_Addressee $data,
60
-        $valid_shortcodes,
61
-        EE_message_type $message_type,
62
-        EE_messenger $messenger,
63
-        EE_Message $message
64
-    ) {
65
-        $extra_data = array(
66
-            'messenger'    => $messenger,
67
-            'message_type' => $message_type,
68
-            'message'      => $message,
69
-        );
70
-        $this->_init_data($template, $data, $valid_shortcodes, $extra_data);
71
-        $this->_template = is_array($template) ? $template['main'] : $template;
72
-        return $this->_parse_message_template();
73
-    }
74
-
75
-
76
-    public function parse_attendee_list_template(
77
-        $template,
78
-        EE_Registration $registration,
79
-        $valid_shortcodes,
80
-        $extra_data = array()
81
-    ) {
82
-        $this->_init_data($template, $registration, $valid_shortcodes, $extra_data);
83
-        $this->_template = is_array($template) ? $template['attendee_list'] : $template;
84
-        return $this->_parse_message_template();
85
-    }
86
-
87
-    public function parse_event_list_template($template, EE_Event $event, $valid_shortcodes, $extra_data = array())
88
-    {
89
-        $this->_init_data($template, $event, $valid_shortcodes, $extra_data);
90
-        $this->_template = is_array($template) ? $template['event_list'] : $template;
91
-        return $this->_parse_message_template();
92
-    }
93
-
94
-
95
-    public function parse_ticket_list_template($template, EE_Ticket $ticket, $valid_shortcodes, $extra_data = array())
96
-    {
97
-        $this->_init_data($template, $ticket, $valid_shortcodes, $extra_data);
98
-        $this->_template = is_array($template) ? $template['ticket_list'] : $template;
99
-        return $this->_parse_message_template();
100
-    }
101
-
102
-
103
-    public function parse_line_item_list_template(
104
-        $template,
105
-        EE_Line_Item $line_item,
106
-        $valid_shortcodes,
107
-        $extra_data = array()
108
-    ) {
109
-        $this->_init_data($template, $line_item, $valid_shortcodes, $extra_data);
110
-        $this->_template = is_array($template) ? $template['ticket_line_item_no_pms'] : $template;
111
-        return $this->_parse_message_template();
112
-    }
113
-
114
-
115
-    public function parse_payment_list_template(
116
-        $template,
117
-        EE_Payment $payment_item,
118
-        $valid_shortcodes,
119
-        $extra_data = array()
120
-    ) {
121
-        $this->_init_data($template, $payment_item, $valid_shortcodes, $extra_data);
122
-        $this->_template = is_array($template) ? $template['payment_list'] : $template;
123
-        return $this->_parse_message_template();
124
-    }
125
-
126
-
127
-    public function parse_datetime_list_template(
128
-        $template,
129
-        EE_Datetime $datetime,
130
-        $valid_shortcodes,
131
-        $extra_data = array()
132
-    ) {
133
-        $this->_init_data($template, $datetime, $valid_shortcodes, $extra_data);
134
-        $this->_template = is_array($template) ? $template['datetime_list'] : $template;
135
-        return $this->_parse_message_template();
136
-    }
137
-
138
-
139
-    public function parse_question_list_template($template, EE_Answer $answer, $valid_shortcodes, $extra_data = array())
140
-    {
141
-        $this->_init_data($template, $answer, $valid_shortcodes, $extra_data);
142
-        $this->_template = is_array($template) ? $template['question_list'] : $template;
143
-        return $this->_parse_message_template();
144
-    }
145
-
146
-
147
-    private function _init_data($template, $data, $valid_shortcodes, $extra_data = array())
148
-    {
149
-        $this->_reset_props();
150
-        $this->_data['template']   = $template;
151
-        $this->_data['data']       = $data;
152
-        $this->_data['extra_data'] = $extra_data;
153
-        $this->_set_shortcodes($valid_shortcodes);
154
-    }
155
-
156
-
157
-    private function _reset_props()
158
-    {
159
-        $this->_template       = $this->_data = null;
160
-        $this->_shortcode_objs = array();
161
-    }
162
-
163
-
164
-    /**
165
-     * takes the given template and parses it with the $_shortcodes property
166
-     *
167
-     * @access private
168
-     * @return string
169
-     */
170
-    private function _parse_message_template()
171
-    {
172
-        // now let's get a list of shortcodes that are found in the given template
173
-        preg_match_all('/(\[.+?\])/', $this->_template, $matches);
174
-        $shortcodes = (array) $matches[0]; // this should be an array of shortcodes in the template string.
175
-
176
-        $matched_code = array();
177
-        $sc_values    = array();
178
-
179
-        $list_type_shortcodes = array(
180
-            '[ATTENDEE_LIST]',
181
-            '[EVENT_LIST]',
182
-            '[TICKET_LIST]',
183
-            '[DATETIME_LIST]',
184
-            '[QUESTION_LIST]',
185
-            '[RECIPIENT_QUESTION_LIST]',
186
-            '[PRIMARY_REGISTRANT_QUESTION_LIST]',
187
-            '[RECIPIENT_TICKET_LIST]',
188
-            '[PRIMARY_REGISTRANT_TICKET_LIST]',
189
-            '[RECIPIENT_DATETIME_LIST]',
190
-            '[PRIMARY_REGISTRANT_DATETIME_LIST]',
191
-            '[TICKET_LINE_ITEM_LIST]',
192
-            '[TAX_LINE_ITEM_LIST]',
193
-            '[ADDITIONAL_LINE_ITEM_LIST]',
194
-            '[PRICE_MODIFIER_LINE_ITEM_LIST]',
195
-            '[PAYMENT_LIST_*]',
196
-        );
197
-
198
-        $list_type_shortcodes = apply_filters(
199
-            'FHEE__EEH_Parse_Shortcodes___parse_message_template__list_type_shortcodes',
200
-            $list_type_shortcodes
201
-        );
202
-
203
-        // now lets go ahead and loop through our parsers for each shortcode and setup the values
204
-        foreach ($shortcodes as $shortcode) {
205
-            foreach ($this->_shortcode_objs as $sc_obj) {
206
-                if ($sc_obj instanceof EE_Shortcodes) {
207
-                    // we need to setup any dynamic shortcodes so that they work with the array_key_exists
208
-                    preg_match_all('/(\[[A-Za-z0-9\_]+_\*)/', $shortcode, $matches);
209
-                    $sc_to_verify = ! empty($matches[0]) ? $matches[0][0] . ']' : $shortcode;
210
-
211
-                    if (! array_key_exists($sc_to_verify, $sc_obj->get_shortcodes())) {
212
-                        continue; // the given shortcode isn't in this object
213
-                    }
214
-
215
-                    // if this isn't  a "list" type shortcode then we'll send along the data vanilla instead of in an array.
216
-                    if (! in_array($sc_to_verify, $list_type_shortcodes)) {
217
-                        $data_send = ! is_object($this->_data) && isset($this->_data['data']) ? $this->_data['data'] : $this->_data;
218
-                    } else {
219
-                        $data_send = $this->_data;
220
-                    }
221
-
222
-                    // is this a conditional type shortcode?  If it is then we actually parse the template here.
223
-                    if ($this->_is_conditional_shortcode($shortcode)) {
224
-                        // most shortcode parsers are not going to have a match for this shortcode and will return an
225
-                        // empty string so we need to make sure that we're only replacing the template when there is a non empty string.
226
-                        $parsed = $sc_obj->parser($shortcode, $data_send, $this->_data['extra_data']);
227
-                        if ($parsed) {
228
-                            $this->_template = $parsed;
229
-                        }
230
-                    }
231
-
232
-                    $parsed = $sc_obj->parser($shortcode, $data_send, $this->_data['extra_data']);
233
-
234
-                    $matched_code[] = $shortcode;
235
-                    $sc_values[]    = $parsed;
236
-                }
237
-            }
238
-        }
239
-
240
-        // now we've got parsed values for all the shortcodes in the template so we can go ahead and swap the shortcodes out.
241
-        return str_replace(array_values($matched_code), array_values($sc_values), $this->_template);
242
-    }
243
-
244
-
245
-    /**
246
-     * Simply returns whether the given shortcode matches the structure for a conditional shortcode.
247
-     *
248
-     * Does it match this format: `[IF_`
249
-     *
250
-     * @param $shortcode
251
-     */
252
-    protected function _is_conditional_shortcode($shortcode)
253
-    {
254
-        return strpos($shortcode, '[IF_') === 0;
255
-    }
256
-
257
-
258
-    /**
259
-     * This sets the shortcodes property from the incoming array of valid shortcodes that corresponds to names of
260
-     * various EE_Shortcode library objects
261
-     *
262
-     * @access private
263
-     * @param array $valid_shortcodes an array of strings corresponding to EE_Shortcode Library objects
264
-     * @return void
265
-     */
266
-    private function _set_shortcodes($valid_shortcodes)
267
-    {
268
-        foreach ($valid_shortcodes as $shortcode_ref) {
269
-            $ref       = ucwords(str_replace('_', ' ', $shortcode_ref));
270
-            $ref       = str_replace(' ', '_', $ref);
271
-            $classname = 'EE_' . $ref . '_Shortcodes';
272
-            if (class_exists($classname)) {
273
-                $this->_shortcode_objs[] = new $classname();
274
-            }
275
-        }
276
-    }
14
+	/**
15
+	 * holds the template
16
+	 *
17
+	 * @access private
18
+	 * @var mixed (string|array)
19
+	 */
20
+	private $_template;
21
+
22
+
23
+	/**
24
+	 * holds the incoming data object
25
+	 *
26
+	 * @access private
27
+	 * @var object
28
+	 */
29
+	private $_data;
30
+
31
+
32
+	/**
33
+	 * will hold an array of EE_Shortcodes library objects.
34
+	 *
35
+	 * @access private
36
+	 * @var EE_Shortcodes[]
37
+	 */
38
+	private $_shortcode_objs = array();
39
+
40
+
41
+	public function __construct()
42
+	{
43
+	}
44
+
45
+
46
+	/**
47
+	 * This kicks off the parsing of shortcodes in message templates
48
+	 *
49
+	 * @param  string                $template         This is the incoming string to be parsed
50
+	 * @param  EE_Messages_Addressee $data             This is the incoming data object
51
+	 * @param  array                 $valid_shortcodes An array of strings that correspond to EE_Shortcode libraries
52
+	 * @param EE_message_type        $message_type     The message type that called the parser
53
+	 * @param EE_messenger           $messenger        The active messenger for this parsing session.
54
+	 * @param EE_Message             $message
55
+	 * @return string                   The parsed template string
56
+	 */
57
+	public function parse_message_template(
58
+		$template,
59
+		EE_Messages_Addressee $data,
60
+		$valid_shortcodes,
61
+		EE_message_type $message_type,
62
+		EE_messenger $messenger,
63
+		EE_Message $message
64
+	) {
65
+		$extra_data = array(
66
+			'messenger'    => $messenger,
67
+			'message_type' => $message_type,
68
+			'message'      => $message,
69
+		);
70
+		$this->_init_data($template, $data, $valid_shortcodes, $extra_data);
71
+		$this->_template = is_array($template) ? $template['main'] : $template;
72
+		return $this->_parse_message_template();
73
+	}
74
+
75
+
76
+	public function parse_attendee_list_template(
77
+		$template,
78
+		EE_Registration $registration,
79
+		$valid_shortcodes,
80
+		$extra_data = array()
81
+	) {
82
+		$this->_init_data($template, $registration, $valid_shortcodes, $extra_data);
83
+		$this->_template = is_array($template) ? $template['attendee_list'] : $template;
84
+		return $this->_parse_message_template();
85
+	}
86
+
87
+	public function parse_event_list_template($template, EE_Event $event, $valid_shortcodes, $extra_data = array())
88
+	{
89
+		$this->_init_data($template, $event, $valid_shortcodes, $extra_data);
90
+		$this->_template = is_array($template) ? $template['event_list'] : $template;
91
+		return $this->_parse_message_template();
92
+	}
93
+
94
+
95
+	public function parse_ticket_list_template($template, EE_Ticket $ticket, $valid_shortcodes, $extra_data = array())
96
+	{
97
+		$this->_init_data($template, $ticket, $valid_shortcodes, $extra_data);
98
+		$this->_template = is_array($template) ? $template['ticket_list'] : $template;
99
+		return $this->_parse_message_template();
100
+	}
101
+
102
+
103
+	public function parse_line_item_list_template(
104
+		$template,
105
+		EE_Line_Item $line_item,
106
+		$valid_shortcodes,
107
+		$extra_data = array()
108
+	) {
109
+		$this->_init_data($template, $line_item, $valid_shortcodes, $extra_data);
110
+		$this->_template = is_array($template) ? $template['ticket_line_item_no_pms'] : $template;
111
+		return $this->_parse_message_template();
112
+	}
113
+
114
+
115
+	public function parse_payment_list_template(
116
+		$template,
117
+		EE_Payment $payment_item,
118
+		$valid_shortcodes,
119
+		$extra_data = array()
120
+	) {
121
+		$this->_init_data($template, $payment_item, $valid_shortcodes, $extra_data);
122
+		$this->_template = is_array($template) ? $template['payment_list'] : $template;
123
+		return $this->_parse_message_template();
124
+	}
125
+
126
+
127
+	public function parse_datetime_list_template(
128
+		$template,
129
+		EE_Datetime $datetime,
130
+		$valid_shortcodes,
131
+		$extra_data = array()
132
+	) {
133
+		$this->_init_data($template, $datetime, $valid_shortcodes, $extra_data);
134
+		$this->_template = is_array($template) ? $template['datetime_list'] : $template;
135
+		return $this->_parse_message_template();
136
+	}
137
+
138
+
139
+	public function parse_question_list_template($template, EE_Answer $answer, $valid_shortcodes, $extra_data = array())
140
+	{
141
+		$this->_init_data($template, $answer, $valid_shortcodes, $extra_data);
142
+		$this->_template = is_array($template) ? $template['question_list'] : $template;
143
+		return $this->_parse_message_template();
144
+	}
145
+
146
+
147
+	private function _init_data($template, $data, $valid_shortcodes, $extra_data = array())
148
+	{
149
+		$this->_reset_props();
150
+		$this->_data['template']   = $template;
151
+		$this->_data['data']       = $data;
152
+		$this->_data['extra_data'] = $extra_data;
153
+		$this->_set_shortcodes($valid_shortcodes);
154
+	}
155
+
156
+
157
+	private function _reset_props()
158
+	{
159
+		$this->_template       = $this->_data = null;
160
+		$this->_shortcode_objs = array();
161
+	}
162
+
163
+
164
+	/**
165
+	 * takes the given template and parses it with the $_shortcodes property
166
+	 *
167
+	 * @access private
168
+	 * @return string
169
+	 */
170
+	private function _parse_message_template()
171
+	{
172
+		// now let's get a list of shortcodes that are found in the given template
173
+		preg_match_all('/(\[.+?\])/', $this->_template, $matches);
174
+		$shortcodes = (array) $matches[0]; // this should be an array of shortcodes in the template string.
175
+
176
+		$matched_code = array();
177
+		$sc_values    = array();
178
+
179
+		$list_type_shortcodes = array(
180
+			'[ATTENDEE_LIST]',
181
+			'[EVENT_LIST]',
182
+			'[TICKET_LIST]',
183
+			'[DATETIME_LIST]',
184
+			'[QUESTION_LIST]',
185
+			'[RECIPIENT_QUESTION_LIST]',
186
+			'[PRIMARY_REGISTRANT_QUESTION_LIST]',
187
+			'[RECIPIENT_TICKET_LIST]',
188
+			'[PRIMARY_REGISTRANT_TICKET_LIST]',
189
+			'[RECIPIENT_DATETIME_LIST]',
190
+			'[PRIMARY_REGISTRANT_DATETIME_LIST]',
191
+			'[TICKET_LINE_ITEM_LIST]',
192
+			'[TAX_LINE_ITEM_LIST]',
193
+			'[ADDITIONAL_LINE_ITEM_LIST]',
194
+			'[PRICE_MODIFIER_LINE_ITEM_LIST]',
195
+			'[PAYMENT_LIST_*]',
196
+		);
197
+
198
+		$list_type_shortcodes = apply_filters(
199
+			'FHEE__EEH_Parse_Shortcodes___parse_message_template__list_type_shortcodes',
200
+			$list_type_shortcodes
201
+		);
202
+
203
+		// now lets go ahead and loop through our parsers for each shortcode and setup the values
204
+		foreach ($shortcodes as $shortcode) {
205
+			foreach ($this->_shortcode_objs as $sc_obj) {
206
+				if ($sc_obj instanceof EE_Shortcodes) {
207
+					// we need to setup any dynamic shortcodes so that they work with the array_key_exists
208
+					preg_match_all('/(\[[A-Za-z0-9\_]+_\*)/', $shortcode, $matches);
209
+					$sc_to_verify = ! empty($matches[0]) ? $matches[0][0] . ']' : $shortcode;
210
+
211
+					if (! array_key_exists($sc_to_verify, $sc_obj->get_shortcodes())) {
212
+						continue; // the given shortcode isn't in this object
213
+					}
214
+
215
+					// if this isn't  a "list" type shortcode then we'll send along the data vanilla instead of in an array.
216
+					if (! in_array($sc_to_verify, $list_type_shortcodes)) {
217
+						$data_send = ! is_object($this->_data) && isset($this->_data['data']) ? $this->_data['data'] : $this->_data;
218
+					} else {
219
+						$data_send = $this->_data;
220
+					}
221
+
222
+					// is this a conditional type shortcode?  If it is then we actually parse the template here.
223
+					if ($this->_is_conditional_shortcode($shortcode)) {
224
+						// most shortcode parsers are not going to have a match for this shortcode and will return an
225
+						// empty string so we need to make sure that we're only replacing the template when there is a non empty string.
226
+						$parsed = $sc_obj->parser($shortcode, $data_send, $this->_data['extra_data']);
227
+						if ($parsed) {
228
+							$this->_template = $parsed;
229
+						}
230
+					}
231
+
232
+					$parsed = $sc_obj->parser($shortcode, $data_send, $this->_data['extra_data']);
233
+
234
+					$matched_code[] = $shortcode;
235
+					$sc_values[]    = $parsed;
236
+				}
237
+			}
238
+		}
239
+
240
+		// now we've got parsed values for all the shortcodes in the template so we can go ahead and swap the shortcodes out.
241
+		return str_replace(array_values($matched_code), array_values($sc_values), $this->_template);
242
+	}
243
+
244
+
245
+	/**
246
+	 * Simply returns whether the given shortcode matches the structure for a conditional shortcode.
247
+	 *
248
+	 * Does it match this format: `[IF_`
249
+	 *
250
+	 * @param $shortcode
251
+	 */
252
+	protected function _is_conditional_shortcode($shortcode)
253
+	{
254
+		return strpos($shortcode, '[IF_') === 0;
255
+	}
256
+
257
+
258
+	/**
259
+	 * This sets the shortcodes property from the incoming array of valid shortcodes that corresponds to names of
260
+	 * various EE_Shortcode library objects
261
+	 *
262
+	 * @access private
263
+	 * @param array $valid_shortcodes an array of strings corresponding to EE_Shortcode Library objects
264
+	 * @return void
265
+	 */
266
+	private function _set_shortcodes($valid_shortcodes)
267
+	{
268
+		foreach ($valid_shortcodes as $shortcode_ref) {
269
+			$ref       = ucwords(str_replace('_', ' ', $shortcode_ref));
270
+			$ref       = str_replace(' ', '_', $ref);
271
+			$classname = 'EE_' . $ref . '_Shortcodes';
272
+			if (class_exists($classname)) {
273
+				$this->_shortcode_objs[] = new $classname();
274
+			}
275
+		}
276
+	}
277 277
 }
Please login to merge, or discard this patch.
core/helpers/EEH_Form_Fields.helper.php 2 patches
Indentation   +2058 added lines, -2058 removed lines patch added patch discarded remove patch
@@ -27,1056 +27,1056 @@  discard block
 block discarded – undo
27 27
  */
28 28
 class EEH_Form_Fields
29 29
 {
30
-    /**
31
-     *  Generates HTML for the forms used on admin pages
32
-     *
33
-     *
34
-     * @static
35
-     * @access public
36
-     * @param array $input_vars - array of input field details
37
-     *                          format:
38
-     *                          $template_form_fields['field-id'] = array(
39
-     *                          'name' => 'name_attribute',
40
-     *                          'label' => esc_html__('Field Label', 'event_espresso'), //or false
41
-     *                          'input' => 'hidden', //field input type can be 'text', 'select', 'textarea', 'hidden',
42
-     *                          'checkbox', 'wp_editor'
43
-     *                          'type' => 'int', //what "type" the value is (i.e. string, int etc)
44
-     *                          'required' => false, //boolean for whether the field is required
45
-     *                          'validation' => true, //boolean, whether to validate the field (todo)
46
-     *                          'value' => 'some_value_for_field', //what value is used for field
47
-     *                          'format' => '%d', //what format the value is (%d, %f, or %s)
48
-     *                          'db-col' => 'column_in_db' //used to indicate which column the field corresponds with
49
-     *                          in the db
50
-     *                          'options' => optiona, optionb || array('value' => 'label', '') //if the input type is
51
-     *                          "select", this allows you to set the args for the different <option> tags.
52
-     *                          'tabindex' => 1 //this allows you to set the tabindex for the field.
53
-     *                          'append_content' => '' //this allows you to send in html content to append to the
54
-     *                          field.
55
-     *                          )
56
-     * @param array $form_id    - used for defining unique identifiers for the form.
57
-     * @return string
58
-     * @todo   : at some point we can break this down into other static methods to abstract it a bit better.
59
-     */
60
-    public static function get_form_fields($input_vars = [], $form_id = false)
61
-    {
62
-
63
-        if (empty($input_vars)) {
64
-            EE_Error::add_error(
65
-                esc_html__('missing required variables for the form field generator', 'event_espresso'),
66
-                __FILE__,
67
-                __FUNCTION__,
68
-                __LINE__
69
-            );
70
-            return false;
71
-        }
72
-
73
-        $output        = "";
74
-        $inputs        = [];
75
-        $hidden_inputs = [];
76
-
77
-        // cycle thru inputs
78
-        foreach ($input_vars as $input_key => $input_value) {
79
-            $defaults = [
80
-                'append_content' => '',
81
-                'css_class'      => '',
82
-                'cols'           => 80,
83
-                'db-col'         => 'column_in_db',
84
-                'format'         => '%d',
85
-                'input'          => 'hidden',
86
-                'label'          => esc_html__('No label', 'event_espresso'),
87
-                'name'           => $input_key,
88
-                'options'        => [],
89
-                'required'       => false,
90
-                'tabindex'       => 0,
91
-                'rows'           => 10,
92
-                'type'           => 'int',
93
-                'validation'     => true,
94
-                'value'          => 'some_value_for_field',
95
-            ];
96
-
97
-            $input_value = wp_parse_args($input_value, $defaults);
98
-
99
-            $append_content = $input_value['append_content'];
100
-            $css_class      = $input_value['css_class'];
101
-            $cols           = $input_value['cols'];
102
-            $label          = $input_value['label'];
103
-            $name           = $input_value['name'];
104
-            $options        = $input_value['options'];
105
-            $required       = $input_value['required'];
106
-            $tab_index      = $input_value['tabindex'];
107
-            $rows           = $input_value['rows'];
108
-            $type           = $input_value['input'];
109
-            $value          = $input_value['value'];
110
-
111
-            $id    = $form_id ? $form_id . '-' . $input_key : $input_key;
112
-            $class = $required ? 'required ' . $css_class : $css_class;
113
-
114
-            // what type of input are we dealing with ?
115
-            switch ($type) {
116
-                case 'checkbox':
117
-                case 'radio':
118
-                    $field = self::adminMulti($value, $class, $id, $name, $required, $tab_index, $type, 1, $label);
119
-                    $field .= $append_content ?: '';
120
-                    break;
121
-
122
-                case 'hidden':
123
-                    $field           = null;
124
-                    $hidden_inputs[] = self::adminHidden($css_class, $id, $name, $value);
125
-                    break;
126
-
127
-                case 'select':
128
-                    $options = is_array($options) ? $options : explode(',', $options);
129
-                    $field   = self::adminLabel($id, $label, $required);
130
-                    $field   .= self::adminSelect($value, $class, $id, $name, $required, $tab_index, $options);
131
-                    $field   .= $append_content ?: '';
132
-                    break;
133
-
134
-                case 'textarea':
135
-                    $field = self::adminLabel($id, $label, $required);
136
-                    $field .= self::adminTextarea($class, $cols, $id, $name, $required, $rows, $tab_index, $value);
137
-                    $field .= $append_content ?: '';
138
-                    break;
139
-
140
-                case 'wp_editor':
141
-                    $label = esc_html($label);
142
-                    $field = "<h4>{$label}</h4>";
143
-                    $field .= $append_content ?: '';
144
-                    $field .= self::adminWpEditor(
145
-                        $class,
146
-                        $id,
147
-                        $name,
148
-                        $rows,
149
-                        $tab_index,
150
-                        $value
151
-                    );
152
-                    break;
153
-
154
-                default:
155
-                    $field = self::adminLabel($id, $label, $required);
156
-                    $field .= self::adminText($class, $id, $name, $required, $tab_index, $value);
157
-                    $field .= $append_content ?: '';
158
-            }
159
-            if ($field) {
160
-                $inputs[] = $field;
161
-            }
162
-        } // end foreach( $input_vars as $input_key => $input_value )
163
-
164
-        if (! empty($inputs)) {
165
-            $glue   = "
30
+	/**
31
+	 *  Generates HTML for the forms used on admin pages
32
+	 *
33
+	 *
34
+	 * @static
35
+	 * @access public
36
+	 * @param array $input_vars - array of input field details
37
+	 *                          format:
38
+	 *                          $template_form_fields['field-id'] = array(
39
+	 *                          'name' => 'name_attribute',
40
+	 *                          'label' => esc_html__('Field Label', 'event_espresso'), //or false
41
+	 *                          'input' => 'hidden', //field input type can be 'text', 'select', 'textarea', 'hidden',
42
+	 *                          'checkbox', 'wp_editor'
43
+	 *                          'type' => 'int', //what "type" the value is (i.e. string, int etc)
44
+	 *                          'required' => false, //boolean for whether the field is required
45
+	 *                          'validation' => true, //boolean, whether to validate the field (todo)
46
+	 *                          'value' => 'some_value_for_field', //what value is used for field
47
+	 *                          'format' => '%d', //what format the value is (%d, %f, or %s)
48
+	 *                          'db-col' => 'column_in_db' //used to indicate which column the field corresponds with
49
+	 *                          in the db
50
+	 *                          'options' => optiona, optionb || array('value' => 'label', '') //if the input type is
51
+	 *                          "select", this allows you to set the args for the different <option> tags.
52
+	 *                          'tabindex' => 1 //this allows you to set the tabindex for the field.
53
+	 *                          'append_content' => '' //this allows you to send in html content to append to the
54
+	 *                          field.
55
+	 *                          )
56
+	 * @param array $form_id    - used for defining unique identifiers for the form.
57
+	 * @return string
58
+	 * @todo   : at some point we can break this down into other static methods to abstract it a bit better.
59
+	 */
60
+	public static function get_form_fields($input_vars = [], $form_id = false)
61
+	{
62
+
63
+		if (empty($input_vars)) {
64
+			EE_Error::add_error(
65
+				esc_html__('missing required variables for the form field generator', 'event_espresso'),
66
+				__FILE__,
67
+				__FUNCTION__,
68
+				__LINE__
69
+			);
70
+			return false;
71
+		}
72
+
73
+		$output        = "";
74
+		$inputs        = [];
75
+		$hidden_inputs = [];
76
+
77
+		// cycle thru inputs
78
+		foreach ($input_vars as $input_key => $input_value) {
79
+			$defaults = [
80
+				'append_content' => '',
81
+				'css_class'      => '',
82
+				'cols'           => 80,
83
+				'db-col'         => 'column_in_db',
84
+				'format'         => '%d',
85
+				'input'          => 'hidden',
86
+				'label'          => esc_html__('No label', 'event_espresso'),
87
+				'name'           => $input_key,
88
+				'options'        => [],
89
+				'required'       => false,
90
+				'tabindex'       => 0,
91
+				'rows'           => 10,
92
+				'type'           => 'int',
93
+				'validation'     => true,
94
+				'value'          => 'some_value_for_field',
95
+			];
96
+
97
+			$input_value = wp_parse_args($input_value, $defaults);
98
+
99
+			$append_content = $input_value['append_content'];
100
+			$css_class      = $input_value['css_class'];
101
+			$cols           = $input_value['cols'];
102
+			$label          = $input_value['label'];
103
+			$name           = $input_value['name'];
104
+			$options        = $input_value['options'];
105
+			$required       = $input_value['required'];
106
+			$tab_index      = $input_value['tabindex'];
107
+			$rows           = $input_value['rows'];
108
+			$type           = $input_value['input'];
109
+			$value          = $input_value['value'];
110
+
111
+			$id    = $form_id ? $form_id . '-' . $input_key : $input_key;
112
+			$class = $required ? 'required ' . $css_class : $css_class;
113
+
114
+			// what type of input are we dealing with ?
115
+			switch ($type) {
116
+				case 'checkbox':
117
+				case 'radio':
118
+					$field = self::adminMulti($value, $class, $id, $name, $required, $tab_index, $type, 1, $label);
119
+					$field .= $append_content ?: '';
120
+					break;
121
+
122
+				case 'hidden':
123
+					$field           = null;
124
+					$hidden_inputs[] = self::adminHidden($css_class, $id, $name, $value);
125
+					break;
126
+
127
+				case 'select':
128
+					$options = is_array($options) ? $options : explode(',', $options);
129
+					$field   = self::adminLabel($id, $label, $required);
130
+					$field   .= self::adminSelect($value, $class, $id, $name, $required, $tab_index, $options);
131
+					$field   .= $append_content ?: '';
132
+					break;
133
+
134
+				case 'textarea':
135
+					$field = self::adminLabel($id, $label, $required);
136
+					$field .= self::adminTextarea($class, $cols, $id, $name, $required, $rows, $tab_index, $value);
137
+					$field .= $append_content ?: '';
138
+					break;
139
+
140
+				case 'wp_editor':
141
+					$label = esc_html($label);
142
+					$field = "<h4>{$label}</h4>";
143
+					$field .= $append_content ?: '';
144
+					$field .= self::adminWpEditor(
145
+						$class,
146
+						$id,
147
+						$name,
148
+						$rows,
149
+						$tab_index,
150
+						$value
151
+					);
152
+					break;
153
+
154
+				default:
155
+					$field = self::adminLabel($id, $label, $required);
156
+					$field .= self::adminText($class, $id, $name, $required, $tab_index, $value);
157
+					$field .= $append_content ?: '';
158
+			}
159
+			if ($field) {
160
+				$inputs[] = $field;
161
+			}
162
+		} // end foreach( $input_vars as $input_key => $input_value )
163
+
164
+		if (! empty($inputs)) {
165
+			$glue   = "
166 166
                 </li>
167 167
                 <li>
168 168
                     ";
169
-            $inputs = implode($glue, $inputs);
170
-            $output = "
169
+			$inputs = implode($glue, $inputs);
170
+			$output = "
171 171
             <ul>
172 172
                 <li>
173 173
                 {$inputs}
174 174
                 </li>
175 175
             </ul>
176 176
             ";
177
-        }
178
-        return $output . implode("\n", $hidden_inputs);
179
-    }
180
-
181
-
182
-    /**
183
-     * form_fields_array
184
-     * This utility function assembles form fields from a given structured array with field information.
185
-     * //TODO: This is an alternate generator that we may want to use instead.
186
-     *
187
-     * @param array $fields structured array of fields to assemble in the following format:
188
-     *                      [field_name] => array(
189
-     *                      ['label'] => 'label for field',
190
-     *                      ['labels'] => array('label_1', 'label_2'); //optional - if the field type is a multi select
191
-     *                      type of field you can indicated the labels for each option via this index
192
-     *                      ['extra_desc'] => 'extra description for the field', //optional
193
-     *                      ['type'] => 'textarea'|'text'|'wp_editor'|'checkbox'|'radio'|'hidden'|'select', //defaults
194
-     *                      to text
195
-     *                      ['value'] => 'value that goes in the field', //(if multi then this is an array of values
196
-     *                      and the 'default' paramater will be used for what is selected)
197
-     *                      ['default'] => 'default if the field type is multi (i.e. select or radios or checkboxes)',
198
-     *                      ['class'] => 'name-of-class(es)-for-input',
199
-     *                      ['classes'] => array('class_1', 'class_2'); //optional - if the field type is a multi
200
-     *                      select type of field you can indicate the css class for each option via this index.
201
-     *                      ['id'] => 'css-id-for-input') //defaults to 'field_name'
202
-     *                      ['unique_id'] => 1 //defaults to empty string.  This is useful for when the fields
203
-     *                      generated are going to be used in a loop and you want to make sure that the field
204
-     *                      identifiers are unique from each other.
205
-     *                      ['dimensions'] => array(100,300), //defaults to empty array.  This is used by field types
206
-     *                      such as textarea to indicate cols/rows.
207
-     *                      ['tabindex'] => '' //this allows you to set the tabindex for the field.
208
-     *                      ['wpeditor_args'] => array() //if the type of field is wpeditor then this can optionally
209
-     *                      contain an array of arguments for the editor setup.
210
-     *
211
-     * @return array         an array of inputs for form indexed by field name, and in the following structure:
212
-     *     [field_name] => array( 'label' => '{label_html}', 'field' => '{input_html}'
213
-     */
214
-    public static function get_form_fields_array($fields)
215
-    {
216
-
217
-        $form_fields = [];
218
-        $fields      = (array) $fields;
219
-
220
-        foreach ($fields as $field_name => $field_atts) {
221
-            // defaults:
222
-            $defaults = [
223
-                'class'         => '',
224
-                'classes'       => '',
225
-                'default'       => '',
226
-                'dimensions'    => ['10', '5'],
227
-                'extra_desc'    => '',
228
-                'id'            => $field_name,
229
-                'label'         => '',
230
-                'labels'        => '',
231
-                'required'      => false,
232
-                'tabindex'      => 0,
233
-                'type'          => 'text',
234
-                'unique_id'     => '',
235
-                'value'         => '',
236
-                'wpeditor_args' => [],
237
-            ];
238
-            // merge defaults with passed arguments
239
-            $_fields = wp_parse_args($field_atts, $defaults);
240
-
241
-            $class          = $_fields['class'];
242
-            $classes        = $_fields['classes'];
243
-            $default        = $_fields['default'];
244
-            $dims           = $_fields['dimensions'];
245
-            $extra_desc     = $_fields['extra_desc'];
246
-            $id             = $_fields['id'];
247
-            $label          = $_fields['label'];
248
-            $labels         = $_fields['labels'];
249
-            $required       = $_fields['required'];
250
-            $tab_index      = $_fields['tabindex'];
251
-            $type           = $_fields['type'];
252
-            $unique_id      = $_fields['unique_id'];
253
-            $value          = $_fields['value'];
254
-            $wp_editor_args = $_fields['wpeditor_args'];
255
-
256
-            // generate label
257
-            $label = ! empty($label) ? self::adminLabel($id, $label, $required) : '';
258
-            // generate field name
259
-            $name = ! empty($unique_id) ? $field_name . '[' . $unique_id . ']' : $field_name;
260
-
261
-            // we determine what we're building based on the type
262
-            switch ($type) {
263
-                case 'checkbox':
264
-                case 'radio':
265
-                    if (is_array($value)) {
266
-                        $c_input = '';
267
-                        foreach ($value as $key => $val) {
268
-                            $c_input .= self::adminMulti(
269
-                                $default,
270
-                                isset($classes[ $key ]) ? $classes[ $key ] : '',
271
-                                $field_name . '_' . $value,
272
-                                $name,
273
-                                $required,
274
-                                $tab_index,
275
-                                $type,
276
-                                $val,
277
-                                isset($labels[ $key ]) ? $labels[ $key ] : ''
278
-                            );
279
-                        }
280
-                        $field = $c_input;
281
-                    } else {
282
-                        $field = self::adminMulti(
283
-                            $default,
284
-                            $class,
285
-                            $id,
286
-                            $name,
287
-                            $required,
288
-                            $tab_index,
289
-                            $type,
290
-                            $value,
291
-                            $_fields['label']
292
-                        );
293
-                    }
294
-                    break;
295
-
296
-                case 'hidden':
297
-                    $field = self::adminHidden($class, $id, $name, $value);
298
-                    break;
299
-
300
-                case 'select':
301
-                    $options = [];
302
-                    foreach ($value as $key => $val) {
303
-                        $options[ $val ] = isset($labels[ $key ]) ? $labels[ $key ] : '';
304
-                    }
305
-                    $field = self::adminSelect($default, $class, $id, $name, $required, $tab_index, $options);
306
-                    break;
307
-
308
-                case 'textarea':
309
-                    $field =
310
-                        self::adminTextarea($class, $dims[0], $id, $name, $required, $dims[1], $tab_index, $value);
311
-                    break;
312
-
313
-                case 'wp_editor':
314
-                    $field = self::adminWpEditor(
315
-                        $class,
316
-                        $_fields['id'],
317
-                        $name,
318
-                        $dims[1],
319
-                        $tab_index,
320
-                        $value,
321
-                        $wp_editor_args
322
-                    );
323
-                    break;
324
-
325
-                default:
326
-                    $field = self::adminText($class, $id, $name, $required, $tab_index, $value);
327
-            }
328
-
329
-            $form_fields[ $field_name ] = ['label' => $label, 'field' => $field . $extra_desc];
330
-        }
331
-
332
-        return $form_fields;
333
-    }
334
-
335
-
336
-    /**
337
-     * @param string $class
338
-     * @param string $id
339
-     * @param string $name
340
-     * @param string $value
341
-     * @return string
342
-     * @since   4.10.14.p
343
-     */
344
-    private static function adminHidden($class, $id, $name, $value)
345
-    {
346
-        $id    = esc_attr($id);
347
-        $name  = esc_attr($name);
348
-        $class = esc_attr($class);
349
-        return "
177
+		}
178
+		return $output . implode("\n", $hidden_inputs);
179
+	}
180
+
181
+
182
+	/**
183
+	 * form_fields_array
184
+	 * This utility function assembles form fields from a given structured array with field information.
185
+	 * //TODO: This is an alternate generator that we may want to use instead.
186
+	 *
187
+	 * @param array $fields structured array of fields to assemble in the following format:
188
+	 *                      [field_name] => array(
189
+	 *                      ['label'] => 'label for field',
190
+	 *                      ['labels'] => array('label_1', 'label_2'); //optional - if the field type is a multi select
191
+	 *                      type of field you can indicated the labels for each option via this index
192
+	 *                      ['extra_desc'] => 'extra description for the field', //optional
193
+	 *                      ['type'] => 'textarea'|'text'|'wp_editor'|'checkbox'|'radio'|'hidden'|'select', //defaults
194
+	 *                      to text
195
+	 *                      ['value'] => 'value that goes in the field', //(if multi then this is an array of values
196
+	 *                      and the 'default' paramater will be used for what is selected)
197
+	 *                      ['default'] => 'default if the field type is multi (i.e. select or radios or checkboxes)',
198
+	 *                      ['class'] => 'name-of-class(es)-for-input',
199
+	 *                      ['classes'] => array('class_1', 'class_2'); //optional - if the field type is a multi
200
+	 *                      select type of field you can indicate the css class for each option via this index.
201
+	 *                      ['id'] => 'css-id-for-input') //defaults to 'field_name'
202
+	 *                      ['unique_id'] => 1 //defaults to empty string.  This is useful for when the fields
203
+	 *                      generated are going to be used in a loop and you want to make sure that the field
204
+	 *                      identifiers are unique from each other.
205
+	 *                      ['dimensions'] => array(100,300), //defaults to empty array.  This is used by field types
206
+	 *                      such as textarea to indicate cols/rows.
207
+	 *                      ['tabindex'] => '' //this allows you to set the tabindex for the field.
208
+	 *                      ['wpeditor_args'] => array() //if the type of field is wpeditor then this can optionally
209
+	 *                      contain an array of arguments for the editor setup.
210
+	 *
211
+	 * @return array         an array of inputs for form indexed by field name, and in the following structure:
212
+	 *     [field_name] => array( 'label' => '{label_html}', 'field' => '{input_html}'
213
+	 */
214
+	public static function get_form_fields_array($fields)
215
+	{
216
+
217
+		$form_fields = [];
218
+		$fields      = (array) $fields;
219
+
220
+		foreach ($fields as $field_name => $field_atts) {
221
+			// defaults:
222
+			$defaults = [
223
+				'class'         => '',
224
+				'classes'       => '',
225
+				'default'       => '',
226
+				'dimensions'    => ['10', '5'],
227
+				'extra_desc'    => '',
228
+				'id'            => $field_name,
229
+				'label'         => '',
230
+				'labels'        => '',
231
+				'required'      => false,
232
+				'tabindex'      => 0,
233
+				'type'          => 'text',
234
+				'unique_id'     => '',
235
+				'value'         => '',
236
+				'wpeditor_args' => [],
237
+			];
238
+			// merge defaults with passed arguments
239
+			$_fields = wp_parse_args($field_atts, $defaults);
240
+
241
+			$class          = $_fields['class'];
242
+			$classes        = $_fields['classes'];
243
+			$default        = $_fields['default'];
244
+			$dims           = $_fields['dimensions'];
245
+			$extra_desc     = $_fields['extra_desc'];
246
+			$id             = $_fields['id'];
247
+			$label          = $_fields['label'];
248
+			$labels         = $_fields['labels'];
249
+			$required       = $_fields['required'];
250
+			$tab_index      = $_fields['tabindex'];
251
+			$type           = $_fields['type'];
252
+			$unique_id      = $_fields['unique_id'];
253
+			$value          = $_fields['value'];
254
+			$wp_editor_args = $_fields['wpeditor_args'];
255
+
256
+			// generate label
257
+			$label = ! empty($label) ? self::adminLabel($id, $label, $required) : '';
258
+			// generate field name
259
+			$name = ! empty($unique_id) ? $field_name . '[' . $unique_id . ']' : $field_name;
260
+
261
+			// we determine what we're building based on the type
262
+			switch ($type) {
263
+				case 'checkbox':
264
+				case 'radio':
265
+					if (is_array($value)) {
266
+						$c_input = '';
267
+						foreach ($value as $key => $val) {
268
+							$c_input .= self::adminMulti(
269
+								$default,
270
+								isset($classes[ $key ]) ? $classes[ $key ] : '',
271
+								$field_name . '_' . $value,
272
+								$name,
273
+								$required,
274
+								$tab_index,
275
+								$type,
276
+								$val,
277
+								isset($labels[ $key ]) ? $labels[ $key ] : ''
278
+							);
279
+						}
280
+						$field = $c_input;
281
+					} else {
282
+						$field = self::adminMulti(
283
+							$default,
284
+							$class,
285
+							$id,
286
+							$name,
287
+							$required,
288
+							$tab_index,
289
+							$type,
290
+							$value,
291
+							$_fields['label']
292
+						);
293
+					}
294
+					break;
295
+
296
+				case 'hidden':
297
+					$field = self::adminHidden($class, $id, $name, $value);
298
+					break;
299
+
300
+				case 'select':
301
+					$options = [];
302
+					foreach ($value as $key => $val) {
303
+						$options[ $val ] = isset($labels[ $key ]) ? $labels[ $key ] : '';
304
+					}
305
+					$field = self::adminSelect($default, $class, $id, $name, $required, $tab_index, $options);
306
+					break;
307
+
308
+				case 'textarea':
309
+					$field =
310
+						self::adminTextarea($class, $dims[0], $id, $name, $required, $dims[1], $tab_index, $value);
311
+					break;
312
+
313
+				case 'wp_editor':
314
+					$field = self::adminWpEditor(
315
+						$class,
316
+						$_fields['id'],
317
+						$name,
318
+						$dims[1],
319
+						$tab_index,
320
+						$value,
321
+						$wp_editor_args
322
+					);
323
+					break;
324
+
325
+				default:
326
+					$field = self::adminText($class, $id, $name, $required, $tab_index, $value);
327
+			}
328
+
329
+			$form_fields[ $field_name ] = ['label' => $label, 'field' => $field . $extra_desc];
330
+		}
331
+
332
+		return $form_fields;
333
+	}
334
+
335
+
336
+	/**
337
+	 * @param string $class
338
+	 * @param string $id
339
+	 * @param string $name
340
+	 * @param string $value
341
+	 * @return string
342
+	 * @since   4.10.14.p
343
+	 */
344
+	private static function adminHidden($class, $id, $name, $value)
345
+	{
346
+		$id    = esc_attr($id);
347
+		$name  = esc_attr($name);
348
+		$class = esc_attr($class);
349
+		return "
350 350
         <input name='{$name}' type='hidden' id='{$id}' class='{$class}' value='{$value}' />";
351
-    }
352
-
353
-
354
-    /**
355
-     * @param string $id
356
-     * @param string $label
357
-     * @param string $required
358
-     * @return string
359
-     * @since   4.10.14.p
360
-     */
361
-    private static function adminLabel($id, $label, $required)
362
-    {
363
-        $id       = esc_attr($id);
364
-        $label    = esc_html($label);
365
-        $required = filter_var($required, FILTER_VALIDATE_BOOLEAN) ? " <span>*</span>" : '';
366
-        return "<label for='{$id}'>{$label}{$required}</label>";
367
-    }
368
-
369
-
370
-    /**
371
-     * @param string $default
372
-     * @param string $class
373
-     * @param string $id
374
-     * @param string $name
375
-     * @param string $required
376
-     * @param int    $tab_index
377
-     * @param string $type
378
-     * @param string $value
379
-     * @param string $label
380
-     * @return string
381
-     * @since   4.10.14.p
382
-     */
383
-    private static function adminMulti($default, $class, $id, $name, $required, $tab_index, $type, $value, $label = '')
384
-    {
385
-        $id        = esc_attr($id);
386
-        $name      = esc_attr($name);
387
-        $class     = esc_attr($class);
388
-        $tab_index = absint($tab_index);
389
-        $checked   = ! empty($default) && $default == $value ? 'checked ' : '';
390
-        $required  = filter_var($required, FILTER_VALIDATE_BOOLEAN) ? 'required' : '';
391
-        $input     = "
351
+	}
352
+
353
+
354
+	/**
355
+	 * @param string $id
356
+	 * @param string $label
357
+	 * @param string $required
358
+	 * @return string
359
+	 * @since   4.10.14.p
360
+	 */
361
+	private static function adminLabel($id, $label, $required)
362
+	{
363
+		$id       = esc_attr($id);
364
+		$label    = esc_html($label);
365
+		$required = filter_var($required, FILTER_VALIDATE_BOOLEAN) ? " <span>*</span>" : '';
366
+		return "<label for='{$id}'>{$label}{$required}</label>";
367
+	}
368
+
369
+
370
+	/**
371
+	 * @param string $default
372
+	 * @param string $class
373
+	 * @param string $id
374
+	 * @param string $name
375
+	 * @param string $required
376
+	 * @param int    $tab_index
377
+	 * @param string $type
378
+	 * @param string $value
379
+	 * @param string $label
380
+	 * @return string
381
+	 * @since   4.10.14.p
382
+	 */
383
+	private static function adminMulti($default, $class, $id, $name, $required, $tab_index, $type, $value, $label = '')
384
+	{
385
+		$id        = esc_attr($id);
386
+		$name      = esc_attr($name);
387
+		$class     = esc_attr($class);
388
+		$tab_index = absint($tab_index);
389
+		$checked   = ! empty($default) && $default == $value ? 'checked ' : '';
390
+		$required  = filter_var($required, FILTER_VALIDATE_BOOLEAN) ? 'required' : '';
391
+		$input     = "
392 392
         <input name='{$name}[]' type='{$type}' id='{$id}' class='{$class}' value='{$value}' {$checked} {$required} tabindex='{$tab_index}'/>";
393
-        if ($label === '') {
394
-            return $input;
395
-        }
396
-        $label = esc_html($label);
397
-        $label_class = self::appendInputSizeClass('', $label);
398
-        $label_class = $label_class ? ' class="' . $label_class . '"' : '';
399
-        return "
393
+		if ($label === '') {
394
+			return $input;
395
+		}
396
+		$label = esc_html($label);
397
+		$label_class = self::appendInputSizeClass('', $label);
398
+		$label_class = $label_class ? ' class="' . $label_class . '"' : '';
399
+		return "
400 400
         <label for='$id'{$label_class}>
401 401
             {$input}
402 402
             {$label}
403 403
         </label>";
404
-    }
405
-
406
-
407
-    /**
408
-     * @param string $default
409
-     * @param string $class
410
-     * @param string $id
411
-     * @param string $name
412
-     * @param string $required
413
-     * @param int    $tab_index
414
-     * @param array  $options
415
-     * @return string
416
-     * @since   4.10.14.p
417
-     */
418
-    private static function adminSelect($default, $class, $id, $name, $required, $tab_index, $options = [])
419
-    {
420
-        $options_array = [];
421
-        foreach ($options as $value => $label) {
422
-            $selected        = ! empty($default) && $default == $value ? 'selected' : '';
423
-            $value           = esc_attr($value);
424
-            $label           = wp_strip_all_tags($label);
425
-            $options_array[] = "<option value='{$value}' {$selected}>{$label}</option>";
426
-        }
427
-        $options_html = implode("\n", $options_array);
428
-        $id           = esc_attr($id);
429
-        $name         = esc_attr($name);
430
-        $class        = esc_attr($class);
431
-        $tab_index    = absint($tab_index);
432
-        $required     = filter_var($required, FILTER_VALIDATE_BOOLEAN) ? 'required' : '';
433
-
434
-        $class = self::appendInputSizeClass($class, $options);
435
-
436
-        return "
404
+	}
405
+
406
+
407
+	/**
408
+	 * @param string $default
409
+	 * @param string $class
410
+	 * @param string $id
411
+	 * @param string $name
412
+	 * @param string $required
413
+	 * @param int    $tab_index
414
+	 * @param array  $options
415
+	 * @return string
416
+	 * @since   4.10.14.p
417
+	 */
418
+	private static function adminSelect($default, $class, $id, $name, $required, $tab_index, $options = [])
419
+	{
420
+		$options_array = [];
421
+		foreach ($options as $value => $label) {
422
+			$selected        = ! empty($default) && $default == $value ? 'selected' : '';
423
+			$value           = esc_attr($value);
424
+			$label           = wp_strip_all_tags($label);
425
+			$options_array[] = "<option value='{$value}' {$selected}>{$label}</option>";
426
+		}
427
+		$options_html = implode("\n", $options_array);
428
+		$id           = esc_attr($id);
429
+		$name         = esc_attr($name);
430
+		$class        = esc_attr($class);
431
+		$tab_index    = absint($tab_index);
432
+		$required     = filter_var($required, FILTER_VALIDATE_BOOLEAN) ? 'required' : '';
433
+
434
+		$class = self::appendInputSizeClass($class, $options);
435
+
436
+		return "
437 437
         <select name='{$name}' id='{$id}' class='{$class}' {$required} tabindex='{$tab_index}'>
438 438
             {$options_html}
439 439
         </select>";
440
-    }
441
-
442
-
443
-    /**
444
-     * @param string $class
445
-     * @param string $id
446
-     * @param string $name
447
-     * @param string $required
448
-     * @param int    $tab_index
449
-     * @param string $value
450
-     * @return string
451
-     * @since   4.10.14.p
452
-     */
453
-    private static function adminText($class, $id, $name, $required, $tab_index, $value)
454
-    {
455
-        $id        = esc_attr($id);
456
-        $name      = esc_attr($name);
457
-        $class     = esc_attr($class);
458
-        $tab_index = absint($tab_index);
459
-        $required  = filter_var($required, FILTER_VALIDATE_BOOLEAN) ? 'required' : '';
460
-        $class     = self::appendInputSizeClass($class, $value);
461
-        $value     = esc_attr($value);
462
-        return "
440
+	}
441
+
442
+
443
+	/**
444
+	 * @param string $class
445
+	 * @param string $id
446
+	 * @param string $name
447
+	 * @param string $required
448
+	 * @param int    $tab_index
449
+	 * @param string $value
450
+	 * @return string
451
+	 * @since   4.10.14.p
452
+	 */
453
+	private static function adminText($class, $id, $name, $required, $tab_index, $value)
454
+	{
455
+		$id        = esc_attr($id);
456
+		$name      = esc_attr($name);
457
+		$class     = esc_attr($class);
458
+		$tab_index = absint($tab_index);
459
+		$required  = filter_var($required, FILTER_VALIDATE_BOOLEAN) ? 'required' : '';
460
+		$class     = self::appendInputSizeClass($class, $value);
461
+		$value     = esc_attr($value);
462
+		return "
463 463
         <input name='{$name}' type='text' id='{$id}' class='{$class}' value='{$value}' {$required} tabindex='{$tab_index}'/>";
464
-    }
465
-
466
-
467
-    /**
468
-     * @param string $class
469
-     * @param int    $cols
470
-     * @param string $id
471
-     * @param string $name
472
-     * @param string $required
473
-     * @param int    $rows
474
-     * @param int    $tab_index
475
-     * @param string $value
476
-     * @return string
477
-     * @since   4.10.14.p
478
-     */
479
-    private static function adminTextarea($class, $cols, $id, $name, $required, $rows, $tab_index, $value)
480
-    {
481
-        $id        = esc_attr($id);
482
-        $name      = esc_attr($name);
483
-        $class     = esc_attr($class);
484
-        $cols      = absint($cols);
485
-        $rows      = absint($rows);
486
-        $value     = esc_textarea($value);
487
-        $tab_index = absint($tab_index);
488
-        $required  = filter_var($required, FILTER_VALIDATE_BOOLEAN) ? 'required' : '';
489
-        return "
464
+	}
465
+
466
+
467
+	/**
468
+	 * @param string $class
469
+	 * @param int    $cols
470
+	 * @param string $id
471
+	 * @param string $name
472
+	 * @param string $required
473
+	 * @param int    $rows
474
+	 * @param int    $tab_index
475
+	 * @param string $value
476
+	 * @return string
477
+	 * @since   4.10.14.p
478
+	 */
479
+	private static function adminTextarea($class, $cols, $id, $name, $required, $rows, $tab_index, $value)
480
+	{
481
+		$id        = esc_attr($id);
482
+		$name      = esc_attr($name);
483
+		$class     = esc_attr($class);
484
+		$cols      = absint($cols);
485
+		$rows      = absint($rows);
486
+		$value     = esc_textarea($value);
487
+		$tab_index = absint($tab_index);
488
+		$required  = filter_var($required, FILTER_VALIDATE_BOOLEAN) ? 'required' : '';
489
+		return "
490 490
         <textarea name='{$name}' id='{$id}' class='{$class}' rows='{$rows}' cols='{$cols}' {$required} tabindex='{$tab_index}'>{$value}</textarea>";
491
-    }
492
-
493
-
494
-    /**
495
-     * @param string $class
496
-     * @param string $id
497
-     * @param string $name
498
-     * @param int    $rows
499
-     * @param int    $tab_index
500
-     * @param string $value
501
-     * @param array  $wp_editor_args
502
-     * @return false|string
503
-     * @since   4.10.14.p
504
-     */
505
-    private static function adminWpEditor($class, $id, $name, $rows, $tab_index, $value, $wp_editor_args = [])
506
-    {
507
-        $editor_settings = $wp_editor_args + [
508
-                'textarea_name' => esc_attr($name),
509
-                'textarea_rows' => absint($rows),
510
-                'editor_class'  => esc_attr($class),
511
-                'tabindex'      => absint($tab_index),
512
-            ];
513
-        ob_start();
514
-        wp_editor($value, esc_attr($id), $editor_settings);
515
-        return ob_get_clean();
516
-    }
517
-
518
-
519
-    /**
520
-     * espresso admin page select_input
521
-     * Turns an array into a select fields
522
-     *
523
-     * @static
524
-     * @access public
525
-     * @param string  $name       field name
526
-     * @param array   $values     option values, numbered array starting at 0, where each value is an array with a key
527
-     *                            'text' (meaning text to display' and 'id' (meaning the internal value) eg:
528
-     *                            array(1=>array('text'=>'Monday','id'=>1),2=>array('text'=>'Tuesday','id'=>2)...). or
529
-     *                            as an array of key-value pairs, where the key is to be used for the select input's
530
-     *                            name, and the value will be the text shown to the user.  Optionally you can also
531
-     *                            include an additional key of "class" which will add a specific class to the option
532
-     *                            for that value.
533
-     * @param string  $default    default value
534
-     * @param string  $parameters extra parameters
535
-     * @param string  $class      css class
536
-     * @param boolean $autosize   whether to autosize the select or not
537
-     * @return string              html string for the select input
538
-     */
539
-    public static function select_input(
540
-        $name,
541
-        $values,
542
-        $default = '',
543
-        $parameters = '',
544
-        $class = '',
545
-        $autosize = true
546
-    ) {
547
-        // if $values was submitted in the wrong format, convert it over
548
-        if (! empty($values) && (! array_key_exists(0, $values) || ! is_array($values[0]))) {
549
-            $converted_values = [];
550
-            foreach ($values as $id => $text) {
551
-                $converted_values[] = ['id' => $id, 'text' => $text];
552
-            }
553
-            $values = $converted_values;
554
-        }
555
-
556
-        $field =
557
-            '<select id="' . EEH_Formatter::ee_tep_output_string($name)
558
-            . '" name="' . EEH_Formatter::ee_tep_output_string($name)
559
-            . '"';
560
-
561
-        if (EEH_Formatter::ee_tep_not_null($parameters)) {
562
-            $field .= ' ' . $parameters;
563
-        }
564
-        $class = $autosize ? self::appendInputSizeClass($class, $values) : '';
565
-
566
-        $field .= ' class="' . $class . '">';
567
-
568
-        if (empty($default) && isset($GLOBALS[ $name ])) {
569
-            $default = stripslashes($GLOBALS[ $name ]);
570
-        }
571
-
572
-        $field .= self::selectInputOption($values, $default);
573
-        $field .= '</select>';
574
-
575
-        return $field;
576
-    }
577
-
578
-
579
-    private static function selectInputOption(array $values, $default): string
580
-    {
581
-        if (isset($values['id'], $values['text'])) {
582
-            $id = is_scalar($values['id']) ? $values['id'] : '';
583
-            $text = is_scalar($values['text']) ? $values['text'] : '';
584
-            $selected = $default == $values['id'] ? ' selected = "selected"' : '';
585
-            $html_class = isset($values['class']) ? ' class="' . $values['class'] . '"' : '';
586
-            return "<option value='{$id}'{$selected}{$html_class}>{$text}</option>";
587
-        }
588
-        $options = '';
589
-        foreach ($values as $value) {
590
-            $options .= self::selectInputOption($value, $default);
591
-        }
592
-        return $options;
593
-    }
594
-
595
-
596
-    /**
597
-     * @param mixed $value
598
-     * @return int
599
-     * @since   5.0.0.p
600
-     */
601
-    private static function getInputValueLength($value): int
602
-    {
603
-        if ($value instanceof EE_Question_Option) {
604
-            return self::getInputValueLength($value->desc());
605
-        }
606
-        if (is_array($value)) {
607
-            $chars = 0;
608
-            foreach ($value as $val) {
609
-                $length = self::getInputValueLength($val);
610
-                $chars = max($length, $chars);
611
-            }
612
-            return $chars;
613
-        }
614
-        // not a primitive? return something big
615
-        if (! is_scalar($value)) {
616
-            return 500;
617
-        }
618
-        return strlen((string) $value);
619
-    }
620
-
621
-
622
-    /**
623
-     * @param string $class
624
-     * @param mixed $value
625
-     * @return string
626
-     * @since   5.0.0.p
627
-     */
628
-    private static function appendInputSizeClass(string $class, $value): string
629
-    {
630
-        if (strpos($class, 'ee-input-width--') !== false) {
631
-            return $class;
632
-        }
633
-        $chars = self::getInputValueLength($value);
634
-        if ($chars && $chars < 5) {
635
-            return "{$class} ee-input-width--tiny";
636
-        }
637
-        if ($chars && $chars < 25) {
638
-            return "{$class} ee-input-width--small";
639
-        }
640
-        if ($chars && $chars > 100) {
641
-            return "{$class} ee-input-width--big";
642
-        }
643
-        return "{$class} ee-input-width--reg";
644
-    }
645
-
646
-
647
-    /**
648
-     * generate_question_groups_html
649
-     *
650
-     * @param array  $question_groups
651
-     * @param string $group_wrapper
652
-     * @return string HTML
653
-     * @throws EE_Error
654
-     * @throws ReflectionException
655
-     */
656
-    public static function generate_question_groups_html($question_groups = [], $group_wrapper = 'fieldset')
657
-    {
658
-
659
-        $html                            = '';
660
-        $before_question_group_questions =
661
-            apply_filters('FHEE__EEH_Form_Fields__generate_question_groups_html__before_question_group_questions', '');
662
-        $after_question_group_questions  =
663
-            apply_filters('FHEE__EEH_Form_Fields__generate_question_groups_html__after_question_group_questions', '');
664
-
665
-        if (! empty($question_groups)) {
666
-            // loop thru question groups
667
-            foreach ($question_groups as $QSG) {
668
-                // check that questions exist
669
-                if (! empty($QSG['QSG_questions'])) {
670
-                    // use fieldsets
671
-                    $html .= "\n\t"
672
-                             . '<'
673
-                             . $group_wrapper
674
-                             . ' class="espresso-question-group-wrap" id="'
675
-                             . $QSG['QSG_identifier']
676
-                             . '">';
677
-                    // group_name
678
-                    $html .= $QSG['QSG_show_group_name']
679
-                        ? "\n\t\t"
680
-                          . '<h5 class="espresso-question-group-title-h5 section-title">'
681
-                          . self::prep_answer($QSG['QSG_name'])
682
-                          . '</h5>'
683
-                        : '';
684
-                    // group_desc
685
-                    $html .= $QSG['QSG_show_group_desc'] && ! empty($QSG['QSG_desc'])
686
-                        ? '<div class="espresso-question-group-desc-pg">'
687
-                          . self::prep_answer($QSG['QSG_desc'])
688
-                          . '</div>'
689
-                        : '';
690
-
691
-                    $html .= $before_question_group_questions;
692
-                    // loop thru questions
693
-                    foreach ($QSG['QSG_questions'] as $question) {
694
-                        $QFI  = new EE_Question_Form_Input(
695
-                            $question['qst_obj'],
696
-                            $question['ans_obj'],
697
-                            $question
698
-                        );
699
-                        $html .= self::generate_form_input($QFI);
700
-                    }
701
-                    $html .= $after_question_group_questions;
702
-                    $html .= "\n\t" . '</' . $group_wrapper . '>';
703
-                }
704
-            }
705
-        }
706
-
707
-        return $html;
708
-    }
709
-
710
-
711
-    /**
712
-     * generate_question_groups_html
713
-     *
714
-     * @param array  $question_groups
715
-     * @param array  $q_meta
716
-     * @param bool   $from_admin
717
-     * @param string $group_wrapper
718
-     * @return string HTML
719
-     * @throws EE_Error
720
-     * @throws ReflectionException
721
-     */
722
-    public static function generate_question_groups_html2(
723
-        $question_groups = [],
724
-        $q_meta = [],
725
-        $from_admin = false,
726
-        $group_wrapper = 'fieldset'
727
-    ) {
728
-
729
-        $html                            = '';
730
-        $before_question_group_questions =
731
-            apply_filters('FHEE__EEH_Form_Fields__generate_question_groups_html__before_question_group_questions', '');
732
-        $after_question_group_questions  =
733
-            apply_filters('FHEE__EEH_Form_Fields__generate_question_groups_html__after_question_group_questions', '');
734
-
735
-        $default_q_meta = [
736
-            'att_nmbr'    => 1,
737
-            'ticket_id'   => '',
738
-            'input_name'  => '',
739
-            'input_id'    => '',
740
-            'input_class' => '',
741
-        ];
742
-        $q_meta         = array_merge($default_q_meta, $q_meta);
743
-
744
-        if (! empty($question_groups)) {
745
-            // loop thru question groups
746
-            foreach ($question_groups as $QSG) {
747
-                if ($QSG instanceof EE_Question_Group) {
748
-                    // check that questions exist
749
-
750
-                    $where = ['QST_deleted' => 0];
751
-                    if (! $from_admin) {
752
-                        $where['QST_admin_only'] = 0;
753
-                    }
754
-                    $questions =
755
-                        $QSG->questions([$where, 'order_by' => ['Question_Group_Question.QGQ_order' => 'ASC']]);
756
-                    if (! empty($questions)) {
757
-                        // use fieldsets
758
-                        $html .= "\n\t"
759
-                                 . '<' . $group_wrapper . ' class="espresso-question-group-wrap" '
760
-                                 . 'id="' . $QSG->get('QSG_identifier') . '">';
761
-                        // group_name
762
-                        if ($QSG->show_group_name()) {
763
-                            $html .= "\n\t\t"
764
-                                     . '<h5 class="espresso-question-group-title-h5 section-title">'
765
-                                     . $QSG->get_pretty('QSG_name')
766
-                                     . '</h5>';
767
-                        }
768
-                        // group_desc
769
-                        if ($QSG->show_group_desc()) {
770
-                            $html .= '<div class="espresso-question-group-desc-pg">'
771
-                                     . $QSG->get_pretty('QSG_desc')
772
-                                     . '</div>';
773
-                        }
774
-
775
-                        $html .= $before_question_group_questions;
776
-                        // loop thru questions
777
-                        foreach ($questions as $QST) {
778
-                            $qstn_id = $QST->is_system_question() ? $QST->system_ID() : $QST->ID();
779
-
780
-                            $answer = null;
781
-
782
-                            /** @var RequestInterface $request */
783
-                            $request      = LoaderFactory::getLoader()->getShared(RequestInterface::class);
784
-                            $request_qstn = $request->getRequestParam('qstn', [], 'string', true);
785
-                            if (! empty($request_qstn) && isset($q_meta['input_id']) && isset($q_meta['att_nmbr'])) {
786
-                                // check for answer in $request_qstn in case we are reprocessing a form after an error
787
-                                if (isset($request_qstn[ $q_meta['input_id'] ][ $qstn_id ])) {
788
-                                    $answer = is_array($request_qstn[ $q_meta['input_id'] ][ $qstn_id ])
789
-                                        ? $request_qstn[ $q_meta['input_id'] ][ $qstn_id ]
790
-                                        : sanitize_text_field($request_qstn[ $q_meta['input_id'] ][ $qstn_id ]);
791
-                                }
792
-                            } elseif (isset($q_meta['attendee']) && $q_meta['attendee']) {
793
-                                // attendee data from the session
794
-                                $answer =
795
-                                    isset($q_meta['attendee'][ $qstn_id ]) ? $q_meta['attendee'][ $qstn_id ] : null;
796
-                            }
797
-
798
-
799
-                            $QFI  = new EE_Question_Form_Input(
800
-                                $QST,
801
-                                EE_Answer::new_instance(
802
-                                    [
803
-                                        'ANS_ID'    => 0,
804
-                                        'QST_ID'    => 0,
805
-                                        'REG_ID'    => 0,
806
-                                        'ANS_value' => $answer,
807
-                                    ]
808
-                                ),
809
-                                $q_meta
810
-                            );
811
-                            $html .= self::generate_form_input($QFI);
812
-                        }
813
-                        $html .= $after_question_group_questions;
814
-                        $html .= "\n\t" . '</' . $group_wrapper . '>';
815
-                    }
816
-                }
817
-            }
818
-        }
819
-        return $html;
820
-    }
821
-
822
-
823
-    /**
824
-     * generate_form_input
825
-     *
826
-     * @param EE_Question_Form_Input $QFI
827
-     * @return string HTML
828
-     * @throws EE_Error
829
-     * @throws ReflectionException
830
-     */
831
-    public static function generate_form_input(EE_Question_Form_Input $QFI)
832
-    {
833
-        if (isset($QFI->QST_admin_only) && $QFI->QST_admin_only && ! is_admin()) {
834
-            return '';
835
-        }
836
-        /** @var RequestInterface $request */
837
-        $request = LoaderFactory::getLoader()->getShared(RequestInterface::class);
838
-
839
-        $QFI = self::_load_system_dropdowns($QFI);
840
-        $QFI = self::_load_specialized_dropdowns($QFI);
841
-
842
-        // we also need to verify
843
-
844
-        $display_text = (string) $QFI->get('QST_display_text');
845
-        $input_name   = (string) $QFI->get('QST_input_name');
846
-        $answer       = $request->getRequestParam($input_name, $QFI->get('ANS_value'));
847
-        $input_id     = (string) $QFI->get('QST_input_id');
848
-        $input_class  = (string) $QFI->get('QST_input_class');
849
-        //      $disabled = $QFI->get('QST_disabled') ? ' disabled="disabled"' : '';
850
-        $disabled          = (bool) $QFI->get('QST_disabled');
851
-        $required_label    = apply_filters(' FHEE__EEH_Form_Fields__generate_form_input__required_label', '<em>*</em>');
852
-        $QST_required      = (bool) $QFI->get('QST_required');
853
-        $required          = $QST_required
854
-            ? ['label' => $required_label, 'class' => 'required needs-value', 'title' => $QST_required]
855
-            : [];
856
-        $use_html_entities = $QFI->get_meta('htmlentities');
857
-        $required_text     = (string) $QFI->get('QST_required_text') !== ''
858
-            ? (string) $QFI->get('QST_required_text')
859
-            : esc_html__('This field is required', 'event_espresso');
860
-        $required_text     = $QST_required
861
-            ? "\n\t\t\t"
862
-              . '<div class="required-text hidden">'
863
-              . self::prep_answer($required_text, $use_html_entities)
864
-              . '</div>'
865
-            : '';
866
-        $label_class       = (string) $QFI->get('label_class');
867
-        $label_class       = $label_class ? "{$label_class} espresso-form-input-lbl" : 'espresso-form-input-lbl';
868
-        $QST_options       = $QFI->options(true, $answer);
869
-        $options           = is_array($QST_options) ? self::prep_answer_options($QST_options) : [];
870
-        $system_ID         = (string) $QFI->get('QST_system');
871
-        $label_b4          = (bool) $QFI->get_meta('label_b4');
872
-        $use_desc_4_label  = (bool) $QFI->get_meta('use_desc_4_label');
873
-        $add_mobile_label  = (bool) $QFI->get_meta('add_mobile_label');
874
-
875
-
876
-        switch ($QFI->get('QST_type')) {
877
-            case 'TEXTAREA':
878
-                return EEH_Form_Fields::textarea(
879
-                    $display_text,
880
-                    $answer,
881
-                    $input_name,
882
-                    $input_id,
883
-                    $input_class,
884
-                    [],
885
-                    $required,
886
-                    $required_text,
887
-                    $label_class,
888
-                    $disabled,
889
-                    $system_ID,
890
-                    $use_html_entities,
891
-                    $add_mobile_label
892
-                );
893
-
894
-            case 'DROPDOWN':
895
-                return EEH_Form_Fields::select(
896
-                    $display_text,
897
-                    $answer,
898
-                    $options,
899
-                    $input_name,
900
-                    $input_id,
901
-                    $input_class,
902
-                    $required,
903
-                    $required_text,
904
-                    $label_class,
905
-                    $disabled,
906
-                    $system_ID,
907
-                    $use_html_entities,
908
-                    true,
909
-                    $add_mobile_label
910
-                );
911
-
912
-
913
-            case 'RADIO_BTN':
914
-                return EEH_Form_Fields::radio(
915
-                    $display_text,
916
-                    $answer,
917
-                    $options,
918
-                    $input_name,
919
-                    $input_id,
920
-                    $input_class,
921
-                    $required,
922
-                    $required_text,
923
-                    $label_class,
924
-                    $disabled,
925
-                    $system_ID,
926
-                    $use_html_entities,
927
-                    $label_b4,
928
-                    $use_desc_4_label,
929
-                    $add_mobile_label
930
-                );
931
-
932
-            case 'CHECKBOX':
933
-                return EEH_Form_Fields::checkbox(
934
-                    $display_text,
935
-                    $answer,
936
-                    $options,
937
-                    $input_name,
938
-                    $input_id,
939
-                    $input_class,
940
-                    $required,
941
-                    $required_text,
942
-                    $label_class,
943
-                    $disabled,
944
-                    $label_b4,
945
-                    $system_ID,
946
-                    $use_html_entities,
947
-                    $add_mobile_label
948
-                );
949
-
950
-            case 'DATE':
951
-                return EEH_Form_Fields::datepicker(
952
-                    $display_text,
953
-                    $answer,
954
-                    $input_name,
955
-                    $input_id,
956
-                    $input_class,
957
-                    $required,
958
-                    $required_text,
959
-                    $label_class,
960
-                    $disabled,
961
-                    $system_ID,
962
-                    $use_html_entities,
963
-                    $add_mobile_label
964
-                );
965
-
966
-            case 'TEXT':
967
-            default:
968
-                return EEH_Form_Fields::text(
969
-                    $display_text,
970
-                    $answer,
971
-                    $input_name,
972
-                    $input_id,
973
-                    $input_class,
974
-                    $required,
975
-                    $required_text,
976
-                    $label_class,
977
-                    $disabled,
978
-                    $system_ID,
979
-                    $use_html_entities,
980
-                    $add_mobile_label
981
-                );
982
-        }
983
-    }
984
-
985
-
986
-    public static function label(
987
-        string $question,
988
-        string $required_text = '',
989
-        string $required_label = '',
990
-        string $name = '',
991
-        string $label_class = '',
992
-        bool $filter = true
993
-    ): string {
994
-        $for   = ! empty($name) ? " for='{$name}'" : '';
995
-        $class = ! empty($label_class) ? " class='{$label_class}'" : '';
996
-        $label = self::prep_question($question) . $required_label;
997
-        $label_html = "
491
+	}
492
+
493
+
494
+	/**
495
+	 * @param string $class
496
+	 * @param string $id
497
+	 * @param string $name
498
+	 * @param int    $rows
499
+	 * @param int    $tab_index
500
+	 * @param string $value
501
+	 * @param array  $wp_editor_args
502
+	 * @return false|string
503
+	 * @since   4.10.14.p
504
+	 */
505
+	private static function adminWpEditor($class, $id, $name, $rows, $tab_index, $value, $wp_editor_args = [])
506
+	{
507
+		$editor_settings = $wp_editor_args + [
508
+				'textarea_name' => esc_attr($name),
509
+				'textarea_rows' => absint($rows),
510
+				'editor_class'  => esc_attr($class),
511
+				'tabindex'      => absint($tab_index),
512
+			];
513
+		ob_start();
514
+		wp_editor($value, esc_attr($id), $editor_settings);
515
+		return ob_get_clean();
516
+	}
517
+
518
+
519
+	/**
520
+	 * espresso admin page select_input
521
+	 * Turns an array into a select fields
522
+	 *
523
+	 * @static
524
+	 * @access public
525
+	 * @param string  $name       field name
526
+	 * @param array   $values     option values, numbered array starting at 0, where each value is an array with a key
527
+	 *                            'text' (meaning text to display' and 'id' (meaning the internal value) eg:
528
+	 *                            array(1=>array('text'=>'Monday','id'=>1),2=>array('text'=>'Tuesday','id'=>2)...). or
529
+	 *                            as an array of key-value pairs, where the key is to be used for the select input's
530
+	 *                            name, and the value will be the text shown to the user.  Optionally you can also
531
+	 *                            include an additional key of "class" which will add a specific class to the option
532
+	 *                            for that value.
533
+	 * @param string  $default    default value
534
+	 * @param string  $parameters extra parameters
535
+	 * @param string  $class      css class
536
+	 * @param boolean $autosize   whether to autosize the select or not
537
+	 * @return string              html string for the select input
538
+	 */
539
+	public static function select_input(
540
+		$name,
541
+		$values,
542
+		$default = '',
543
+		$parameters = '',
544
+		$class = '',
545
+		$autosize = true
546
+	) {
547
+		// if $values was submitted in the wrong format, convert it over
548
+		if (! empty($values) && (! array_key_exists(0, $values) || ! is_array($values[0]))) {
549
+			$converted_values = [];
550
+			foreach ($values as $id => $text) {
551
+				$converted_values[] = ['id' => $id, 'text' => $text];
552
+			}
553
+			$values = $converted_values;
554
+		}
555
+
556
+		$field =
557
+			'<select id="' . EEH_Formatter::ee_tep_output_string($name)
558
+			. '" name="' . EEH_Formatter::ee_tep_output_string($name)
559
+			. '"';
560
+
561
+		if (EEH_Formatter::ee_tep_not_null($parameters)) {
562
+			$field .= ' ' . $parameters;
563
+		}
564
+		$class = $autosize ? self::appendInputSizeClass($class, $values) : '';
565
+
566
+		$field .= ' class="' . $class . '">';
567
+
568
+		if (empty($default) && isset($GLOBALS[ $name ])) {
569
+			$default = stripslashes($GLOBALS[ $name ]);
570
+		}
571
+
572
+		$field .= self::selectInputOption($values, $default);
573
+		$field .= '</select>';
574
+
575
+		return $field;
576
+	}
577
+
578
+
579
+	private static function selectInputOption(array $values, $default): string
580
+	{
581
+		if (isset($values['id'], $values['text'])) {
582
+			$id = is_scalar($values['id']) ? $values['id'] : '';
583
+			$text = is_scalar($values['text']) ? $values['text'] : '';
584
+			$selected = $default == $values['id'] ? ' selected = "selected"' : '';
585
+			$html_class = isset($values['class']) ? ' class="' . $values['class'] . '"' : '';
586
+			return "<option value='{$id}'{$selected}{$html_class}>{$text}</option>";
587
+		}
588
+		$options = '';
589
+		foreach ($values as $value) {
590
+			$options .= self::selectInputOption($value, $default);
591
+		}
592
+		return $options;
593
+	}
594
+
595
+
596
+	/**
597
+	 * @param mixed $value
598
+	 * @return int
599
+	 * @since   5.0.0.p
600
+	 */
601
+	private static function getInputValueLength($value): int
602
+	{
603
+		if ($value instanceof EE_Question_Option) {
604
+			return self::getInputValueLength($value->desc());
605
+		}
606
+		if (is_array($value)) {
607
+			$chars = 0;
608
+			foreach ($value as $val) {
609
+				$length = self::getInputValueLength($val);
610
+				$chars = max($length, $chars);
611
+			}
612
+			return $chars;
613
+		}
614
+		// not a primitive? return something big
615
+		if (! is_scalar($value)) {
616
+			return 500;
617
+		}
618
+		return strlen((string) $value);
619
+	}
620
+
621
+
622
+	/**
623
+	 * @param string $class
624
+	 * @param mixed $value
625
+	 * @return string
626
+	 * @since   5.0.0.p
627
+	 */
628
+	private static function appendInputSizeClass(string $class, $value): string
629
+	{
630
+		if (strpos($class, 'ee-input-width--') !== false) {
631
+			return $class;
632
+		}
633
+		$chars = self::getInputValueLength($value);
634
+		if ($chars && $chars < 5) {
635
+			return "{$class} ee-input-width--tiny";
636
+		}
637
+		if ($chars && $chars < 25) {
638
+			return "{$class} ee-input-width--small";
639
+		}
640
+		if ($chars && $chars > 100) {
641
+			return "{$class} ee-input-width--big";
642
+		}
643
+		return "{$class} ee-input-width--reg";
644
+	}
645
+
646
+
647
+	/**
648
+	 * generate_question_groups_html
649
+	 *
650
+	 * @param array  $question_groups
651
+	 * @param string $group_wrapper
652
+	 * @return string HTML
653
+	 * @throws EE_Error
654
+	 * @throws ReflectionException
655
+	 */
656
+	public static function generate_question_groups_html($question_groups = [], $group_wrapper = 'fieldset')
657
+	{
658
+
659
+		$html                            = '';
660
+		$before_question_group_questions =
661
+			apply_filters('FHEE__EEH_Form_Fields__generate_question_groups_html__before_question_group_questions', '');
662
+		$after_question_group_questions  =
663
+			apply_filters('FHEE__EEH_Form_Fields__generate_question_groups_html__after_question_group_questions', '');
664
+
665
+		if (! empty($question_groups)) {
666
+			// loop thru question groups
667
+			foreach ($question_groups as $QSG) {
668
+				// check that questions exist
669
+				if (! empty($QSG['QSG_questions'])) {
670
+					// use fieldsets
671
+					$html .= "\n\t"
672
+							 . '<'
673
+							 . $group_wrapper
674
+							 . ' class="espresso-question-group-wrap" id="'
675
+							 . $QSG['QSG_identifier']
676
+							 . '">';
677
+					// group_name
678
+					$html .= $QSG['QSG_show_group_name']
679
+						? "\n\t\t"
680
+						  . '<h5 class="espresso-question-group-title-h5 section-title">'
681
+						  . self::prep_answer($QSG['QSG_name'])
682
+						  . '</h5>'
683
+						: '';
684
+					// group_desc
685
+					$html .= $QSG['QSG_show_group_desc'] && ! empty($QSG['QSG_desc'])
686
+						? '<div class="espresso-question-group-desc-pg">'
687
+						  . self::prep_answer($QSG['QSG_desc'])
688
+						  . '</div>'
689
+						: '';
690
+
691
+					$html .= $before_question_group_questions;
692
+					// loop thru questions
693
+					foreach ($QSG['QSG_questions'] as $question) {
694
+						$QFI  = new EE_Question_Form_Input(
695
+							$question['qst_obj'],
696
+							$question['ans_obj'],
697
+							$question
698
+						);
699
+						$html .= self::generate_form_input($QFI);
700
+					}
701
+					$html .= $after_question_group_questions;
702
+					$html .= "\n\t" . '</' . $group_wrapper . '>';
703
+				}
704
+			}
705
+		}
706
+
707
+		return $html;
708
+	}
709
+
710
+
711
+	/**
712
+	 * generate_question_groups_html
713
+	 *
714
+	 * @param array  $question_groups
715
+	 * @param array  $q_meta
716
+	 * @param bool   $from_admin
717
+	 * @param string $group_wrapper
718
+	 * @return string HTML
719
+	 * @throws EE_Error
720
+	 * @throws ReflectionException
721
+	 */
722
+	public static function generate_question_groups_html2(
723
+		$question_groups = [],
724
+		$q_meta = [],
725
+		$from_admin = false,
726
+		$group_wrapper = 'fieldset'
727
+	) {
728
+
729
+		$html                            = '';
730
+		$before_question_group_questions =
731
+			apply_filters('FHEE__EEH_Form_Fields__generate_question_groups_html__before_question_group_questions', '');
732
+		$after_question_group_questions  =
733
+			apply_filters('FHEE__EEH_Form_Fields__generate_question_groups_html__after_question_group_questions', '');
734
+
735
+		$default_q_meta = [
736
+			'att_nmbr'    => 1,
737
+			'ticket_id'   => '',
738
+			'input_name'  => '',
739
+			'input_id'    => '',
740
+			'input_class' => '',
741
+		];
742
+		$q_meta         = array_merge($default_q_meta, $q_meta);
743
+
744
+		if (! empty($question_groups)) {
745
+			// loop thru question groups
746
+			foreach ($question_groups as $QSG) {
747
+				if ($QSG instanceof EE_Question_Group) {
748
+					// check that questions exist
749
+
750
+					$where = ['QST_deleted' => 0];
751
+					if (! $from_admin) {
752
+						$where['QST_admin_only'] = 0;
753
+					}
754
+					$questions =
755
+						$QSG->questions([$where, 'order_by' => ['Question_Group_Question.QGQ_order' => 'ASC']]);
756
+					if (! empty($questions)) {
757
+						// use fieldsets
758
+						$html .= "\n\t"
759
+								 . '<' . $group_wrapper . ' class="espresso-question-group-wrap" '
760
+								 . 'id="' . $QSG->get('QSG_identifier') . '">';
761
+						// group_name
762
+						if ($QSG->show_group_name()) {
763
+							$html .= "\n\t\t"
764
+									 . '<h5 class="espresso-question-group-title-h5 section-title">'
765
+									 . $QSG->get_pretty('QSG_name')
766
+									 . '</h5>';
767
+						}
768
+						// group_desc
769
+						if ($QSG->show_group_desc()) {
770
+							$html .= '<div class="espresso-question-group-desc-pg">'
771
+									 . $QSG->get_pretty('QSG_desc')
772
+									 . '</div>';
773
+						}
774
+
775
+						$html .= $before_question_group_questions;
776
+						// loop thru questions
777
+						foreach ($questions as $QST) {
778
+							$qstn_id = $QST->is_system_question() ? $QST->system_ID() : $QST->ID();
779
+
780
+							$answer = null;
781
+
782
+							/** @var RequestInterface $request */
783
+							$request      = LoaderFactory::getLoader()->getShared(RequestInterface::class);
784
+							$request_qstn = $request->getRequestParam('qstn', [], 'string', true);
785
+							if (! empty($request_qstn) && isset($q_meta['input_id']) && isset($q_meta['att_nmbr'])) {
786
+								// check for answer in $request_qstn in case we are reprocessing a form after an error
787
+								if (isset($request_qstn[ $q_meta['input_id'] ][ $qstn_id ])) {
788
+									$answer = is_array($request_qstn[ $q_meta['input_id'] ][ $qstn_id ])
789
+										? $request_qstn[ $q_meta['input_id'] ][ $qstn_id ]
790
+										: sanitize_text_field($request_qstn[ $q_meta['input_id'] ][ $qstn_id ]);
791
+								}
792
+							} elseif (isset($q_meta['attendee']) && $q_meta['attendee']) {
793
+								// attendee data from the session
794
+								$answer =
795
+									isset($q_meta['attendee'][ $qstn_id ]) ? $q_meta['attendee'][ $qstn_id ] : null;
796
+							}
797
+
798
+
799
+							$QFI  = new EE_Question_Form_Input(
800
+								$QST,
801
+								EE_Answer::new_instance(
802
+									[
803
+										'ANS_ID'    => 0,
804
+										'QST_ID'    => 0,
805
+										'REG_ID'    => 0,
806
+										'ANS_value' => $answer,
807
+									]
808
+								),
809
+								$q_meta
810
+							);
811
+							$html .= self::generate_form_input($QFI);
812
+						}
813
+						$html .= $after_question_group_questions;
814
+						$html .= "\n\t" . '</' . $group_wrapper . '>';
815
+					}
816
+				}
817
+			}
818
+		}
819
+		return $html;
820
+	}
821
+
822
+
823
+	/**
824
+	 * generate_form_input
825
+	 *
826
+	 * @param EE_Question_Form_Input $QFI
827
+	 * @return string HTML
828
+	 * @throws EE_Error
829
+	 * @throws ReflectionException
830
+	 */
831
+	public static function generate_form_input(EE_Question_Form_Input $QFI)
832
+	{
833
+		if (isset($QFI->QST_admin_only) && $QFI->QST_admin_only && ! is_admin()) {
834
+			return '';
835
+		}
836
+		/** @var RequestInterface $request */
837
+		$request = LoaderFactory::getLoader()->getShared(RequestInterface::class);
838
+
839
+		$QFI = self::_load_system_dropdowns($QFI);
840
+		$QFI = self::_load_specialized_dropdowns($QFI);
841
+
842
+		// we also need to verify
843
+
844
+		$display_text = (string) $QFI->get('QST_display_text');
845
+		$input_name   = (string) $QFI->get('QST_input_name');
846
+		$answer       = $request->getRequestParam($input_name, $QFI->get('ANS_value'));
847
+		$input_id     = (string) $QFI->get('QST_input_id');
848
+		$input_class  = (string) $QFI->get('QST_input_class');
849
+		//      $disabled = $QFI->get('QST_disabled') ? ' disabled="disabled"' : '';
850
+		$disabled          = (bool) $QFI->get('QST_disabled');
851
+		$required_label    = apply_filters(' FHEE__EEH_Form_Fields__generate_form_input__required_label', '<em>*</em>');
852
+		$QST_required      = (bool) $QFI->get('QST_required');
853
+		$required          = $QST_required
854
+			? ['label' => $required_label, 'class' => 'required needs-value', 'title' => $QST_required]
855
+			: [];
856
+		$use_html_entities = $QFI->get_meta('htmlentities');
857
+		$required_text     = (string) $QFI->get('QST_required_text') !== ''
858
+			? (string) $QFI->get('QST_required_text')
859
+			: esc_html__('This field is required', 'event_espresso');
860
+		$required_text     = $QST_required
861
+			? "\n\t\t\t"
862
+			  . '<div class="required-text hidden">'
863
+			  . self::prep_answer($required_text, $use_html_entities)
864
+			  . '</div>'
865
+			: '';
866
+		$label_class       = (string) $QFI->get('label_class');
867
+		$label_class       = $label_class ? "{$label_class} espresso-form-input-lbl" : 'espresso-form-input-lbl';
868
+		$QST_options       = $QFI->options(true, $answer);
869
+		$options           = is_array($QST_options) ? self::prep_answer_options($QST_options) : [];
870
+		$system_ID         = (string) $QFI->get('QST_system');
871
+		$label_b4          = (bool) $QFI->get_meta('label_b4');
872
+		$use_desc_4_label  = (bool) $QFI->get_meta('use_desc_4_label');
873
+		$add_mobile_label  = (bool) $QFI->get_meta('add_mobile_label');
874
+
875
+
876
+		switch ($QFI->get('QST_type')) {
877
+			case 'TEXTAREA':
878
+				return EEH_Form_Fields::textarea(
879
+					$display_text,
880
+					$answer,
881
+					$input_name,
882
+					$input_id,
883
+					$input_class,
884
+					[],
885
+					$required,
886
+					$required_text,
887
+					$label_class,
888
+					$disabled,
889
+					$system_ID,
890
+					$use_html_entities,
891
+					$add_mobile_label
892
+				);
893
+
894
+			case 'DROPDOWN':
895
+				return EEH_Form_Fields::select(
896
+					$display_text,
897
+					$answer,
898
+					$options,
899
+					$input_name,
900
+					$input_id,
901
+					$input_class,
902
+					$required,
903
+					$required_text,
904
+					$label_class,
905
+					$disabled,
906
+					$system_ID,
907
+					$use_html_entities,
908
+					true,
909
+					$add_mobile_label
910
+				);
911
+
912
+
913
+			case 'RADIO_BTN':
914
+				return EEH_Form_Fields::radio(
915
+					$display_text,
916
+					$answer,
917
+					$options,
918
+					$input_name,
919
+					$input_id,
920
+					$input_class,
921
+					$required,
922
+					$required_text,
923
+					$label_class,
924
+					$disabled,
925
+					$system_ID,
926
+					$use_html_entities,
927
+					$label_b4,
928
+					$use_desc_4_label,
929
+					$add_mobile_label
930
+				);
931
+
932
+			case 'CHECKBOX':
933
+				return EEH_Form_Fields::checkbox(
934
+					$display_text,
935
+					$answer,
936
+					$options,
937
+					$input_name,
938
+					$input_id,
939
+					$input_class,
940
+					$required,
941
+					$required_text,
942
+					$label_class,
943
+					$disabled,
944
+					$label_b4,
945
+					$system_ID,
946
+					$use_html_entities,
947
+					$add_mobile_label
948
+				);
949
+
950
+			case 'DATE':
951
+				return EEH_Form_Fields::datepicker(
952
+					$display_text,
953
+					$answer,
954
+					$input_name,
955
+					$input_id,
956
+					$input_class,
957
+					$required,
958
+					$required_text,
959
+					$label_class,
960
+					$disabled,
961
+					$system_ID,
962
+					$use_html_entities,
963
+					$add_mobile_label
964
+				);
965
+
966
+			case 'TEXT':
967
+			default:
968
+				return EEH_Form_Fields::text(
969
+					$display_text,
970
+					$answer,
971
+					$input_name,
972
+					$input_id,
973
+					$input_class,
974
+					$required,
975
+					$required_text,
976
+					$label_class,
977
+					$disabled,
978
+					$system_ID,
979
+					$use_html_entities,
980
+					$add_mobile_label
981
+				);
982
+		}
983
+	}
984
+
985
+
986
+	public static function label(
987
+		string $question,
988
+		string $required_text = '',
989
+		string $required_label = '',
990
+		string $name = '',
991
+		string $label_class = '',
992
+		bool $filter = true
993
+	): string {
994
+		$for   = ! empty($name) ? " for='{$name}'" : '';
995
+		$class = ! empty($label_class) ? " class='{$label_class}'" : '';
996
+		$label = self::prep_question($question) . $required_label;
997
+		$label_html = "
998 998
             {$required_text}
999 999
             <label{$for}{$class}>{$label}</label>";
1000
-        // filter label but ensure required text comes before it
1001
-        return $filter
1002
-            ? apply_filters('FHEE__EEH_Form_Fields__label_html', $label_html, $required_text)
1003
-            : $label_html;
1004
-    }
1005
-
1006
-
1007
-
1008
-    public static function mobileLabel(
1009
-        bool $add_mobile_label,
1010
-        string $question,
1011
-        string $required_text = '',
1012
-        string $required_label = '',
1013
-        string $label_class = '',
1014
-        string $name = ''
1015
-    ): string {
1016
-        return $add_mobile_label
1017
-            ? self::label($question, $required_text, $required_label, $name, $label_class, false)
1018
-            : '';
1019
-    }
1020
-
1021
-
1022
-    /**
1023
-     * generates HTML for a form text input
1024
-     *
1025
-     * @param string $question    label content
1026
-     * @param string $answer      form input value attribute
1027
-     * @param string $name        form input name attribute
1028
-     * @param string $id          form input css id attribute
1029
-     * @param string $class       form input css class attribute
1030
-     * @param array  $required    'label', 'class', and 'msg' - array of values for required "label" content, css
1031
-     *                            required 'class', and required 'msg' attribute
1032
-     * @param string $label_class css class attribute for the label
1033
-     * @param string $disabled    disabled="disabled" or null
1034
-     * @return string HTML
1035
-     */
1036
-    public static function text(
1037
-        $question = false,
1038
-        $answer = null,
1039
-        $name = false,
1040
-        $id = '',
1041
-        $class = '',
1042
-        $required = false,
1043
-        $required_text = '',
1044
-        $label_class = '',
1045
-        $disabled = false,
1046
-        $system_ID = false,
1047
-        $use_html_entities = true,
1048
-        $add_mobile_label = false,
1049
-        $extra_attributes = ''
1050
-    ) {
1051
-        // need these
1052
-        if (! $question || ! $name) {
1053
-            return null;
1054
-        }
1055
-        // prep the answer
1056
-        $answer = is_array($answer) ? '' : self::prep_answer($answer, $use_html_entities);
1057
-        // prep the required array
1058
-        $required = self::prep_required($required);
1059
-        // set disabled tag
1060
-        $disabled = $answer === null || ! $disabled ? '' : ' disabled="disabled"';
1061
-        // ya gots ta have style man!!!
1062
-        $txt_class = is_admin() ? 'regular-text' : 'espresso-text-inp';
1063
-        $class     = empty($class) ? $txt_class : $class;
1064
-        $class     .= ! empty($system_ID) ? ' ' . $system_ID : '';
1065
-        $class = self::appendInputSizeClass($class, $answer);
1066
-        $class .= ! empty($required['class']) ? ' ' . $required['class'] : '';
1067
-        $extra_attributes = apply_filters('FHEE__EEH_Form_Fields__additional_form_field_attributes', $extra_attributes);
1068
-
1069
-        $label_html = self::label($question, $required_text, $required['label'], $name, $label_class);
1070
-        $mobile_label = self::mobileLabel(
1071
-            $add_mobile_label,
1072
-            $question,
1073
-            $required_text,
1074
-            $required['label'],
1075
-            $label_class,
1076
-            $name
1077
-        );
1078
-
1079
-        $input_html = $mobile_label . '
1000
+		// filter label but ensure required text comes before it
1001
+		return $filter
1002
+			? apply_filters('FHEE__EEH_Form_Fields__label_html', $label_html, $required_text)
1003
+			: $label_html;
1004
+	}
1005
+
1006
+
1007
+
1008
+	public static function mobileLabel(
1009
+		bool $add_mobile_label,
1010
+		string $question,
1011
+		string $required_text = '',
1012
+		string $required_label = '',
1013
+		string $label_class = '',
1014
+		string $name = ''
1015
+	): string {
1016
+		return $add_mobile_label
1017
+			? self::label($question, $required_text, $required_label, $name, $label_class, false)
1018
+			: '';
1019
+	}
1020
+
1021
+
1022
+	/**
1023
+	 * generates HTML for a form text input
1024
+	 *
1025
+	 * @param string $question    label content
1026
+	 * @param string $answer      form input value attribute
1027
+	 * @param string $name        form input name attribute
1028
+	 * @param string $id          form input css id attribute
1029
+	 * @param string $class       form input css class attribute
1030
+	 * @param array  $required    'label', 'class', and 'msg' - array of values for required "label" content, css
1031
+	 *                            required 'class', and required 'msg' attribute
1032
+	 * @param string $label_class css class attribute for the label
1033
+	 * @param string $disabled    disabled="disabled" or null
1034
+	 * @return string HTML
1035
+	 */
1036
+	public static function text(
1037
+		$question = false,
1038
+		$answer = null,
1039
+		$name = false,
1040
+		$id = '',
1041
+		$class = '',
1042
+		$required = false,
1043
+		$required_text = '',
1044
+		$label_class = '',
1045
+		$disabled = false,
1046
+		$system_ID = false,
1047
+		$use_html_entities = true,
1048
+		$add_mobile_label = false,
1049
+		$extra_attributes = ''
1050
+	) {
1051
+		// need these
1052
+		if (! $question || ! $name) {
1053
+			return null;
1054
+		}
1055
+		// prep the answer
1056
+		$answer = is_array($answer) ? '' : self::prep_answer($answer, $use_html_entities);
1057
+		// prep the required array
1058
+		$required = self::prep_required($required);
1059
+		// set disabled tag
1060
+		$disabled = $answer === null || ! $disabled ? '' : ' disabled="disabled"';
1061
+		// ya gots ta have style man!!!
1062
+		$txt_class = is_admin() ? 'regular-text' : 'espresso-text-inp';
1063
+		$class     = empty($class) ? $txt_class : $class;
1064
+		$class     .= ! empty($system_ID) ? ' ' . $system_ID : '';
1065
+		$class = self::appendInputSizeClass($class, $answer);
1066
+		$class .= ! empty($required['class']) ? ' ' . $required['class'] : '';
1067
+		$extra_attributes = apply_filters('FHEE__EEH_Form_Fields__additional_form_field_attributes', $extra_attributes);
1068
+
1069
+		$label_html = self::label($question, $required_text, $required['label'], $name, $label_class);
1070
+		$mobile_label = self::mobileLabel(
1071
+			$add_mobile_label,
1072
+			$question,
1073
+			$required_text,
1074
+			$required['label'],
1075
+			$label_class,
1076
+			$name
1077
+		);
1078
+
1079
+		$input_html = $mobile_label . '
1080 1080
             <input  type="text"
1081 1081
                     name="' . $name . '"
1082 1082
                     id="' . $id . '"
@@ -1086,1034 +1086,1034 @@  discard block
 block discarded – undo
1086 1086
                     ' . $disabled . ' ' . $extra_attributes . '
1087 1087
             />';
1088 1088
 
1089
-        $input_html = apply_filters('FHEE__EEH_Form_Fields__input_html', $input_html, $label_html, $id);
1090
-        return $label_html . $input_html;
1091
-    }
1092
-
1093
-
1094
-    /**
1095
-     * generates HTML for a form textarea
1096
-     *
1097
-     * @param string $question    label content
1098
-     * @param string $answer      form input value attribute
1099
-     * @param string $name        form input name attribute
1100
-     * @param string $id          form input css id attribute
1101
-     * @param string $class       form input css class attribute
1102
-     * @param array  $dimensions  array of form input rows and cols attributes : array( 'rows' => 3, 'cols' => 40 )
1103
-     * @param array  $required    'label', 'class', and 'msg' - array of values for required "label" content, css
1104
-     *                            required 'class', and required 'msg' attribute
1105
-     * @param string $label_class css class attribute for the label
1106
-     * @param string $disabled    disabled="disabled" or null
1107
-     * @return string HTML
1108
-     */
1109
-    public static function textarea(
1110
-        $question = false,
1111
-        $answer = null,
1112
-        $name = false,
1113
-        $id = '',
1114
-        $class = '',
1115
-        $dimensions = false,
1116
-        $required = false,
1117
-        $required_text = '',
1118
-        $label_class = '',
1119
-        $disabled = false,
1120
-        $system_ID = false,
1121
-        $use_html_entities = true,
1122
-        $add_mobile_label = false
1123
-    ) {
1124
-        // need these
1125
-        if (! $question || ! $name) {
1126
-            return null;
1127
-        }
1128
-        // prep the answer
1129
-        $answer = is_array($answer) ? '' : self::prep_answer($answer, $use_html_entities);
1130
-        // prep the required array
1131
-        $required = self::prep_required($required);
1132
-        // make sure $dimensions is an array
1133
-        $dimensions = is_array($dimensions) ? $dimensions : [];
1134
-        // and set some defaults
1135
-        $dimensions = array_merge(['rows' => 3, 'cols' => 40], $dimensions);
1136
-        // set disabled tag
1137
-        $disabled = $answer === null || ! $disabled ? '' : ' disabled="disabled"';
1138
-        // ya gots ta have style man!!!
1139
-        $class     .= ! empty($system_ID) ? ' ' . $system_ID : '';
1140
-        $class     .= ! empty($required['class']) ? ' ' . $required['class'] : '';
1141
-        $extra     = apply_filters('FHEE__EEH_Form_Fields__additional_form_field_attributes', '');
1142
-
1143
-        $label_html   = self::label($question, $required_text, $required['label'], $name, $label_class);
1144
-        $mobile_label = self::mobileLabel(
1145
-            $add_mobile_label,
1146
-            $question,
1147
-            $required_text,
1148
-            $required['label'],
1149
-            $label_class,
1150
-            $name
1151
-        );
1152
-
1153
-        $input_html = $mobile_label
1154
-            . '<textarea name="' . $name . '" id="' . $id . '" class="' . trim($class) . '" '
1155
-            . 'rows="' . $dimensions['rows'] . '" cols="' . $dimensions['cols'] . '"  '
1156
-            . 'aria-label="' . $required['msg'] . '" ' . $disabled . ' ' . $extra . '>'
1157
-             . esc_textarea($answer)
1158
-              . '</textarea>';
1159
-
1160
-        $input_html = apply_filters('FHEE__EEH_Form_Fields__input_html', $input_html, $label_html, $id);
1161
-        return $label_html . $input_html;
1162
-    }
1163
-
1164
-
1165
-    /**
1166
-     * generates HTML for a form select input
1167
-     *
1168
-     * @param string $question    label content
1169
-     * @param string $answer      form input value attribute
1170
-     * @param array  $options     array of answer options where array key = option value and array value = option
1171
-     *                            display text
1172
-     * @param string $name        form input name attribute
1173
-     * @param string $id          form input css id attribute
1174
-     * @param string $class       form input css class attribute
1175
-     * @param array  $required    'label', 'class', and 'msg' - array of values for required "label" content, css
1176
-     *                            required 'class', and required 'msg' attribute
1177
-     * @param string $label_class css class attribute for the label
1178
-     * @param string $disabled    disabled="disabled" or null
1179
-     * @return string HTML
1180
-     */
1181
-    public static function select(
1182
-        $question = false,
1183
-        $answer = null,
1184
-        $options = false,
1185
-        $name = false,
1186
-        $id = '',
1187
-        $class = '',
1188
-        $required = false,
1189
-        $required_text = '',
1190
-        $label_class = '',
1191
-        $disabled = false,
1192
-        $system_ID = false,
1193
-        $use_html_entities = true,
1194
-        $add_please_select_option = false,
1195
-        $add_mobile_label = false
1196
-    ) {
1197
-
1198
-        // need these
1199
-        if (! $question || ! $name || ! $options || empty($options) || ! is_array($options)) {
1200
-            return null;
1201
-        }
1202
-        // prep the answer
1203
-        $answer = is_array($answer)
1204
-            ? self::prep_answer(array_shift($answer), $use_html_entities)
1205
-            : self::prep_answer($answer, $use_html_entities);
1206
-        // prep the required array
1207
-        $required = self::prep_required($required);
1208
-        // set disabled tag
1209
-        $disabled = $answer === null || ! $disabled ? '' : ' disabled="disabled"';
1210
-        // ya gots ta have style man!!!
1211
-        $class     .= ! empty($system_ID) ? ' ' . $system_ID : '';
1212
-        $class = self::appendInputSizeClass($class, $options);
1213
-        $extra     = apply_filters('FHEE__EEH_Form_Fields__additional_form_field_attributes', '');
1214
-
1215
-        $label_html   = self::label($question, $required_text, $required['label'], $name, $label_class);
1216
-        $mobile_label = self::mobileLabel(
1217
-            $add_mobile_label,
1218
-            $question,
1219
-            $required_text,
1220
-            $required['label'],
1221
-            $label_class,
1222
-            $name
1223
-        );
1224
-
1225
-        $input_html = $mobile_label
1226
-            . '<select name="' . $name . '" id="' . $id . '" class="' . trim($class) . ' ' . $required['class'] . '" '
1227
-            . 'aria-label="' . esc_attr($required['msg']) . '"' . $disabled . ' ' . $extra . '>';
1228
-        // recursively count array elements, to determine total number of options
1229
-        $only_option = count($options, 1) == 1;
1230
-        if (! $only_option) {
1231
-            // if there is NO answer set and there are multiple options to choose from, then set the "please select" message as selected
1232
-            $selected   = $answer === null ? ' selected' : '';
1233
-            $input_html .= $add_please_select_option
1234
-                ? "\n\t\t\t\t"
1235
-                  . '<option value=""' . $selected . '>'
1236
-                  . esc_html__(' - please select - ', 'event_espresso')
1237
-                  . '</option>'
1238
-                : '';
1239
-        }
1240
-        foreach ($options as $key => $value) {
1241
-            // if value is an array, then create option groups, else create regular ol' options
1242
-            $input_html .= is_array($value)
1243
-                ? self::_generate_select_option_group(
1244
-                    $key,
1245
-                    $value,
1246
-                    $answer,
1247
-                    $use_html_entities
1248
-                )
1249
-                : self::_generate_select_option(
1250
-                    $value->value(),
1251
-                    $value->desc(),
1252
-                    $answer,
1253
-                    $only_option,
1254
-                    $use_html_entities
1255
-                );
1256
-        }
1257
-
1258
-        $input_html .= "\n\t\t\t" . '</select>';
1259
-
1260
-        $input_html =
1261
-            apply_filters(
1262
-                'FHEE__EEH_Form_Fields__select__before_end_wrapper',
1263
-                $input_html,
1264
-                $question,
1265
-                $answer,
1266
-                $name,
1267
-                $id,
1268
-                $class,
1269
-                $system_ID
1270
-            );
1271
-
1272
-        $input_html = apply_filters('FHEE__EEH_Form_Fields__input_html', $input_html, $label_html, $id);
1273
-        return $label_html . $input_html;
1274
-    }
1275
-
1276
-
1277
-    /**
1278
-     *  _generate_select_option_group
1279
-     *
1280
-     *  if  $value for a select box is an array, then the key will be used as the optgroup label
1281
-     *  and the value array will be looped thru and the elements sent to _generate_select_option
1282
-     *
1283
-     * @param mixed   $opt_group
1284
-     * @param mixed   $QSOs
1285
-     * @param mixed   $answer
1286
-     * @param boolean $use_html_entities
1287
-     * @return string
1288
-     */
1289
-    private static function _generate_select_option_group($opt_group, $QSOs, $answer, $use_html_entities = true)
1290
-    {
1291
-        $html = "\n\t\t\t\t" . '<optgroup label="' . self::prep_option_value($opt_group) . '">';
1292
-        foreach ($QSOs as $QSO) {
1293
-            $html .= self::_generate_select_option($QSO->value(), $QSO->desc(), $answer, false, $use_html_entities);
1294
-        }
1295
-        $html .= "\n\t\t\t\t" . '</optgroup>';
1296
-        return $html;
1297
-    }
1298
-
1299
-
1300
-    /**
1301
-     *  _generate_select_option
1302
-     *
1303
-     * @param mixed   $key
1304
-     * @param mixed   $value
1305
-     * @param mixed   $answer
1306
-     * @param int     $only_option
1307
-     * @param boolean $use_html_entities
1308
-     * @return string
1309
-     */
1310
-    private static function _generate_select_option(
1311
-        $key,
1312
-        $value,
1313
-        $answer,
1314
-        $only_option = false,
1315
-        $use_html_entities = true
1316
-    ) {
1317
-        $key      = self::prep_answer($key, $use_html_entities);
1318
-        $value    = self::prep_answer($value, $use_html_entities);
1319
-        $value    = ! empty($value) ? $value : $key;
1320
-        $selected = ($answer == $key || $only_option) ? 'selected' : '';
1321
-        return "\n\t\t\t\t"
1322
-               . '<option value="' . self::prep_option_value($key) . '" ' . $selected . '> '
1323
-               . $value
1324
-               . '&nbsp;&nbsp;&nbsp;</option>';
1325
-    }
1326
-
1327
-
1328
-    /**
1329
-     * generates HTML for form radio button inputs
1330
-     *
1331
-     * @param string      $question    label content
1332
-     * @param string|int  $answer      form input value attribute
1333
-     * @param array|bool  $options     array of answer options where array key = option value and array value = option
1334
-     *                                 display text
1335
-     * @param string $name        form input name attribute
1336
-     * @param string      $id          form input css id attribute
1337
-     * @param string      $class       form input css class attribute
1338
-     * @param array|bool  $required    'label', 'class', and 'msg' - array of values for required "label" content, css
1339
-     *                                 required 'class', and required 'msg' attribute
1340
-     * @param string      $required_text
1341
-     * @param string      $label_class css class attribute for the label
1342
-     * @param bool|string $disabled    disabled="disabled" or null
1343
-     * @param string      $system_ID
1344
-     * @param bool        $use_html_entities
1345
-     * @param bool        $label_b4
1346
-     * @param bool        $use_desc_4_label
1347
-     * @return string HTML
1348
-     */
1349
-    public static function radio(
1350
-        string $question = '',
1351
-        $answer = null,
1352
-        $options = false,
1353
-        string $name = '',
1354
-        string $id = '',
1355
-        string $class = '',
1356
-        $required = false,
1357
-        string $required_text = '',
1358
-        string $label_class = '',
1359
-        bool $disabled = false,
1360
-        string $system_ID = '',
1361
-        bool $use_html_entities = true,
1362
-        bool $label_b4 = false,
1363
-        bool $use_desc_4_label = false,
1364
-        bool $add_mobile_label = false
1365
-    ) {
1366
-        // need these
1367
-        if (! $question || ! $name || ! $options || empty($options) || ! is_array($options)) {
1368
-            return null;
1369
-        }
1370
-        // prep the answer
1371
-        $answer = is_array($answer) ? '' : self::prep_answer($answer, $use_html_entities);
1372
-        // prep the required array
1373
-        $required = self::prep_required($required);
1374
-        // set disabled tag
1375
-        $disabled = $answer === null || ! $disabled ? '' : ' disabled="disabled"';
1376
-        // ya gots ta have style man!!!
1377
-        $radio_class = is_admin() ? 'ee-admin-radio-lbl' : $label_class;
1378
-        $class       = ! empty($class) ? $class : 'espresso-radio-btn-inp';
1379
-        $extra       = apply_filters('FHEE__EEH_Form_Fields__additional_form_field_attributes', '');
1380
-
1381
-        $label_html = self::label($question, $required_text, $required['label'], '', $label_class);
1382
-        $mobile_label = self::mobileLabel(
1383
-            $add_mobile_label,
1384
-            $question,
1385
-            $required_text,
1386
-            $required['label'],
1387
-            $label_class
1388
-        );
1389
-
1390
-        $input_html = $mobile_label
1391
-            . '<ul id="' . $id . '-ul" class="espresso-radio-btn-options-ul ' . $class . '-ul">';
1392
-
1393
-        $class .= ! empty($system_ID) ? ' ' . $system_ID : '';
1394
-        $class .= ! empty($required['class']) ? ' ' . $required['class'] : '';
1395
-
1396
-        foreach ($options as $OPT) {
1397
-            if ($OPT instanceof EE_Question_Option) {
1398
-                $value   = self::prep_option_value($OPT->value());
1399
-                $label   = $use_desc_4_label ? $OPT->desc() : $OPT->value();
1400
-                $size    = $use_desc_4_label
1401
-                    ? self::get_label_size_class($OPT->value() . ' ' . $OPT->desc())
1402
-                    : self::get_label_size_class($OPT->value());
1403
-                $desc    = $OPT->desc();// no self::prep_answer
1404
-                $answer  = is_numeric($value) && empty($answer) ? 0 : $answer;
1405
-                $value  = is_numeric($answer) && empty($value) ? 0 : $value;
1406
-                $checked = (string) $value == (string) $answer ? ' checked' : '';
1407
-                $opt     = '-' . sanitize_key($value);
1408
-
1409
-                $input_html .= "\n\t\t\t\t" . '<li' . $size . '>';
1410
-                $input_html .= "\n\t\t\t\t\t" . '<label class="' . $radio_class . ' espresso-radio-btn-lbl">';
1411
-                $input_html .= $label_b4 ? "\n\t\t\t\t\t\t" . '<span>' . $label . '</span>&nbsp;' : '';
1412
-                $input_html .= "\n\t\t\t\t\t\t"
1413
-                               . '<input type="radio" name="' . $name . '" id="' . $id . $opt . '" '
1414
-                               . 'class="' . $class . '" value="' . $value . '" '
1415
-                               . 'aria-label="' . esc_attr($required['msg']) . '" ' . $disabled
1416
-                               . $checked . ' ' . $extra . '/>';
1417
-                $input_html .= ! $label_b4
1418
-                    ? "\n\t\t\t\t\t\t"
1419
-                      . '&nbsp;<span class="espresso-radio-btn-desc">'
1420
-                      . $label
1421
-                      . '</span>'
1422
-                    : '';
1423
-                $input_html .= "\n\t\t\t\t\t" . '</label>';
1424
-                $input_html .= $use_desc_4_label
1425
-                    ? ''
1426
-                    : '<span class="espresso-radio-btn-option-desc small-text grey-text">' . $desc . '</span>';
1427
-                $input_html .= "\n\t\t\t\t" . '</li>';
1428
-            }
1429
-        }
1430
-
1431
-        $input_html .= "\n\t\t\t" . '</ul>';
1432
-
1433
-        $input_html = apply_filters('FHEE__EEH_Form_Fields__input_html', $input_html, $label_html, $id);
1434
-        return $label_html . $input_html;
1435
-    }
1436
-
1437
-
1438
-    /**
1439
-     * generates HTML for form checkbox inputs
1440
-     *
1441
-     * @param string $question    label content
1442
-     * @param string $answer      form input value attribute
1443
-     * @param array  $options     array of options where array key = option value and array value = option display text
1444
-     * @param string $name        form input name attribute
1445
-     * @param string $id          form input css id attribute
1446
-     * @param string $class       form input css class attribute
1447
-     * @param array  $required    'label', 'class', and 'msg' - array of values for required "label" content, css
1448
-     *                            required 'class', and required 'msg' attribute
1449
-     * @param string $label_class css class attribute for the label
1450
-     * @param string $disabled    disabled="disabled" or null
1451
-     * @return string HTML
1452
-     */
1453
-    public static function checkbox(
1454
-        $question = false,
1455
-        $answer = null,
1456
-        $options = false,
1457
-        $name = false,
1458
-        $id = '',
1459
-        $class = '',
1460
-        $required = false,
1461
-        $required_text = '',
1462
-        $label_class = '',
1463
-        $disabled = false,
1464
-        $label_b4 = false,
1465
-        $system_ID = false,
1466
-        $use_html_entities = true,
1467
-        $add_mobile_label = false
1468
-    ) {
1469
-        // need these
1470
-        if (! $question || ! $name || ! $options || empty($options) || ! is_array($options)) {
1471
-            return null;
1472
-        }
1473
-        $answer = maybe_unserialize($answer);
1474
-
1475
-        // prep the answer(s)
1476
-        $answer = is_array($answer) ? $answer : [sanitize_key($answer) => $answer];
1477
-
1478
-        foreach ($answer as $key => $value) {
1479
-            $key            = self::prep_option_value($key);
1480
-            $answer[ $key ] = self::prep_answer($value, $use_html_entities);
1481
-        }
1482
-
1483
-        // prep the required array
1484
-        $required = self::prep_required($required);
1485
-        // set disabled tag
1486
-        $disabled = $answer === null || ! $disabled ? '' : ' disabled="disabled"';
1487
-        // ya gots ta have style man!!!
1488
-        $radio_class = is_admin() ? 'ee-admin-radio-lbl' : $label_class;
1489
-        $class       = empty($class) ? 'espresso-radio-btn-inp' : $class;
1490
-        $extra       = apply_filters('FHEE__EEH_Form_Fields__additional_form_field_attributes', '');
1491
-
1492
-        $label_html   = self::label($question, $required_text, $required['label'], '', $label_class);
1493
-        $mobile_label = self::mobileLabel(
1494
-            $add_mobile_label,
1495
-            $question,
1496
-            $required_text,
1497
-            $required['label'],
1498
-            $label_class
1499
-        );
1500
-
1501
-        $input_html = $mobile_label
1502
-            . '<ul id="' . $id . '-ul" class="espresso-checkbox-options-ul ' . $class . '-ul">';
1503
-
1504
-        $class .= ! empty($system_ID) ? ' ' . $system_ID : '';
1505
-        $class .= ! empty($required['class']) ? ' ' . $required['class'] : '';
1506
-
1507
-        foreach ($options as $OPT) {
1508
-            $value = $OPT->value();// self::prep_option_value( $OPT->value() );
1509
-            $size  = self::get_label_size_class($OPT->value() . ' ' . $OPT->desc());
1510
-            $text  = self::prep_answer($OPT->value());
1511
-            $desc  = $OPT->desc();
1512
-            $opt   = '-' . sanitize_key($value);
1513
-
1514
-            $checked = is_array($answer) && in_array($text, $answer) ? ' checked' : '';
1515
-
1516
-            $input_html .= "\n\t\t\t\t" . '<li' . $size . '>';
1517
-            $input_html .= "\n\t\t\t\t\t" . '<label class="' . $radio_class . ' espresso-checkbox-lbl">';
1518
-            $input_html .= $label_b4 ? "\n\t\t\t\t\t\t" . '<span>' . $text . '</span>&nbsp;' : '';
1519
-            $input_html .= "\n\t\t\t\t\t\t"
1520
-                           . '<input type="checkbox" name="' . $name . '[' . $OPT->ID() . ']" '
1521
-                           . 'id="' . $id . $opt . '" class="' . $class . '" value="' . $value . '" '
1522
-                           . 'aria-label="' . esc_attr($required['msg']) . '" ' . $disabled . $checked . ' ' . $extra . '/>';
1523
-            $input_html .= ! $label_b4 ? "\n\t\t\t\t\t\t" . '&nbsp;<span>' . $text . '</span>' : '';
1524
-            $input_html .= "\n\t\t\t\t\t" . '</label>';
1525
-            if (! empty($desc) && $desc != $text) {
1526
-                $input_html .= "\n\t\t\t\t\t"
1527
-                               . ' &nbsp; <br/><div class="espresso-checkbox-option-desc small-text grey-text">'
1528
-                               . $desc
1529
-                               . '</div>';
1530
-            }
1531
-            $input_html .= "\n\t\t\t\t" . '</li>';
1532
-        }
1533
-
1534
-        $input_html .= "\n\t\t\t" . '</ul>';
1535
-
1536
-        $input_html = apply_filters('FHEE__EEH_Form_Fields__input_html', $input_html, $label_html, $id);
1537
-        return $label_html . $input_html;
1538
-    }
1539
-
1540
-
1541
-    /**
1542
-     * generates HTML for a form datepicker input
1543
-     *
1544
-     * @param string $question    label content
1545
-     * @param string $answer      form input value attribute
1546
-     * @param string $name        form input name attribute
1547
-     * @param string $id          form input css id attribute
1548
-     * @param string $class       form input css class attribute
1549
-     * @param array  $required    'label', 'class', and 'msg' - array of values for required "label" content, css
1550
-     *                            required 'class', and required 'msg' attribute
1551
-     * @param string $label_class css class attribute for the label
1552
-     * @param string $disabled    disabled="disabled" or null
1553
-     * @return string HTML
1554
-     */
1555
-    public static function datepicker(
1556
-        $question = false,
1557
-        $answer = null,
1558
-        $name = false,
1559
-        $id = '',
1560
-        $class = '',
1561
-        $required = false,
1562
-        $required_text = '',
1563
-        $label_class = '',
1564
-        $disabled = false,
1565
-        $system_ID = false,
1566
-        $use_html_entities = true,
1567
-        $add_mobile_label = false
1568
-    ) {
1569
-        // need these
1570
-        if (! $question || ! $name) {
1571
-            return null;
1572
-        }
1573
-        // prep the answer
1574
-        $answer = is_array($answer) ? '' : self::prep_answer($answer, $use_html_entities);
1575
-        // prep the required array
1576
-        $required = self::prep_required($required);
1577
-        // set disabled tag
1578
-        $disabled = $answer === null || ! $disabled ? '' : ' disabled="disabled"';
1579
-        // ya gots ta have style man!!!
1580
-        $txt_class = is_admin() ? 'regular-text' : 'espresso-datepicker-inp';
1581
-        $class     = empty($class) ? $txt_class : $class;
1582
-        $class     .= ! empty($system_ID) ? ' ' . $system_ID : '';
1583
-        $class = self::appendInputSizeClass($class, $answer);
1584
-        $extra     = apply_filters('FHEE__EEH_Form_Fields__additional_form_field_attributes', '');
1585
-
1586
-        $label_html   = self::label($question, $required_text, $required['label'], '', $label_class);
1587
-        $mobile_label = self::mobileLabel(
1588
-            $add_mobile_label,
1589
-            $question,
1590
-            $required_text,
1591
-            $required['label'],
1592
-            $label_class,
1593
-            $name
1594
-        );
1595
-
1596
-        $input_html = $mobile_label
1597
-            . '<input type="text" name="' . $name . '" id="' . $id . '" '
1598
-            . 'class="' . $class . ' ' . $required['class'] . ' datepicker" value="' . $answer . '"  '
1599
-            . 'aria-label="' . esc_attr($required['msg']) . '" ' . $disabled . ' ' . $extra . '/>';
1600
-
1601
-        // enqueue scripts
1602
-        wp_register_style(
1603
-            'espresso-ui-theme',
1604
-            EE_GLOBAL_ASSETS_URL . 'css/espresso-ui-theme/jquery-ui-1.10.3.custom.min.css',
1605
-            [],
1606
-            EVENT_ESPRESSO_VERSION
1607
-        );
1608
-        wp_enqueue_style('espresso-ui-theme');
1609
-        wp_enqueue_script('jquery-ui-datepicker');
1610
-
1611
-        $input_html = apply_filters('FHEE__EEH_Form_Fields__input_html', $input_html, $label_html, $id);
1612
-        return $label_html . $input_html;
1613
-    }
1614
-
1615
-
1616
-    /**
1617
-     *  remove_label_keep_required_msg
1618
-     *  this will strip out a form input's label HTML while keeping the required text HTML that MUST be before the label
1619
-     *
1620
-     * @access public
1621
-     * @return     string
1622
-     */
1623
-    public static function remove_label_keep_required_msg($label_html, $required_text)
1624
-    {
1625
-        return $required_text;
1626
-    }
1627
-
1628
-
1629
-    /**
1630
-     * Simply returns the HTML for a hidden input of the given name and value.
1631
-     *
1632
-     * @param string $name
1633
-     * @param string $value
1634
-     * @return string HTML
1635
-     */
1636
-    public static function hidden_input($name, $value, $id = '')
1637
-    {
1638
-        $id = ! empty($id) ? $id : $name;
1639
-        return '<input id="' . $id . '" type="hidden" name="' . $name . '" value="' . $value . '"/>';
1640
-    }
1641
-
1642
-
1643
-    /**
1644
-     * prep_question
1645
-     *
1646
-     * @param string $question
1647
-     * @return string
1648
-     */
1649
-    public static function prep_question($question)
1650
-    {
1651
-        return $question;
1652
-    }
1653
-
1654
-
1655
-    /**
1656
-     *  prep_answer
1657
-     *
1658
-     * @param mixed $answer
1659
-     * @return string
1660
-     */
1661
-    public static function prep_answer($answer, $use_html_entities = true)
1662
-    {
1663
-        // make sure we convert bools first.  Otherwise (bool) false becomes an empty string which is NOT desired,
1664
-        // we want "0".
1665
-        if (is_bool($answer)) {
1666
-            $answer = $answer ? 1 : 0;
1667
-        }
1668
-        $answer = trim(stripslashes(str_replace('&#039;', "'", $answer)));
1669
-        return $use_html_entities ? htmlentities($answer, ENT_QUOTES, 'UTF-8') : $answer;
1670
-    }
1671
-
1672
-
1673
-    /**
1674
-     *  prep_answer_options
1675
-     *
1676
-     * @param array $QSOs array of EE_Question_Option objects
1677
-     * @return array
1678
-     */
1679
-    public static function prep_answer_options($QSOs = [])
1680
-    {
1681
-        $prepped_answer_options = [];
1682
-        if (is_array($QSOs) && ! empty($QSOs)) {
1683
-            foreach ($QSOs as $key => $QSO) {
1684
-                if (! $QSO instanceof EE_Question_Option) {
1685
-                    $QSO = EE_Question_Option::new_instance(
1686
-                        [
1687
-                            'QSO_value' => is_array($QSO) && isset($QSO['id'])
1688
-                                ? (string) $QSO['id']
1689
-                                : (string) $key,
1690
-                            'QSO_desc'  => is_array($QSO) && isset($QSO['text'])
1691
-                                ? (string) $QSO['text']
1692
-                                : (string) $QSO,
1693
-                        ]
1694
-                    );
1695
-                }
1696
-                if ($QSO->opt_group()) {
1697
-                    $prepped_answer_options[ $QSO->opt_group() ][] = $QSO;
1698
-                } else {
1699
-                    $prepped_answer_options[] = $QSO;
1700
-                }
1701
-            }
1702
-        }
1703
-        //      d( $prepped_answer_options );
1704
-        return $prepped_answer_options;
1705
-    }
1706
-
1707
-
1708
-    /**
1709
-     *  prep_option_value
1710
-     *
1711
-     * @param string|int $option_value
1712
-     * @return string
1713
-     */
1714
-    public static function prep_option_value($option_value)
1715
-    {
1716
-        return esc_attr(trim(stripslashes($option_value)));
1717
-    }
1718
-
1719
-
1720
-    /**
1721
-     *  prep_required
1722
-     *
1723
-     * @param string|array $required
1724
-     * @return array
1725
-     */
1726
-    public static function prep_required($required = [])
1727
-    {
1728
-        // make sure required is an array
1729
-        $required = is_array($required) ? $required : [];
1730
-        // and set some defaults
1731
-        return array_merge(['label' => '', 'class' => '', 'msg' => ''], $required);
1732
-    }
1733
-
1734
-
1735
-    /**
1736
-     *  get_label_size_class
1737
-     *
1738
-     * @param string $value
1739
-     * @return string
1740
-     */
1741
-    public static function get_label_size_class($value = false)
1742
-    {
1743
-        if ($value === false || $value === '') {
1744
-            return ' class="medium-lbl"';
1745
-        }
1746
-        // determine length of option value
1747
-        $val_size = strlen($value);
1748
-        switch ($val_size) {
1749
-            case $val_size < 3:
1750
-                $size = ' class="nano-lbl"';
1751
-                break;
1752
-            case $val_size < 6:
1753
-                $size = ' class="micro-lbl"';
1754
-                break;
1755
-            case $val_size < 12:
1756
-                $size = ' class="tiny-lbl"';
1757
-                break;
1758
-            case $val_size < 25:
1759
-                $size = ' class="small-lbl"';
1760
-                break;
1761
-            case $val_size > 100:
1762
-                $size = ' class="big-lbl"';
1763
-                break;
1764
-            default:
1765
-                $size = ' class="medium-lbl"';
1766
-                break;
1767
-        }
1768
-        return $size;
1769
-    }
1770
-
1771
-
1772
-    /**
1773
-     *  _load_system_dropdowns
1774
-     *
1775
-     * @param EE_Question_Form_Input $QFI
1776
-     * @return array
1777
-     * @throws EE_Error
1778
-     * @throws ReflectionException
1779
-     */
1780
-    private static function _load_system_dropdowns($QFI)
1781
-    {
1782
-        $QST_system = $QFI->get('QST_system');
1783
-        switch ($QST_system) {
1784
-            case 'state':
1785
-                $QFI = self::generate_state_dropdown($QFI);
1786
-                break;
1787
-            case 'country':
1788
-                $QFI = self::generate_country_dropdown($QFI);
1789
-                break;
1790
-            case 'admin-state':
1791
-                $QFI = self::generate_state_dropdown($QFI, true);
1792
-                break;
1793
-            case 'admin-country':
1794
-                $QFI = self::generate_country_dropdown($QFI, true);
1795
-                break;
1796
-        }
1797
-        return $QFI;
1798
-    }
1799
-
1800
-
1801
-    /**
1802
-     * This preps dropdowns that are specialized.
1803
-     *
1804
-     * @param EE_Question_Form_Input $QFI
1805
-     *
1806
-     * @return EE_Question_Form_Input
1807
-     * @throws EE_Error
1808
-     * @throws ReflectionException
1809
-     * @since  4.6.0
1810
-     */
1811
-    protected static function _load_specialized_dropdowns($QFI)
1812
-    {
1813
-        switch ($QFI->get('QST_type')) {
1814
-            case 'STATE':
1815
-                $QFI = self::generate_state_dropdown($QFI);
1816
-                break;
1817
-            case 'COUNTRY':
1818
-                $QFI = self::generate_country_dropdown($QFI);
1819
-                break;
1820
-        }
1821
-        return $QFI;
1822
-    }
1823
-
1824
-
1825
-    /**
1826
-     *    generate_state_dropdown
1827
-     *
1828
-     * @param EE_Question_Form_Input $QST
1829
-     * @param bool                   $get_all
1830
-     * @return EE_Question_Form_Input
1831
-     * @throws EE_Error
1832
-     * @throws ReflectionException
1833
-     */
1834
-    public static function generate_state_dropdown($QST, $get_all = false)
1835
-    {
1836
-        $states = $get_all
1837
-            ? EEM_State::instance()->get_all_states()
1838
-            : EEM_State::instance()->get_all_states_of_active_countries();
1839
-        if ($states && count($states) != count($QST->options())) {
1840
-            $QST->set('QST_type', 'DROPDOWN');
1841
-            // if multiple countries, we'll create option groups within the dropdown
1842
-            foreach ($states as $state) {
1843
-                if ($state instanceof EE_State) {
1844
-                    $QSO = EE_Question_Option::new_instance(
1845
-                        [
1846
-                            'QSO_value'   => $state->ID(),
1847
-                            'QSO_desc'    => $state->name(),
1848
-                            'QST_ID'      => $QST->get('QST_ID'),
1849
-                            'QSO_deleted' => false,
1850
-                        ]
1851
-                    );
1852
-                    // set option group
1853
-                    $QSO->set_opt_group($state->country()->name());
1854
-                    // add option to question
1855
-                    $QST->add_temp_option($QSO);
1856
-                }
1857
-            }
1858
-        }
1859
-        return $QST;
1860
-    }
1861
-
1862
-
1863
-    /**
1864
-     *    generate_country_dropdown
1865
-     *
1866
-     * @param      $QST
1867
-     * @param bool $get_all
1868
-     * @return array
1869
-     * @throws EE_Error
1870
-     * @throws ReflectionException
1871
-     * @internal param array $question
1872
-     */
1873
-    public static function generate_country_dropdown($QST, $get_all = false)
1874
-    {
1875
-        $countries = $get_all
1876
-            ? EEM_Country::instance()->get_all_countries()
1877
-            : EEM_Country::instance()->get_all_active_countries();
1878
-        if ($countries && count($countries) != count($QST->options())) {
1879
-            $QST->set('QST_type', 'DROPDOWN');
1880
-            // now add countries
1881
-            foreach ($countries as $country) {
1882
-                if ($country instanceof EE_Country) {
1883
-                    $QSO = EE_Question_Option::new_instance(
1884
-                        [
1885
-                            'QSO_value'   => $country->ID(),
1886
-                            'QSO_desc'    => $country->name(),
1887
-                            'QST_ID'      => $QST->get('QST_ID'),
1888
-                            'QSO_deleted' => false,
1889
-                        ]
1890
-                    );
1891
-                    $QST->add_temp_option($QSO);
1892
-                }
1893
-            }
1894
-        }
1895
-        return $QST;
1896
-    }
1897
-
1898
-
1899
-    /**
1900
-     *  generates options for a month dropdown selector with numbers from 01 to 12
1901
-     *
1902
-     * @return array()
1903
-     */
1904
-    public static function two_digit_months_dropdown_options()
1905
-    {
1906
-        $options = [];
1907
-        for ($x = 1; $x <= 12; $x++) {
1908
-            $mm             = str_pad($x, 2, '0', STR_PAD_LEFT);
1909
-            $options[ $mm ] = $mm;
1910
-        }
1911
-        return EEH_Form_Fields::prep_answer_options($options);
1912
-    }
1913
-
1914
-
1915
-    /**
1916
-     *  generates a year dropdown selector with numbers for the next ten years
1917
-     *
1918
-     * @return array
1919
-     */
1920
-    public static function next_decade_two_digit_year_dropdown_options()
1921
-    {
1922
-        $options      = [];
1923
-        $current_year = date('y');
1924
-        $next_decade  = $current_year + 10;
1925
-        for ($x = $current_year; $x <= $next_decade; $x++) {
1926
-            $yy             = str_pad($x, 2, '0', STR_PAD_LEFT);
1927
-            $options[ $yy ] = $yy;
1928
-        }
1929
-        return EEH_Form_Fields::prep_answer_options($options);
1930
-    }
1931
-
1932
-
1933
-    /**
1934
-     * generates a month/year dropdown selector for all registrations matching the given criteria.  Typically used for
1935
-     * list table filter.
1936
-     *
1937
-     * @param string  $cur_date     any currently selected date can be entered here.
1938
-     * @param string  $status       Registration status
1939
-     * @param integer $evt_category Event Category ID if the Event Category filter is selected
1940
-     * @return string                html
1941
-     * @throws EE_Error
1942
-     */
1943
-    public static function generate_registration_months_dropdown($cur_date = '', $status = '', $evt_category = 0)
1944
-    {
1945
-        $_where = [];
1946
-        if (! empty($status)) {
1947
-            $_where['STS_ID'] = $status;
1948
-        }
1949
-
1950
-        if ($evt_category > 0) {
1951
-            $_where['Event.Term_Taxonomy.term_id'] = $evt_category;
1952
-        }
1953
-
1954
-        $regdtts = EEM_Registration::instance()->get_reg_months_and_years($_where);
1955
-
1956
-        // setup vals for select input helper
1957
-        $options = [
1958
-            0 => [
1959
-                'text' => esc_html__('Select a Month/Year', 'event_espresso'),
1960
-                'id'   => '',
1961
-            ],
1962
-        ];
1963
-
1964
-        foreach ($regdtts as $regdtt) {
1965
-            $date      = $regdtt->reg_month . ' ' . $regdtt->reg_year;
1966
-            $options[] = [
1967
-                'text' => $date,
1968
-                'id'   => $date,
1969
-            ];
1970
-        }
1971
-
1972
-        return self::select_input('month_range', $options, $cur_date);
1973
-    }
1974
-
1975
-
1976
-    /**
1977
-     * generates a month/year dropdown selector for all events matching the given criteria
1978
-     * Typically used for list table filter
1979
-     *
1980
-     * @param string $cur_date          any currently selected date can be entered here.
1981
-     * @param string $status            "view" (i.e. all, today, month, draft)
1982
-     * @param int    $evt_category      category event belongs to
1983
-     * @param string $evt_active_status "upcoming", "expired", "active", or "inactive"
1984
-     * @return string                    html
1985
-     * @throws EE_Error
1986
-     * @throws ReflectionException
1987
-     */
1988
-    public static function generate_event_months_dropdown(
1989
-        string $cur_date = '',
1990
-        string $status = 'all',
1991
-        int $evt_category = 0,
1992
-        string $evt_active_status = ''
1993
-    ): string {
1994
-        // determine what post_status our condition will have for the query.
1995
-        switch ($status) {
1996
-            case 'month':
1997
-            case 'today':
1998
-            case 'all':
1999
-                $where['Event.status'] = ['NOT IN', ['trash']];
2000
-                break;
2001
-            case 'draft':
2002
-                $where['Event.status'] = ['IN', ['draft', 'auto-draft']];
2003
-                break;
2004
-            default:
2005
-                $where['Event.status'] = $status;
2006
-        }
2007
-
2008
-        // categories?
2009
-        if (! empty($evt_category) and $evt_category > 0) {
2010
-            $where['Event.Term_Taxonomy.taxonomy'] = 'espresso_event_categories';
2011
-            $where['Event.Term_Taxonomy.term_id']  = $evt_category;
2012
-        }
2013
-
2014
-        //      $where['DTT_is_primary'] = 1;
2015
-
2016
-        $DTTS = EEM_Datetime::instance()->get_dtt_months_and_years($where, $evt_active_status);
2017
-
2018
-        // let's setup vals for select input helper
2019
-        $options = [
2020
-            0 => [
2021
-                'text' => esc_html__('Select a Month/Year', 'event_espresso'),
2022
-                'id'   => "",
2023
-            ],
2024
-        ];
2025
-
2026
-
2027
-        // translate month and date
2028
-        global $wp_locale;
2029
-
2030
-        foreach ($DTTS as $DTT) {
2031
-            $localized_date = $wp_locale->get_month($DTT->dtt_month_num) . ' ' . $DTT->dtt_year;
2032
-            $id             = $DTT->dtt_month . ' ' . $DTT->dtt_year;
2033
-            $options[]      = [
2034
-                'text' => $localized_date,
2035
-                'id'   => $id,
2036
-            ];
2037
-        }
2038
-
2039
-
2040
-        return self::select_input('month_range', $options, $cur_date);
2041
-    }
2042
-
2043
-
2044
-    /**
2045
-     * generates the dropdown selector for event categories
2046
-     * typically used as a filter on list tables.
2047
-     *
2048
-     * @param integer $current_cat currently selected category
2049
-     * @return string               html for dropdown
2050
-     * @throws EE_Error
2051
-     * @throws ReflectionException
2052
-     */
2053
-    public static function generate_event_category_dropdown($current_cat = -1)
2054
-    {
2055
-        $categories = EEM_Term::instance()->get_all_ee_categories(true);
2056
-        $options    = [
2057
-            '0' => [
2058
-                'text' => esc_html__('All Categories', 'event_espresso'),
2059
-                'id'   => -1,
2060
-            ],
2061
-        ];
2062
-
2063
-        // setup categories for dropdown
2064
-        foreach ($categories as $category) {
2065
-            $options[] = [
2066
-                'text' => $category->get('name'),
2067
-                'id'   => $category->ID(),
2068
-            ];
2069
-        }
2070
-
2071
-        return self::select_input('EVT_CAT', $options, $current_cat);
2072
-    }
2073
-
2074
-
2075
-    /**
2076
-     *    generate a submit button with or without it's own microform
2077
-     *    this is the only way to create buttons that are compatible across all themes
2078
-     *
2079
-     * @access    public
2080
-     * @param string      $url              - the form action
2081
-     * @param string      $ID               - some kind of unique ID, appended with "-sbmt" for the input and "-frm"
2082
-     *                                      for the form
2083
-     * @param string      $class            - css classes (separated by spaces if more than one)
2084
-     * @param string      $text             - what appears on the button
2085
-     * @param string      $nonce_action     - if using nonces
2086
-     * @param bool|string $input_only       - whether to print form header and footer. TRUE returns the input without
2087
-     *                                      the form
2088
-     * @param string      $extra_attributes - any extra attributes that need to be attached to the form input
2089
-     * @return    string
2090
-     */
2091
-    public static function submit_button(
2092
-        $url = '',
2093
-        $ID = '',
2094
-        $class = '',
2095
-        $text = '',
2096
-        $nonce_action = '',
2097
-        $input_only = false,
2098
-        $extra_attributes = ''
2099
-    ) {
2100
-        $btn = '';
2101
-        if (empty($url) || empty($ID)) {
2102
-            return $btn;
2103
-        }
2104
-        $text = ! empty($text) ? $text : esc_html__('Submit', 'event_espresso');
2105
-        $btn  .= '<input id="' . $ID . '-btn" class="' . $class . '" '
2106
-                 . 'type="submit" value="' . $text . '" ' . $extra_attributes . '/>';
2107
-        if (! $input_only) {
2108
-            $btn_frm = '<form id="' . $ID . '-frm" method="POST" action="' . $url . '">';
2109
-            $btn_frm .= ! empty($nonce_action)
2110
-                ? wp_nonce_field($nonce_action, $nonce_action . '_nonce', true, false)
2111
-                : '';
2112
-            $btn_frm .= $btn;
2113
-            $btn_frm .= '</form>';
2114
-            $btn     = $btn_frm;
2115
-            unset($btn_frm);
2116
-        }
2117
-        return $btn;
2118
-    }
1089
+		$input_html = apply_filters('FHEE__EEH_Form_Fields__input_html', $input_html, $label_html, $id);
1090
+		return $label_html . $input_html;
1091
+	}
1092
+
1093
+
1094
+	/**
1095
+	 * generates HTML for a form textarea
1096
+	 *
1097
+	 * @param string $question    label content
1098
+	 * @param string $answer      form input value attribute
1099
+	 * @param string $name        form input name attribute
1100
+	 * @param string $id          form input css id attribute
1101
+	 * @param string $class       form input css class attribute
1102
+	 * @param array  $dimensions  array of form input rows and cols attributes : array( 'rows' => 3, 'cols' => 40 )
1103
+	 * @param array  $required    'label', 'class', and 'msg' - array of values for required "label" content, css
1104
+	 *                            required 'class', and required 'msg' attribute
1105
+	 * @param string $label_class css class attribute for the label
1106
+	 * @param string $disabled    disabled="disabled" or null
1107
+	 * @return string HTML
1108
+	 */
1109
+	public static function textarea(
1110
+		$question = false,
1111
+		$answer = null,
1112
+		$name = false,
1113
+		$id = '',
1114
+		$class = '',
1115
+		$dimensions = false,
1116
+		$required = false,
1117
+		$required_text = '',
1118
+		$label_class = '',
1119
+		$disabled = false,
1120
+		$system_ID = false,
1121
+		$use_html_entities = true,
1122
+		$add_mobile_label = false
1123
+	) {
1124
+		// need these
1125
+		if (! $question || ! $name) {
1126
+			return null;
1127
+		}
1128
+		// prep the answer
1129
+		$answer = is_array($answer) ? '' : self::prep_answer($answer, $use_html_entities);
1130
+		// prep the required array
1131
+		$required = self::prep_required($required);
1132
+		// make sure $dimensions is an array
1133
+		$dimensions = is_array($dimensions) ? $dimensions : [];
1134
+		// and set some defaults
1135
+		$dimensions = array_merge(['rows' => 3, 'cols' => 40], $dimensions);
1136
+		// set disabled tag
1137
+		$disabled = $answer === null || ! $disabled ? '' : ' disabled="disabled"';
1138
+		// ya gots ta have style man!!!
1139
+		$class     .= ! empty($system_ID) ? ' ' . $system_ID : '';
1140
+		$class     .= ! empty($required['class']) ? ' ' . $required['class'] : '';
1141
+		$extra     = apply_filters('FHEE__EEH_Form_Fields__additional_form_field_attributes', '');
1142
+
1143
+		$label_html   = self::label($question, $required_text, $required['label'], $name, $label_class);
1144
+		$mobile_label = self::mobileLabel(
1145
+			$add_mobile_label,
1146
+			$question,
1147
+			$required_text,
1148
+			$required['label'],
1149
+			$label_class,
1150
+			$name
1151
+		);
1152
+
1153
+		$input_html = $mobile_label
1154
+			. '<textarea name="' . $name . '" id="' . $id . '" class="' . trim($class) . '" '
1155
+			. 'rows="' . $dimensions['rows'] . '" cols="' . $dimensions['cols'] . '"  '
1156
+			. 'aria-label="' . $required['msg'] . '" ' . $disabled . ' ' . $extra . '>'
1157
+			 . esc_textarea($answer)
1158
+			  . '</textarea>';
1159
+
1160
+		$input_html = apply_filters('FHEE__EEH_Form_Fields__input_html', $input_html, $label_html, $id);
1161
+		return $label_html . $input_html;
1162
+	}
1163
+
1164
+
1165
+	/**
1166
+	 * generates HTML for a form select input
1167
+	 *
1168
+	 * @param string $question    label content
1169
+	 * @param string $answer      form input value attribute
1170
+	 * @param array  $options     array of answer options where array key = option value and array value = option
1171
+	 *                            display text
1172
+	 * @param string $name        form input name attribute
1173
+	 * @param string $id          form input css id attribute
1174
+	 * @param string $class       form input css class attribute
1175
+	 * @param array  $required    'label', 'class', and 'msg' - array of values for required "label" content, css
1176
+	 *                            required 'class', and required 'msg' attribute
1177
+	 * @param string $label_class css class attribute for the label
1178
+	 * @param string $disabled    disabled="disabled" or null
1179
+	 * @return string HTML
1180
+	 */
1181
+	public static function select(
1182
+		$question = false,
1183
+		$answer = null,
1184
+		$options = false,
1185
+		$name = false,
1186
+		$id = '',
1187
+		$class = '',
1188
+		$required = false,
1189
+		$required_text = '',
1190
+		$label_class = '',
1191
+		$disabled = false,
1192
+		$system_ID = false,
1193
+		$use_html_entities = true,
1194
+		$add_please_select_option = false,
1195
+		$add_mobile_label = false
1196
+	) {
1197
+
1198
+		// need these
1199
+		if (! $question || ! $name || ! $options || empty($options) || ! is_array($options)) {
1200
+			return null;
1201
+		}
1202
+		// prep the answer
1203
+		$answer = is_array($answer)
1204
+			? self::prep_answer(array_shift($answer), $use_html_entities)
1205
+			: self::prep_answer($answer, $use_html_entities);
1206
+		// prep the required array
1207
+		$required = self::prep_required($required);
1208
+		// set disabled tag
1209
+		$disabled = $answer === null || ! $disabled ? '' : ' disabled="disabled"';
1210
+		// ya gots ta have style man!!!
1211
+		$class     .= ! empty($system_ID) ? ' ' . $system_ID : '';
1212
+		$class = self::appendInputSizeClass($class, $options);
1213
+		$extra     = apply_filters('FHEE__EEH_Form_Fields__additional_form_field_attributes', '');
1214
+
1215
+		$label_html   = self::label($question, $required_text, $required['label'], $name, $label_class);
1216
+		$mobile_label = self::mobileLabel(
1217
+			$add_mobile_label,
1218
+			$question,
1219
+			$required_text,
1220
+			$required['label'],
1221
+			$label_class,
1222
+			$name
1223
+		);
1224
+
1225
+		$input_html = $mobile_label
1226
+			. '<select name="' . $name . '" id="' . $id . '" class="' . trim($class) . ' ' . $required['class'] . '" '
1227
+			. 'aria-label="' . esc_attr($required['msg']) . '"' . $disabled . ' ' . $extra . '>';
1228
+		// recursively count array elements, to determine total number of options
1229
+		$only_option = count($options, 1) == 1;
1230
+		if (! $only_option) {
1231
+			// if there is NO answer set and there are multiple options to choose from, then set the "please select" message as selected
1232
+			$selected   = $answer === null ? ' selected' : '';
1233
+			$input_html .= $add_please_select_option
1234
+				? "\n\t\t\t\t"
1235
+				  . '<option value=""' . $selected . '>'
1236
+				  . esc_html__(' - please select - ', 'event_espresso')
1237
+				  . '</option>'
1238
+				: '';
1239
+		}
1240
+		foreach ($options as $key => $value) {
1241
+			// if value is an array, then create option groups, else create regular ol' options
1242
+			$input_html .= is_array($value)
1243
+				? self::_generate_select_option_group(
1244
+					$key,
1245
+					$value,
1246
+					$answer,
1247
+					$use_html_entities
1248
+				)
1249
+				: self::_generate_select_option(
1250
+					$value->value(),
1251
+					$value->desc(),
1252
+					$answer,
1253
+					$only_option,
1254
+					$use_html_entities
1255
+				);
1256
+		}
1257
+
1258
+		$input_html .= "\n\t\t\t" . '</select>';
1259
+
1260
+		$input_html =
1261
+			apply_filters(
1262
+				'FHEE__EEH_Form_Fields__select__before_end_wrapper',
1263
+				$input_html,
1264
+				$question,
1265
+				$answer,
1266
+				$name,
1267
+				$id,
1268
+				$class,
1269
+				$system_ID
1270
+			);
1271
+
1272
+		$input_html = apply_filters('FHEE__EEH_Form_Fields__input_html', $input_html, $label_html, $id);
1273
+		return $label_html . $input_html;
1274
+	}
1275
+
1276
+
1277
+	/**
1278
+	 *  _generate_select_option_group
1279
+	 *
1280
+	 *  if  $value for a select box is an array, then the key will be used as the optgroup label
1281
+	 *  and the value array will be looped thru and the elements sent to _generate_select_option
1282
+	 *
1283
+	 * @param mixed   $opt_group
1284
+	 * @param mixed   $QSOs
1285
+	 * @param mixed   $answer
1286
+	 * @param boolean $use_html_entities
1287
+	 * @return string
1288
+	 */
1289
+	private static function _generate_select_option_group($opt_group, $QSOs, $answer, $use_html_entities = true)
1290
+	{
1291
+		$html = "\n\t\t\t\t" . '<optgroup label="' . self::prep_option_value($opt_group) . '">';
1292
+		foreach ($QSOs as $QSO) {
1293
+			$html .= self::_generate_select_option($QSO->value(), $QSO->desc(), $answer, false, $use_html_entities);
1294
+		}
1295
+		$html .= "\n\t\t\t\t" . '</optgroup>';
1296
+		return $html;
1297
+	}
1298
+
1299
+
1300
+	/**
1301
+	 *  _generate_select_option
1302
+	 *
1303
+	 * @param mixed   $key
1304
+	 * @param mixed   $value
1305
+	 * @param mixed   $answer
1306
+	 * @param int     $only_option
1307
+	 * @param boolean $use_html_entities
1308
+	 * @return string
1309
+	 */
1310
+	private static function _generate_select_option(
1311
+		$key,
1312
+		$value,
1313
+		$answer,
1314
+		$only_option = false,
1315
+		$use_html_entities = true
1316
+	) {
1317
+		$key      = self::prep_answer($key, $use_html_entities);
1318
+		$value    = self::prep_answer($value, $use_html_entities);
1319
+		$value    = ! empty($value) ? $value : $key;
1320
+		$selected = ($answer == $key || $only_option) ? 'selected' : '';
1321
+		return "\n\t\t\t\t"
1322
+			   . '<option value="' . self::prep_option_value($key) . '" ' . $selected . '> '
1323
+			   . $value
1324
+			   . '&nbsp;&nbsp;&nbsp;</option>';
1325
+	}
1326
+
1327
+
1328
+	/**
1329
+	 * generates HTML for form radio button inputs
1330
+	 *
1331
+	 * @param string      $question    label content
1332
+	 * @param string|int  $answer      form input value attribute
1333
+	 * @param array|bool  $options     array of answer options where array key = option value and array value = option
1334
+	 *                                 display text
1335
+	 * @param string $name        form input name attribute
1336
+	 * @param string      $id          form input css id attribute
1337
+	 * @param string      $class       form input css class attribute
1338
+	 * @param array|bool  $required    'label', 'class', and 'msg' - array of values for required "label" content, css
1339
+	 *                                 required 'class', and required 'msg' attribute
1340
+	 * @param string      $required_text
1341
+	 * @param string      $label_class css class attribute for the label
1342
+	 * @param bool|string $disabled    disabled="disabled" or null
1343
+	 * @param string      $system_ID
1344
+	 * @param bool        $use_html_entities
1345
+	 * @param bool        $label_b4
1346
+	 * @param bool        $use_desc_4_label
1347
+	 * @return string HTML
1348
+	 */
1349
+	public static function radio(
1350
+		string $question = '',
1351
+		$answer = null,
1352
+		$options = false,
1353
+		string $name = '',
1354
+		string $id = '',
1355
+		string $class = '',
1356
+		$required = false,
1357
+		string $required_text = '',
1358
+		string $label_class = '',
1359
+		bool $disabled = false,
1360
+		string $system_ID = '',
1361
+		bool $use_html_entities = true,
1362
+		bool $label_b4 = false,
1363
+		bool $use_desc_4_label = false,
1364
+		bool $add_mobile_label = false
1365
+	) {
1366
+		// need these
1367
+		if (! $question || ! $name || ! $options || empty($options) || ! is_array($options)) {
1368
+			return null;
1369
+		}
1370
+		// prep the answer
1371
+		$answer = is_array($answer) ? '' : self::prep_answer($answer, $use_html_entities);
1372
+		// prep the required array
1373
+		$required = self::prep_required($required);
1374
+		// set disabled tag
1375
+		$disabled = $answer === null || ! $disabled ? '' : ' disabled="disabled"';
1376
+		// ya gots ta have style man!!!
1377
+		$radio_class = is_admin() ? 'ee-admin-radio-lbl' : $label_class;
1378
+		$class       = ! empty($class) ? $class : 'espresso-radio-btn-inp';
1379
+		$extra       = apply_filters('FHEE__EEH_Form_Fields__additional_form_field_attributes', '');
1380
+
1381
+		$label_html = self::label($question, $required_text, $required['label'], '', $label_class);
1382
+		$mobile_label = self::mobileLabel(
1383
+			$add_mobile_label,
1384
+			$question,
1385
+			$required_text,
1386
+			$required['label'],
1387
+			$label_class
1388
+		);
1389
+
1390
+		$input_html = $mobile_label
1391
+			. '<ul id="' . $id . '-ul" class="espresso-radio-btn-options-ul ' . $class . '-ul">';
1392
+
1393
+		$class .= ! empty($system_ID) ? ' ' . $system_ID : '';
1394
+		$class .= ! empty($required['class']) ? ' ' . $required['class'] : '';
1395
+
1396
+		foreach ($options as $OPT) {
1397
+			if ($OPT instanceof EE_Question_Option) {
1398
+				$value   = self::prep_option_value($OPT->value());
1399
+				$label   = $use_desc_4_label ? $OPT->desc() : $OPT->value();
1400
+				$size    = $use_desc_4_label
1401
+					? self::get_label_size_class($OPT->value() . ' ' . $OPT->desc())
1402
+					: self::get_label_size_class($OPT->value());
1403
+				$desc    = $OPT->desc();// no self::prep_answer
1404
+				$answer  = is_numeric($value) && empty($answer) ? 0 : $answer;
1405
+				$value  = is_numeric($answer) && empty($value) ? 0 : $value;
1406
+				$checked = (string) $value == (string) $answer ? ' checked' : '';
1407
+				$opt     = '-' . sanitize_key($value);
1408
+
1409
+				$input_html .= "\n\t\t\t\t" . '<li' . $size . '>';
1410
+				$input_html .= "\n\t\t\t\t\t" . '<label class="' . $radio_class . ' espresso-radio-btn-lbl">';
1411
+				$input_html .= $label_b4 ? "\n\t\t\t\t\t\t" . '<span>' . $label . '</span>&nbsp;' : '';
1412
+				$input_html .= "\n\t\t\t\t\t\t"
1413
+							   . '<input type="radio" name="' . $name . '" id="' . $id . $opt . '" '
1414
+							   . 'class="' . $class . '" value="' . $value . '" '
1415
+							   . 'aria-label="' . esc_attr($required['msg']) . '" ' . $disabled
1416
+							   . $checked . ' ' . $extra . '/>';
1417
+				$input_html .= ! $label_b4
1418
+					? "\n\t\t\t\t\t\t"
1419
+					  . '&nbsp;<span class="espresso-radio-btn-desc">'
1420
+					  . $label
1421
+					  . '</span>'
1422
+					: '';
1423
+				$input_html .= "\n\t\t\t\t\t" . '</label>';
1424
+				$input_html .= $use_desc_4_label
1425
+					? ''
1426
+					: '<span class="espresso-radio-btn-option-desc small-text grey-text">' . $desc . '</span>';
1427
+				$input_html .= "\n\t\t\t\t" . '</li>';
1428
+			}
1429
+		}
1430
+
1431
+		$input_html .= "\n\t\t\t" . '</ul>';
1432
+
1433
+		$input_html = apply_filters('FHEE__EEH_Form_Fields__input_html', $input_html, $label_html, $id);
1434
+		return $label_html . $input_html;
1435
+	}
1436
+
1437
+
1438
+	/**
1439
+	 * generates HTML for form checkbox inputs
1440
+	 *
1441
+	 * @param string $question    label content
1442
+	 * @param string $answer      form input value attribute
1443
+	 * @param array  $options     array of options where array key = option value and array value = option display text
1444
+	 * @param string $name        form input name attribute
1445
+	 * @param string $id          form input css id attribute
1446
+	 * @param string $class       form input css class attribute
1447
+	 * @param array  $required    'label', 'class', and 'msg' - array of values for required "label" content, css
1448
+	 *                            required 'class', and required 'msg' attribute
1449
+	 * @param string $label_class css class attribute for the label
1450
+	 * @param string $disabled    disabled="disabled" or null
1451
+	 * @return string HTML
1452
+	 */
1453
+	public static function checkbox(
1454
+		$question = false,
1455
+		$answer = null,
1456
+		$options = false,
1457
+		$name = false,
1458
+		$id = '',
1459
+		$class = '',
1460
+		$required = false,
1461
+		$required_text = '',
1462
+		$label_class = '',
1463
+		$disabled = false,
1464
+		$label_b4 = false,
1465
+		$system_ID = false,
1466
+		$use_html_entities = true,
1467
+		$add_mobile_label = false
1468
+	) {
1469
+		// need these
1470
+		if (! $question || ! $name || ! $options || empty($options) || ! is_array($options)) {
1471
+			return null;
1472
+		}
1473
+		$answer = maybe_unserialize($answer);
1474
+
1475
+		// prep the answer(s)
1476
+		$answer = is_array($answer) ? $answer : [sanitize_key($answer) => $answer];
1477
+
1478
+		foreach ($answer as $key => $value) {
1479
+			$key            = self::prep_option_value($key);
1480
+			$answer[ $key ] = self::prep_answer($value, $use_html_entities);
1481
+		}
1482
+
1483
+		// prep the required array
1484
+		$required = self::prep_required($required);
1485
+		// set disabled tag
1486
+		$disabled = $answer === null || ! $disabled ? '' : ' disabled="disabled"';
1487
+		// ya gots ta have style man!!!
1488
+		$radio_class = is_admin() ? 'ee-admin-radio-lbl' : $label_class;
1489
+		$class       = empty($class) ? 'espresso-radio-btn-inp' : $class;
1490
+		$extra       = apply_filters('FHEE__EEH_Form_Fields__additional_form_field_attributes', '');
1491
+
1492
+		$label_html   = self::label($question, $required_text, $required['label'], '', $label_class);
1493
+		$mobile_label = self::mobileLabel(
1494
+			$add_mobile_label,
1495
+			$question,
1496
+			$required_text,
1497
+			$required['label'],
1498
+			$label_class
1499
+		);
1500
+
1501
+		$input_html = $mobile_label
1502
+			. '<ul id="' . $id . '-ul" class="espresso-checkbox-options-ul ' . $class . '-ul">';
1503
+
1504
+		$class .= ! empty($system_ID) ? ' ' . $system_ID : '';
1505
+		$class .= ! empty($required['class']) ? ' ' . $required['class'] : '';
1506
+
1507
+		foreach ($options as $OPT) {
1508
+			$value = $OPT->value();// self::prep_option_value( $OPT->value() );
1509
+			$size  = self::get_label_size_class($OPT->value() . ' ' . $OPT->desc());
1510
+			$text  = self::prep_answer($OPT->value());
1511
+			$desc  = $OPT->desc();
1512
+			$opt   = '-' . sanitize_key($value);
1513
+
1514
+			$checked = is_array($answer) && in_array($text, $answer) ? ' checked' : '';
1515
+
1516
+			$input_html .= "\n\t\t\t\t" . '<li' . $size . '>';
1517
+			$input_html .= "\n\t\t\t\t\t" . '<label class="' . $radio_class . ' espresso-checkbox-lbl">';
1518
+			$input_html .= $label_b4 ? "\n\t\t\t\t\t\t" . '<span>' . $text . '</span>&nbsp;' : '';
1519
+			$input_html .= "\n\t\t\t\t\t\t"
1520
+						   . '<input type="checkbox" name="' . $name . '[' . $OPT->ID() . ']" '
1521
+						   . 'id="' . $id . $opt . '" class="' . $class . '" value="' . $value . '" '
1522
+						   . 'aria-label="' . esc_attr($required['msg']) . '" ' . $disabled . $checked . ' ' . $extra . '/>';
1523
+			$input_html .= ! $label_b4 ? "\n\t\t\t\t\t\t" . '&nbsp;<span>' . $text . '</span>' : '';
1524
+			$input_html .= "\n\t\t\t\t\t" . '</label>';
1525
+			if (! empty($desc) && $desc != $text) {
1526
+				$input_html .= "\n\t\t\t\t\t"
1527
+							   . ' &nbsp; <br/><div class="espresso-checkbox-option-desc small-text grey-text">'
1528
+							   . $desc
1529
+							   . '</div>';
1530
+			}
1531
+			$input_html .= "\n\t\t\t\t" . '</li>';
1532
+		}
1533
+
1534
+		$input_html .= "\n\t\t\t" . '</ul>';
1535
+
1536
+		$input_html = apply_filters('FHEE__EEH_Form_Fields__input_html', $input_html, $label_html, $id);
1537
+		return $label_html . $input_html;
1538
+	}
1539
+
1540
+
1541
+	/**
1542
+	 * generates HTML for a form datepicker input
1543
+	 *
1544
+	 * @param string $question    label content
1545
+	 * @param string $answer      form input value attribute
1546
+	 * @param string $name        form input name attribute
1547
+	 * @param string $id          form input css id attribute
1548
+	 * @param string $class       form input css class attribute
1549
+	 * @param array  $required    'label', 'class', and 'msg' - array of values for required "label" content, css
1550
+	 *                            required 'class', and required 'msg' attribute
1551
+	 * @param string $label_class css class attribute for the label
1552
+	 * @param string $disabled    disabled="disabled" or null
1553
+	 * @return string HTML
1554
+	 */
1555
+	public static function datepicker(
1556
+		$question = false,
1557
+		$answer = null,
1558
+		$name = false,
1559
+		$id = '',
1560
+		$class = '',
1561
+		$required = false,
1562
+		$required_text = '',
1563
+		$label_class = '',
1564
+		$disabled = false,
1565
+		$system_ID = false,
1566
+		$use_html_entities = true,
1567
+		$add_mobile_label = false
1568
+	) {
1569
+		// need these
1570
+		if (! $question || ! $name) {
1571
+			return null;
1572
+		}
1573
+		// prep the answer
1574
+		$answer = is_array($answer) ? '' : self::prep_answer($answer, $use_html_entities);
1575
+		// prep the required array
1576
+		$required = self::prep_required($required);
1577
+		// set disabled tag
1578
+		$disabled = $answer === null || ! $disabled ? '' : ' disabled="disabled"';
1579
+		// ya gots ta have style man!!!
1580
+		$txt_class = is_admin() ? 'regular-text' : 'espresso-datepicker-inp';
1581
+		$class     = empty($class) ? $txt_class : $class;
1582
+		$class     .= ! empty($system_ID) ? ' ' . $system_ID : '';
1583
+		$class = self::appendInputSizeClass($class, $answer);
1584
+		$extra     = apply_filters('FHEE__EEH_Form_Fields__additional_form_field_attributes', '');
1585
+
1586
+		$label_html   = self::label($question, $required_text, $required['label'], '', $label_class);
1587
+		$mobile_label = self::mobileLabel(
1588
+			$add_mobile_label,
1589
+			$question,
1590
+			$required_text,
1591
+			$required['label'],
1592
+			$label_class,
1593
+			$name
1594
+		);
1595
+
1596
+		$input_html = $mobile_label
1597
+			. '<input type="text" name="' . $name . '" id="' . $id . '" '
1598
+			. 'class="' . $class . ' ' . $required['class'] . ' datepicker" value="' . $answer . '"  '
1599
+			. 'aria-label="' . esc_attr($required['msg']) . '" ' . $disabled . ' ' . $extra . '/>';
1600
+
1601
+		// enqueue scripts
1602
+		wp_register_style(
1603
+			'espresso-ui-theme',
1604
+			EE_GLOBAL_ASSETS_URL . 'css/espresso-ui-theme/jquery-ui-1.10.3.custom.min.css',
1605
+			[],
1606
+			EVENT_ESPRESSO_VERSION
1607
+		);
1608
+		wp_enqueue_style('espresso-ui-theme');
1609
+		wp_enqueue_script('jquery-ui-datepicker');
1610
+
1611
+		$input_html = apply_filters('FHEE__EEH_Form_Fields__input_html', $input_html, $label_html, $id);
1612
+		return $label_html . $input_html;
1613
+	}
1614
+
1615
+
1616
+	/**
1617
+	 *  remove_label_keep_required_msg
1618
+	 *  this will strip out a form input's label HTML while keeping the required text HTML that MUST be before the label
1619
+	 *
1620
+	 * @access public
1621
+	 * @return     string
1622
+	 */
1623
+	public static function remove_label_keep_required_msg($label_html, $required_text)
1624
+	{
1625
+		return $required_text;
1626
+	}
1627
+
1628
+
1629
+	/**
1630
+	 * Simply returns the HTML for a hidden input of the given name and value.
1631
+	 *
1632
+	 * @param string $name
1633
+	 * @param string $value
1634
+	 * @return string HTML
1635
+	 */
1636
+	public static function hidden_input($name, $value, $id = '')
1637
+	{
1638
+		$id = ! empty($id) ? $id : $name;
1639
+		return '<input id="' . $id . '" type="hidden" name="' . $name . '" value="' . $value . '"/>';
1640
+	}
1641
+
1642
+
1643
+	/**
1644
+	 * prep_question
1645
+	 *
1646
+	 * @param string $question
1647
+	 * @return string
1648
+	 */
1649
+	public static function prep_question($question)
1650
+	{
1651
+		return $question;
1652
+	}
1653
+
1654
+
1655
+	/**
1656
+	 *  prep_answer
1657
+	 *
1658
+	 * @param mixed $answer
1659
+	 * @return string
1660
+	 */
1661
+	public static function prep_answer($answer, $use_html_entities = true)
1662
+	{
1663
+		// make sure we convert bools first.  Otherwise (bool) false becomes an empty string which is NOT desired,
1664
+		// we want "0".
1665
+		if (is_bool($answer)) {
1666
+			$answer = $answer ? 1 : 0;
1667
+		}
1668
+		$answer = trim(stripslashes(str_replace('&#039;', "'", $answer)));
1669
+		return $use_html_entities ? htmlentities($answer, ENT_QUOTES, 'UTF-8') : $answer;
1670
+	}
1671
+
1672
+
1673
+	/**
1674
+	 *  prep_answer_options
1675
+	 *
1676
+	 * @param array $QSOs array of EE_Question_Option objects
1677
+	 * @return array
1678
+	 */
1679
+	public static function prep_answer_options($QSOs = [])
1680
+	{
1681
+		$prepped_answer_options = [];
1682
+		if (is_array($QSOs) && ! empty($QSOs)) {
1683
+			foreach ($QSOs as $key => $QSO) {
1684
+				if (! $QSO instanceof EE_Question_Option) {
1685
+					$QSO = EE_Question_Option::new_instance(
1686
+						[
1687
+							'QSO_value' => is_array($QSO) && isset($QSO['id'])
1688
+								? (string) $QSO['id']
1689
+								: (string) $key,
1690
+							'QSO_desc'  => is_array($QSO) && isset($QSO['text'])
1691
+								? (string) $QSO['text']
1692
+								: (string) $QSO,
1693
+						]
1694
+					);
1695
+				}
1696
+				if ($QSO->opt_group()) {
1697
+					$prepped_answer_options[ $QSO->opt_group() ][] = $QSO;
1698
+				} else {
1699
+					$prepped_answer_options[] = $QSO;
1700
+				}
1701
+			}
1702
+		}
1703
+		//      d( $prepped_answer_options );
1704
+		return $prepped_answer_options;
1705
+	}
1706
+
1707
+
1708
+	/**
1709
+	 *  prep_option_value
1710
+	 *
1711
+	 * @param string|int $option_value
1712
+	 * @return string
1713
+	 */
1714
+	public static function prep_option_value($option_value)
1715
+	{
1716
+		return esc_attr(trim(stripslashes($option_value)));
1717
+	}
1718
+
1719
+
1720
+	/**
1721
+	 *  prep_required
1722
+	 *
1723
+	 * @param string|array $required
1724
+	 * @return array
1725
+	 */
1726
+	public static function prep_required($required = [])
1727
+	{
1728
+		// make sure required is an array
1729
+		$required = is_array($required) ? $required : [];
1730
+		// and set some defaults
1731
+		return array_merge(['label' => '', 'class' => '', 'msg' => ''], $required);
1732
+	}
1733
+
1734
+
1735
+	/**
1736
+	 *  get_label_size_class
1737
+	 *
1738
+	 * @param string $value
1739
+	 * @return string
1740
+	 */
1741
+	public static function get_label_size_class($value = false)
1742
+	{
1743
+		if ($value === false || $value === '') {
1744
+			return ' class="medium-lbl"';
1745
+		}
1746
+		// determine length of option value
1747
+		$val_size = strlen($value);
1748
+		switch ($val_size) {
1749
+			case $val_size < 3:
1750
+				$size = ' class="nano-lbl"';
1751
+				break;
1752
+			case $val_size < 6:
1753
+				$size = ' class="micro-lbl"';
1754
+				break;
1755
+			case $val_size < 12:
1756
+				$size = ' class="tiny-lbl"';
1757
+				break;
1758
+			case $val_size < 25:
1759
+				$size = ' class="small-lbl"';
1760
+				break;
1761
+			case $val_size > 100:
1762
+				$size = ' class="big-lbl"';
1763
+				break;
1764
+			default:
1765
+				$size = ' class="medium-lbl"';
1766
+				break;
1767
+		}
1768
+		return $size;
1769
+	}
1770
+
1771
+
1772
+	/**
1773
+	 *  _load_system_dropdowns
1774
+	 *
1775
+	 * @param EE_Question_Form_Input $QFI
1776
+	 * @return array
1777
+	 * @throws EE_Error
1778
+	 * @throws ReflectionException
1779
+	 */
1780
+	private static function _load_system_dropdowns($QFI)
1781
+	{
1782
+		$QST_system = $QFI->get('QST_system');
1783
+		switch ($QST_system) {
1784
+			case 'state':
1785
+				$QFI = self::generate_state_dropdown($QFI);
1786
+				break;
1787
+			case 'country':
1788
+				$QFI = self::generate_country_dropdown($QFI);
1789
+				break;
1790
+			case 'admin-state':
1791
+				$QFI = self::generate_state_dropdown($QFI, true);
1792
+				break;
1793
+			case 'admin-country':
1794
+				$QFI = self::generate_country_dropdown($QFI, true);
1795
+				break;
1796
+		}
1797
+		return $QFI;
1798
+	}
1799
+
1800
+
1801
+	/**
1802
+	 * This preps dropdowns that are specialized.
1803
+	 *
1804
+	 * @param EE_Question_Form_Input $QFI
1805
+	 *
1806
+	 * @return EE_Question_Form_Input
1807
+	 * @throws EE_Error
1808
+	 * @throws ReflectionException
1809
+	 * @since  4.6.0
1810
+	 */
1811
+	protected static function _load_specialized_dropdowns($QFI)
1812
+	{
1813
+		switch ($QFI->get('QST_type')) {
1814
+			case 'STATE':
1815
+				$QFI = self::generate_state_dropdown($QFI);
1816
+				break;
1817
+			case 'COUNTRY':
1818
+				$QFI = self::generate_country_dropdown($QFI);
1819
+				break;
1820
+		}
1821
+		return $QFI;
1822
+	}
1823
+
1824
+
1825
+	/**
1826
+	 *    generate_state_dropdown
1827
+	 *
1828
+	 * @param EE_Question_Form_Input $QST
1829
+	 * @param bool                   $get_all
1830
+	 * @return EE_Question_Form_Input
1831
+	 * @throws EE_Error
1832
+	 * @throws ReflectionException
1833
+	 */
1834
+	public static function generate_state_dropdown($QST, $get_all = false)
1835
+	{
1836
+		$states = $get_all
1837
+			? EEM_State::instance()->get_all_states()
1838
+			: EEM_State::instance()->get_all_states_of_active_countries();
1839
+		if ($states && count($states) != count($QST->options())) {
1840
+			$QST->set('QST_type', 'DROPDOWN');
1841
+			// if multiple countries, we'll create option groups within the dropdown
1842
+			foreach ($states as $state) {
1843
+				if ($state instanceof EE_State) {
1844
+					$QSO = EE_Question_Option::new_instance(
1845
+						[
1846
+							'QSO_value'   => $state->ID(),
1847
+							'QSO_desc'    => $state->name(),
1848
+							'QST_ID'      => $QST->get('QST_ID'),
1849
+							'QSO_deleted' => false,
1850
+						]
1851
+					);
1852
+					// set option group
1853
+					$QSO->set_opt_group($state->country()->name());
1854
+					// add option to question
1855
+					$QST->add_temp_option($QSO);
1856
+				}
1857
+			}
1858
+		}
1859
+		return $QST;
1860
+	}
1861
+
1862
+
1863
+	/**
1864
+	 *    generate_country_dropdown
1865
+	 *
1866
+	 * @param      $QST
1867
+	 * @param bool $get_all
1868
+	 * @return array
1869
+	 * @throws EE_Error
1870
+	 * @throws ReflectionException
1871
+	 * @internal param array $question
1872
+	 */
1873
+	public static function generate_country_dropdown($QST, $get_all = false)
1874
+	{
1875
+		$countries = $get_all
1876
+			? EEM_Country::instance()->get_all_countries()
1877
+			: EEM_Country::instance()->get_all_active_countries();
1878
+		if ($countries && count($countries) != count($QST->options())) {
1879
+			$QST->set('QST_type', 'DROPDOWN');
1880
+			// now add countries
1881
+			foreach ($countries as $country) {
1882
+				if ($country instanceof EE_Country) {
1883
+					$QSO = EE_Question_Option::new_instance(
1884
+						[
1885
+							'QSO_value'   => $country->ID(),
1886
+							'QSO_desc'    => $country->name(),
1887
+							'QST_ID'      => $QST->get('QST_ID'),
1888
+							'QSO_deleted' => false,
1889
+						]
1890
+					);
1891
+					$QST->add_temp_option($QSO);
1892
+				}
1893
+			}
1894
+		}
1895
+		return $QST;
1896
+	}
1897
+
1898
+
1899
+	/**
1900
+	 *  generates options for a month dropdown selector with numbers from 01 to 12
1901
+	 *
1902
+	 * @return array()
1903
+	 */
1904
+	public static function two_digit_months_dropdown_options()
1905
+	{
1906
+		$options = [];
1907
+		for ($x = 1; $x <= 12; $x++) {
1908
+			$mm             = str_pad($x, 2, '0', STR_PAD_LEFT);
1909
+			$options[ $mm ] = $mm;
1910
+		}
1911
+		return EEH_Form_Fields::prep_answer_options($options);
1912
+	}
1913
+
1914
+
1915
+	/**
1916
+	 *  generates a year dropdown selector with numbers for the next ten years
1917
+	 *
1918
+	 * @return array
1919
+	 */
1920
+	public static function next_decade_two_digit_year_dropdown_options()
1921
+	{
1922
+		$options      = [];
1923
+		$current_year = date('y');
1924
+		$next_decade  = $current_year + 10;
1925
+		for ($x = $current_year; $x <= $next_decade; $x++) {
1926
+			$yy             = str_pad($x, 2, '0', STR_PAD_LEFT);
1927
+			$options[ $yy ] = $yy;
1928
+		}
1929
+		return EEH_Form_Fields::prep_answer_options($options);
1930
+	}
1931
+
1932
+
1933
+	/**
1934
+	 * generates a month/year dropdown selector for all registrations matching the given criteria.  Typically used for
1935
+	 * list table filter.
1936
+	 *
1937
+	 * @param string  $cur_date     any currently selected date can be entered here.
1938
+	 * @param string  $status       Registration status
1939
+	 * @param integer $evt_category Event Category ID if the Event Category filter is selected
1940
+	 * @return string                html
1941
+	 * @throws EE_Error
1942
+	 */
1943
+	public static function generate_registration_months_dropdown($cur_date = '', $status = '', $evt_category = 0)
1944
+	{
1945
+		$_where = [];
1946
+		if (! empty($status)) {
1947
+			$_where['STS_ID'] = $status;
1948
+		}
1949
+
1950
+		if ($evt_category > 0) {
1951
+			$_where['Event.Term_Taxonomy.term_id'] = $evt_category;
1952
+		}
1953
+
1954
+		$regdtts = EEM_Registration::instance()->get_reg_months_and_years($_where);
1955
+
1956
+		// setup vals for select input helper
1957
+		$options = [
1958
+			0 => [
1959
+				'text' => esc_html__('Select a Month/Year', 'event_espresso'),
1960
+				'id'   => '',
1961
+			],
1962
+		];
1963
+
1964
+		foreach ($regdtts as $regdtt) {
1965
+			$date      = $regdtt->reg_month . ' ' . $regdtt->reg_year;
1966
+			$options[] = [
1967
+				'text' => $date,
1968
+				'id'   => $date,
1969
+			];
1970
+		}
1971
+
1972
+		return self::select_input('month_range', $options, $cur_date);
1973
+	}
1974
+
1975
+
1976
+	/**
1977
+	 * generates a month/year dropdown selector for all events matching the given criteria
1978
+	 * Typically used for list table filter
1979
+	 *
1980
+	 * @param string $cur_date          any currently selected date can be entered here.
1981
+	 * @param string $status            "view" (i.e. all, today, month, draft)
1982
+	 * @param int    $evt_category      category event belongs to
1983
+	 * @param string $evt_active_status "upcoming", "expired", "active", or "inactive"
1984
+	 * @return string                    html
1985
+	 * @throws EE_Error
1986
+	 * @throws ReflectionException
1987
+	 */
1988
+	public static function generate_event_months_dropdown(
1989
+		string $cur_date = '',
1990
+		string $status = 'all',
1991
+		int $evt_category = 0,
1992
+		string $evt_active_status = ''
1993
+	): string {
1994
+		// determine what post_status our condition will have for the query.
1995
+		switch ($status) {
1996
+			case 'month':
1997
+			case 'today':
1998
+			case 'all':
1999
+				$where['Event.status'] = ['NOT IN', ['trash']];
2000
+				break;
2001
+			case 'draft':
2002
+				$where['Event.status'] = ['IN', ['draft', 'auto-draft']];
2003
+				break;
2004
+			default:
2005
+				$where['Event.status'] = $status;
2006
+		}
2007
+
2008
+		// categories?
2009
+		if (! empty($evt_category) and $evt_category > 0) {
2010
+			$where['Event.Term_Taxonomy.taxonomy'] = 'espresso_event_categories';
2011
+			$where['Event.Term_Taxonomy.term_id']  = $evt_category;
2012
+		}
2013
+
2014
+		//      $where['DTT_is_primary'] = 1;
2015
+
2016
+		$DTTS = EEM_Datetime::instance()->get_dtt_months_and_years($where, $evt_active_status);
2017
+
2018
+		// let's setup vals for select input helper
2019
+		$options = [
2020
+			0 => [
2021
+				'text' => esc_html__('Select a Month/Year', 'event_espresso'),
2022
+				'id'   => "",
2023
+			],
2024
+		];
2025
+
2026
+
2027
+		// translate month and date
2028
+		global $wp_locale;
2029
+
2030
+		foreach ($DTTS as $DTT) {
2031
+			$localized_date = $wp_locale->get_month($DTT->dtt_month_num) . ' ' . $DTT->dtt_year;
2032
+			$id             = $DTT->dtt_month . ' ' . $DTT->dtt_year;
2033
+			$options[]      = [
2034
+				'text' => $localized_date,
2035
+				'id'   => $id,
2036
+			];
2037
+		}
2038
+
2039
+
2040
+		return self::select_input('month_range', $options, $cur_date);
2041
+	}
2042
+
2043
+
2044
+	/**
2045
+	 * generates the dropdown selector for event categories
2046
+	 * typically used as a filter on list tables.
2047
+	 *
2048
+	 * @param integer $current_cat currently selected category
2049
+	 * @return string               html for dropdown
2050
+	 * @throws EE_Error
2051
+	 * @throws ReflectionException
2052
+	 */
2053
+	public static function generate_event_category_dropdown($current_cat = -1)
2054
+	{
2055
+		$categories = EEM_Term::instance()->get_all_ee_categories(true);
2056
+		$options    = [
2057
+			'0' => [
2058
+				'text' => esc_html__('All Categories', 'event_espresso'),
2059
+				'id'   => -1,
2060
+			],
2061
+		];
2062
+
2063
+		// setup categories for dropdown
2064
+		foreach ($categories as $category) {
2065
+			$options[] = [
2066
+				'text' => $category->get('name'),
2067
+				'id'   => $category->ID(),
2068
+			];
2069
+		}
2070
+
2071
+		return self::select_input('EVT_CAT', $options, $current_cat);
2072
+	}
2073
+
2074
+
2075
+	/**
2076
+	 *    generate a submit button with or without it's own microform
2077
+	 *    this is the only way to create buttons that are compatible across all themes
2078
+	 *
2079
+	 * @access    public
2080
+	 * @param string      $url              - the form action
2081
+	 * @param string      $ID               - some kind of unique ID, appended with "-sbmt" for the input and "-frm"
2082
+	 *                                      for the form
2083
+	 * @param string      $class            - css classes (separated by spaces if more than one)
2084
+	 * @param string      $text             - what appears on the button
2085
+	 * @param string      $nonce_action     - if using nonces
2086
+	 * @param bool|string $input_only       - whether to print form header and footer. TRUE returns the input without
2087
+	 *                                      the form
2088
+	 * @param string      $extra_attributes - any extra attributes that need to be attached to the form input
2089
+	 * @return    string
2090
+	 */
2091
+	public static function submit_button(
2092
+		$url = '',
2093
+		$ID = '',
2094
+		$class = '',
2095
+		$text = '',
2096
+		$nonce_action = '',
2097
+		$input_only = false,
2098
+		$extra_attributes = ''
2099
+	) {
2100
+		$btn = '';
2101
+		if (empty($url) || empty($ID)) {
2102
+			return $btn;
2103
+		}
2104
+		$text = ! empty($text) ? $text : esc_html__('Submit', 'event_espresso');
2105
+		$btn  .= '<input id="' . $ID . '-btn" class="' . $class . '" '
2106
+				 . 'type="submit" value="' . $text . '" ' . $extra_attributes . '/>';
2107
+		if (! $input_only) {
2108
+			$btn_frm = '<form id="' . $ID . '-frm" method="POST" action="' . $url . '">';
2109
+			$btn_frm .= ! empty($nonce_action)
2110
+				? wp_nonce_field($nonce_action, $nonce_action . '_nonce', true, false)
2111
+				: '';
2112
+			$btn_frm .= $btn;
2113
+			$btn_frm .= '</form>';
2114
+			$btn     = $btn_frm;
2115
+			unset($btn_frm);
2116
+		}
2117
+		return $btn;
2118
+	}
2119 2119
 }
Please login to merge, or discard this patch.
Spacing   +135 added lines, -135 removed lines patch added patch discarded remove patch
@@ -108,8 +108,8 @@  discard block
 block discarded – undo
108 108
             $type           = $input_value['input'];
109 109
             $value          = $input_value['value'];
110 110
 
111
-            $id    = $form_id ? $form_id . '-' . $input_key : $input_key;
112
-            $class = $required ? 'required ' . $css_class : $css_class;
111
+            $id    = $form_id ? $form_id.'-'.$input_key : $input_key;
112
+            $class = $required ? 'required '.$css_class : $css_class;
113 113
 
114 114
             // what type of input are we dealing with ?
115 115
             switch ($type) {
@@ -161,8 +161,8 @@  discard block
 block discarded – undo
161 161
             }
162 162
         } // end foreach( $input_vars as $input_key => $input_value )
163 163
 
164
-        if (! empty($inputs)) {
165
-            $glue   = "
164
+        if ( ! empty($inputs)) {
165
+            $glue = "
166 166
                 </li>
167 167
                 <li>
168 168
                     ";
@@ -175,7 +175,7 @@  discard block
 block discarded – undo
175 175
             </ul>
176 176
             ";
177 177
         }
178
-        return $output . implode("\n", $hidden_inputs);
178
+        return $output.implode("\n", $hidden_inputs);
179 179
     }
180 180
 
181 181
 
@@ -256,7 +256,7 @@  discard block
 block discarded – undo
256 256
             // generate label
257 257
             $label = ! empty($label) ? self::adminLabel($id, $label, $required) : '';
258 258
             // generate field name
259
-            $name = ! empty($unique_id) ? $field_name . '[' . $unique_id . ']' : $field_name;
259
+            $name = ! empty($unique_id) ? $field_name.'['.$unique_id.']' : $field_name;
260 260
 
261 261
             // we determine what we're building based on the type
262 262
             switch ($type) {
@@ -267,14 +267,14 @@  discard block
 block discarded – undo
267 267
                         foreach ($value as $key => $val) {
268 268
                             $c_input .= self::adminMulti(
269 269
                                 $default,
270
-                                isset($classes[ $key ]) ? $classes[ $key ] : '',
271
-                                $field_name . '_' . $value,
270
+                                isset($classes[$key]) ? $classes[$key] : '',
271
+                                $field_name.'_'.$value,
272 272
                                 $name,
273 273
                                 $required,
274 274
                                 $tab_index,
275 275
                                 $type,
276 276
                                 $val,
277
-                                isset($labels[ $key ]) ? $labels[ $key ] : ''
277
+                                isset($labels[$key]) ? $labels[$key] : ''
278 278
                             );
279 279
                         }
280 280
                         $field = $c_input;
@@ -300,7 +300,7 @@  discard block
 block discarded – undo
300 300
                 case 'select':
301 301
                     $options = [];
302 302
                     foreach ($value as $key => $val) {
303
-                        $options[ $val ] = isset($labels[ $key ]) ? $labels[ $key ] : '';
303
+                        $options[$val] = isset($labels[$key]) ? $labels[$key] : '';
304 304
                     }
305 305
                     $field = self::adminSelect($default, $class, $id, $name, $required, $tab_index, $options);
306 306
                     break;
@@ -326,7 +326,7 @@  discard block
 block discarded – undo
326 326
                     $field = self::adminText($class, $id, $name, $required, $tab_index, $value);
327 327
             }
328 328
 
329
-            $form_fields[ $field_name ] = ['label' => $label, 'field' => $field . $extra_desc];
329
+            $form_fields[$field_name] = ['label' => $label, 'field' => $field.$extra_desc];
330 330
         }
331 331
 
332 332
         return $form_fields;
@@ -395,7 +395,7 @@  discard block
 block discarded – undo
395 395
         }
396 396
         $label = esc_html($label);
397 397
         $label_class = self::appendInputSizeClass('', $label);
398
-        $label_class = $label_class ? ' class="' . $label_class . '"' : '';
398
+        $label_class = $label_class ? ' class="'.$label_class.'"' : '';
399 399
         return "
400 400
         <label for='$id'{$label_class}>
401 401
             {$input}
@@ -545,7 +545,7 @@  discard block
 block discarded – undo
545 545
         $autosize = true
546 546
     ) {
547 547
         // if $values was submitted in the wrong format, convert it over
548
-        if (! empty($values) && (! array_key_exists(0, $values) || ! is_array($values[0]))) {
548
+        if ( ! empty($values) && ( ! array_key_exists(0, $values) || ! is_array($values[0]))) {
549 549
             $converted_values = [];
550 550
             foreach ($values as $id => $text) {
551 551
                 $converted_values[] = ['id' => $id, 'text' => $text];
@@ -554,19 +554,19 @@  discard block
 block discarded – undo
554 554
         }
555 555
 
556 556
         $field =
557
-            '<select id="' . EEH_Formatter::ee_tep_output_string($name)
558
-            . '" name="' . EEH_Formatter::ee_tep_output_string($name)
557
+            '<select id="'.EEH_Formatter::ee_tep_output_string($name)
558
+            . '" name="'.EEH_Formatter::ee_tep_output_string($name)
559 559
             . '"';
560 560
 
561 561
         if (EEH_Formatter::ee_tep_not_null($parameters)) {
562
-            $field .= ' ' . $parameters;
562
+            $field .= ' '.$parameters;
563 563
         }
564 564
         $class = $autosize ? self::appendInputSizeClass($class, $values) : '';
565 565
 
566
-        $field .= ' class="' . $class . '">';
566
+        $field .= ' class="'.$class.'">';
567 567
 
568
-        if (empty($default) && isset($GLOBALS[ $name ])) {
569
-            $default = stripslashes($GLOBALS[ $name ]);
568
+        if (empty($default) && isset($GLOBALS[$name])) {
569
+            $default = stripslashes($GLOBALS[$name]);
570 570
         }
571 571
 
572 572
         $field .= self::selectInputOption($values, $default);
@@ -582,7 +582,7 @@  discard block
 block discarded – undo
582 582
             $id = is_scalar($values['id']) ? $values['id'] : '';
583 583
             $text = is_scalar($values['text']) ? $values['text'] : '';
584 584
             $selected = $default == $values['id'] ? ' selected = "selected"' : '';
585
-            $html_class = isset($values['class']) ? ' class="' . $values['class'] . '"' : '';
585
+            $html_class = isset($values['class']) ? ' class="'.$values['class'].'"' : '';
586 586
             return "<option value='{$id}'{$selected}{$html_class}>{$text}</option>";
587 587
         }
588 588
         $options = '';
@@ -612,7 +612,7 @@  discard block
 block discarded – undo
612 612
             return $chars;
613 613
         }
614 614
         // not a primitive? return something big
615
-        if (! is_scalar($value)) {
615
+        if ( ! is_scalar($value)) {
616 616
             return 500;
617 617
         }
618 618
         return strlen((string) $value);
@@ -662,11 +662,11 @@  discard block
 block discarded – undo
662 662
         $after_question_group_questions  =
663 663
             apply_filters('FHEE__EEH_Form_Fields__generate_question_groups_html__after_question_group_questions', '');
664 664
 
665
-        if (! empty($question_groups)) {
665
+        if ( ! empty($question_groups)) {
666 666
             // loop thru question groups
667 667
             foreach ($question_groups as $QSG) {
668 668
                 // check that questions exist
669
-                if (! empty($QSG['QSG_questions'])) {
669
+                if ( ! empty($QSG['QSG_questions'])) {
670 670
                     // use fieldsets
671 671
                     $html .= "\n\t"
672 672
                              . '<'
@@ -691,7 +691,7 @@  discard block
 block discarded – undo
691 691
                     $html .= $before_question_group_questions;
692 692
                     // loop thru questions
693 693
                     foreach ($QSG['QSG_questions'] as $question) {
694
-                        $QFI  = new EE_Question_Form_Input(
694
+                        $QFI = new EE_Question_Form_Input(
695 695
                             $question['qst_obj'],
696 696
                             $question['ans_obj'],
697 697
                             $question
@@ -699,7 +699,7 @@  discard block
 block discarded – undo
699 699
                         $html .= self::generate_form_input($QFI);
700 700
                     }
701 701
                     $html .= $after_question_group_questions;
702
-                    $html .= "\n\t" . '</' . $group_wrapper . '>';
702
+                    $html .= "\n\t".'</'.$group_wrapper.'>';
703 703
                 }
704 704
             }
705 705
         }
@@ -739,25 +739,25 @@  discard block
 block discarded – undo
739 739
             'input_id'    => '',
740 740
             'input_class' => '',
741 741
         ];
742
-        $q_meta         = array_merge($default_q_meta, $q_meta);
742
+        $q_meta = array_merge($default_q_meta, $q_meta);
743 743
 
744
-        if (! empty($question_groups)) {
744
+        if ( ! empty($question_groups)) {
745 745
             // loop thru question groups
746 746
             foreach ($question_groups as $QSG) {
747 747
                 if ($QSG instanceof EE_Question_Group) {
748 748
                     // check that questions exist
749 749
 
750 750
                     $where = ['QST_deleted' => 0];
751
-                    if (! $from_admin) {
751
+                    if ( ! $from_admin) {
752 752
                         $where['QST_admin_only'] = 0;
753 753
                     }
754 754
                     $questions =
755 755
                         $QSG->questions([$where, 'order_by' => ['Question_Group_Question.QGQ_order' => 'ASC']]);
756
-                    if (! empty($questions)) {
756
+                    if ( ! empty($questions)) {
757 757
                         // use fieldsets
758 758
                         $html .= "\n\t"
759
-                                 . '<' . $group_wrapper . ' class="espresso-question-group-wrap" '
760
-                                 . 'id="' . $QSG->get('QSG_identifier') . '">';
759
+                                 . '<'.$group_wrapper.' class="espresso-question-group-wrap" '
760
+                                 . 'id="'.$QSG->get('QSG_identifier').'">';
761 761
                         // group_name
762 762
                         if ($QSG->show_group_name()) {
763 763
                             $html .= "\n\t\t"
@@ -782,21 +782,21 @@  discard block
 block discarded – undo
782 782
                             /** @var RequestInterface $request */
783 783
                             $request      = LoaderFactory::getLoader()->getShared(RequestInterface::class);
784 784
                             $request_qstn = $request->getRequestParam('qstn', [], 'string', true);
785
-                            if (! empty($request_qstn) && isset($q_meta['input_id']) && isset($q_meta['att_nmbr'])) {
785
+                            if ( ! empty($request_qstn) && isset($q_meta['input_id']) && isset($q_meta['att_nmbr'])) {
786 786
                                 // check for answer in $request_qstn in case we are reprocessing a form after an error
787
-                                if (isset($request_qstn[ $q_meta['input_id'] ][ $qstn_id ])) {
788
-                                    $answer = is_array($request_qstn[ $q_meta['input_id'] ][ $qstn_id ])
789
-                                        ? $request_qstn[ $q_meta['input_id'] ][ $qstn_id ]
790
-                                        : sanitize_text_field($request_qstn[ $q_meta['input_id'] ][ $qstn_id ]);
787
+                                if (isset($request_qstn[$q_meta['input_id']][$qstn_id])) {
788
+                                    $answer = is_array($request_qstn[$q_meta['input_id']][$qstn_id])
789
+                                        ? $request_qstn[$q_meta['input_id']][$qstn_id]
790
+                                        : sanitize_text_field($request_qstn[$q_meta['input_id']][$qstn_id]);
791 791
                                 }
792 792
                             } elseif (isset($q_meta['attendee']) && $q_meta['attendee']) {
793 793
                                 // attendee data from the session
794 794
                                 $answer =
795
-                                    isset($q_meta['attendee'][ $qstn_id ]) ? $q_meta['attendee'][ $qstn_id ] : null;
795
+                                    isset($q_meta['attendee'][$qstn_id]) ? $q_meta['attendee'][$qstn_id] : null;
796 796
                             }
797 797
 
798 798
 
799
-                            $QFI  = new EE_Question_Form_Input(
799
+                            $QFI = new EE_Question_Form_Input(
800 800
                                 $QST,
801 801
                                 EE_Answer::new_instance(
802 802
                                     [
@@ -811,7 +811,7 @@  discard block
 block discarded – undo
811 811
                             $html .= self::generate_form_input($QFI);
812 812
                         }
813 813
                         $html .= $after_question_group_questions;
814
-                        $html .= "\n\t" . '</' . $group_wrapper . '>';
814
+                        $html .= "\n\t".'</'.$group_wrapper.'>';
815 815
                     }
816 816
                 }
817 817
             }
@@ -993,7 +993,7 @@  discard block
 block discarded – undo
993 993
     ): string {
994 994
         $for   = ! empty($name) ? " for='{$name}'" : '';
995 995
         $class = ! empty($label_class) ? " class='{$label_class}'" : '';
996
-        $label = self::prep_question($question) . $required_label;
996
+        $label = self::prep_question($question).$required_label;
997 997
         $label_html = "
998 998
             {$required_text}
999 999
             <label{$for}{$class}>{$label}</label>";
@@ -1049,7 +1049,7 @@  discard block
 block discarded – undo
1049 1049
         $extra_attributes = ''
1050 1050
     ) {
1051 1051
         // need these
1052
-        if (! $question || ! $name) {
1052
+        if ( ! $question || ! $name) {
1053 1053
             return null;
1054 1054
         }
1055 1055
         // prep the answer
@@ -1061,9 +1061,9 @@  discard block
 block discarded – undo
1061 1061
         // ya gots ta have style man!!!
1062 1062
         $txt_class = is_admin() ? 'regular-text' : 'espresso-text-inp';
1063 1063
         $class     = empty($class) ? $txt_class : $class;
1064
-        $class     .= ! empty($system_ID) ? ' ' . $system_ID : '';
1064
+        $class .= ! empty($system_ID) ? ' '.$system_ID : '';
1065 1065
         $class = self::appendInputSizeClass($class, $answer);
1066
-        $class .= ! empty($required['class']) ? ' ' . $required['class'] : '';
1066
+        $class .= ! empty($required['class']) ? ' '.$required['class'] : '';
1067 1067
         $extra_attributes = apply_filters('FHEE__EEH_Form_Fields__additional_form_field_attributes', $extra_attributes);
1068 1068
 
1069 1069
         $label_html = self::label($question, $required_text, $required['label'], $name, $label_class);
@@ -1076,18 +1076,18 @@  discard block
 block discarded – undo
1076 1076
             $name
1077 1077
         );
1078 1078
 
1079
-        $input_html = $mobile_label . '
1079
+        $input_html = $mobile_label.'
1080 1080
             <input  type="text"
1081
-                    name="' . $name . '"
1082
-                    id="' . $id . '"
1083
-                    class="' . trim($class) . '"
1084
-                    value="' . esc_attr($answer) . '"
1085
-                    aria-label="' . esc_attr($required['msg']) . '"
1086
-                    ' . $disabled . ' ' . $extra_attributes . '
1081
+                    name="' . $name.'"
1082
+                    id="' . $id.'"
1083
+                    class="' . trim($class).'"
1084
+                    value="' . esc_attr($answer).'"
1085
+                    aria-label="' . esc_attr($required['msg']).'"
1086
+                    ' . $disabled.' '.$extra_attributes.'
1087 1087
             />';
1088 1088
 
1089 1089
         $input_html = apply_filters('FHEE__EEH_Form_Fields__input_html', $input_html, $label_html, $id);
1090
-        return $label_html . $input_html;
1090
+        return $label_html.$input_html;
1091 1091
     }
1092 1092
 
1093 1093
 
@@ -1122,7 +1122,7 @@  discard block
 block discarded – undo
1122 1122
         $add_mobile_label = false
1123 1123
     ) {
1124 1124
         // need these
1125
-        if (! $question || ! $name) {
1125
+        if ( ! $question || ! $name) {
1126 1126
             return null;
1127 1127
         }
1128 1128
         // prep the answer
@@ -1136,9 +1136,9 @@  discard block
 block discarded – undo
1136 1136
         // set disabled tag
1137 1137
         $disabled = $answer === null || ! $disabled ? '' : ' disabled="disabled"';
1138 1138
         // ya gots ta have style man!!!
1139
-        $class     .= ! empty($system_ID) ? ' ' . $system_ID : '';
1140
-        $class     .= ! empty($required['class']) ? ' ' . $required['class'] : '';
1141
-        $extra     = apply_filters('FHEE__EEH_Form_Fields__additional_form_field_attributes', '');
1139
+        $class     .= ! empty($system_ID) ? ' '.$system_ID : '';
1140
+        $class     .= ! empty($required['class']) ? ' '.$required['class'] : '';
1141
+        $extra = apply_filters('FHEE__EEH_Form_Fields__additional_form_field_attributes', '');
1142 1142
 
1143 1143
         $label_html   = self::label($question, $required_text, $required['label'], $name, $label_class);
1144 1144
         $mobile_label = self::mobileLabel(
@@ -1151,14 +1151,14 @@  discard block
 block discarded – undo
1151 1151
         );
1152 1152
 
1153 1153
         $input_html = $mobile_label
1154
-            . '<textarea name="' . $name . '" id="' . $id . '" class="' . trim($class) . '" '
1155
-            . 'rows="' . $dimensions['rows'] . '" cols="' . $dimensions['cols'] . '"  '
1156
-            . 'aria-label="' . $required['msg'] . '" ' . $disabled . ' ' . $extra . '>'
1154
+            . '<textarea name="'.$name.'" id="'.$id.'" class="'.trim($class).'" '
1155
+            . 'rows="'.$dimensions['rows'].'" cols="'.$dimensions['cols'].'"  '
1156
+            . 'aria-label="'.$required['msg'].'" '.$disabled.' '.$extra.'>'
1157 1157
              . esc_textarea($answer)
1158 1158
               . '</textarea>';
1159 1159
 
1160 1160
         $input_html = apply_filters('FHEE__EEH_Form_Fields__input_html', $input_html, $label_html, $id);
1161
-        return $label_html . $input_html;
1161
+        return $label_html.$input_html;
1162 1162
     }
1163 1163
 
1164 1164
 
@@ -1196,7 +1196,7 @@  discard block
 block discarded – undo
1196 1196
     ) {
1197 1197
 
1198 1198
         // need these
1199
-        if (! $question || ! $name || ! $options || empty($options) || ! is_array($options)) {
1199
+        if ( ! $question || ! $name || ! $options || empty($options) || ! is_array($options)) {
1200 1200
             return null;
1201 1201
         }
1202 1202
         // prep the answer
@@ -1208,9 +1208,9 @@  discard block
 block discarded – undo
1208 1208
         // set disabled tag
1209 1209
         $disabled = $answer === null || ! $disabled ? '' : ' disabled="disabled"';
1210 1210
         // ya gots ta have style man!!!
1211
-        $class     .= ! empty($system_ID) ? ' ' . $system_ID : '';
1211
+        $class .= ! empty($system_ID) ? ' '.$system_ID : '';
1212 1212
         $class = self::appendInputSizeClass($class, $options);
1213
-        $extra     = apply_filters('FHEE__EEH_Form_Fields__additional_form_field_attributes', '');
1213
+        $extra = apply_filters('FHEE__EEH_Form_Fields__additional_form_field_attributes', '');
1214 1214
 
1215 1215
         $label_html   = self::label($question, $required_text, $required['label'], $name, $label_class);
1216 1216
         $mobile_label = self::mobileLabel(
@@ -1223,16 +1223,16 @@  discard block
 block discarded – undo
1223 1223
         );
1224 1224
 
1225 1225
         $input_html = $mobile_label
1226
-            . '<select name="' . $name . '" id="' . $id . '" class="' . trim($class) . ' ' . $required['class'] . '" '
1227
-            . 'aria-label="' . esc_attr($required['msg']) . '"' . $disabled . ' ' . $extra . '>';
1226
+            . '<select name="'.$name.'" id="'.$id.'" class="'.trim($class).' '.$required['class'].'" '
1227
+            . 'aria-label="'.esc_attr($required['msg']).'"'.$disabled.' '.$extra.'>';
1228 1228
         // recursively count array elements, to determine total number of options
1229 1229
         $only_option = count($options, 1) == 1;
1230
-        if (! $only_option) {
1230
+        if ( ! $only_option) {
1231 1231
             // if there is NO answer set and there are multiple options to choose from, then set the "please select" message as selected
1232
-            $selected   = $answer === null ? ' selected' : '';
1232
+            $selected = $answer === null ? ' selected' : '';
1233 1233
             $input_html .= $add_please_select_option
1234 1234
                 ? "\n\t\t\t\t"
1235
-                  . '<option value=""' . $selected . '>'
1235
+                  . '<option value=""'.$selected.'>'
1236 1236
                   . esc_html__(' - please select - ', 'event_espresso')
1237 1237
                   . '</option>'
1238 1238
                 : '';
@@ -1255,7 +1255,7 @@  discard block
 block discarded – undo
1255 1255
                 );
1256 1256
         }
1257 1257
 
1258
-        $input_html .= "\n\t\t\t" . '</select>';
1258
+        $input_html .= "\n\t\t\t".'</select>';
1259 1259
 
1260 1260
         $input_html =
1261 1261
             apply_filters(
@@ -1270,7 +1270,7 @@  discard block
 block discarded – undo
1270 1270
             );
1271 1271
 
1272 1272
         $input_html = apply_filters('FHEE__EEH_Form_Fields__input_html', $input_html, $label_html, $id);
1273
-        return $label_html . $input_html;
1273
+        return $label_html.$input_html;
1274 1274
     }
1275 1275
 
1276 1276
 
@@ -1288,11 +1288,11 @@  discard block
 block discarded – undo
1288 1288
      */
1289 1289
     private static function _generate_select_option_group($opt_group, $QSOs, $answer, $use_html_entities = true)
1290 1290
     {
1291
-        $html = "\n\t\t\t\t" . '<optgroup label="' . self::prep_option_value($opt_group) . '">';
1291
+        $html = "\n\t\t\t\t".'<optgroup label="'.self::prep_option_value($opt_group).'">';
1292 1292
         foreach ($QSOs as $QSO) {
1293 1293
             $html .= self::_generate_select_option($QSO->value(), $QSO->desc(), $answer, false, $use_html_entities);
1294 1294
         }
1295
-        $html .= "\n\t\t\t\t" . '</optgroup>';
1295
+        $html .= "\n\t\t\t\t".'</optgroup>';
1296 1296
         return $html;
1297 1297
     }
1298 1298
 
@@ -1319,7 +1319,7 @@  discard block
 block discarded – undo
1319 1319
         $value    = ! empty($value) ? $value : $key;
1320 1320
         $selected = ($answer == $key || $only_option) ? 'selected' : '';
1321 1321
         return "\n\t\t\t\t"
1322
-               . '<option value="' . self::prep_option_value($key) . '" ' . $selected . '> '
1322
+               . '<option value="'.self::prep_option_value($key).'" '.$selected.'> '
1323 1323
                . $value
1324 1324
                . '&nbsp;&nbsp;&nbsp;</option>';
1325 1325
     }
@@ -1364,7 +1364,7 @@  discard block
 block discarded – undo
1364 1364
         bool $add_mobile_label = false
1365 1365
     ) {
1366 1366
         // need these
1367
-        if (! $question || ! $name || ! $options || empty($options) || ! is_array($options)) {
1367
+        if ( ! $question || ! $name || ! $options || empty($options) || ! is_array($options)) {
1368 1368
             return null;
1369 1369
         }
1370 1370
         // prep the answer
@@ -1388,50 +1388,50 @@  discard block
 block discarded – undo
1388 1388
         );
1389 1389
 
1390 1390
         $input_html = $mobile_label
1391
-            . '<ul id="' . $id . '-ul" class="espresso-radio-btn-options-ul ' . $class . '-ul">';
1391
+            . '<ul id="'.$id.'-ul" class="espresso-radio-btn-options-ul '.$class.'-ul">';
1392 1392
 
1393
-        $class .= ! empty($system_ID) ? ' ' . $system_ID : '';
1394
-        $class .= ! empty($required['class']) ? ' ' . $required['class'] : '';
1393
+        $class .= ! empty($system_ID) ? ' '.$system_ID : '';
1394
+        $class .= ! empty($required['class']) ? ' '.$required['class'] : '';
1395 1395
 
1396 1396
         foreach ($options as $OPT) {
1397 1397
             if ($OPT instanceof EE_Question_Option) {
1398 1398
                 $value   = self::prep_option_value($OPT->value());
1399 1399
                 $label   = $use_desc_4_label ? $OPT->desc() : $OPT->value();
1400 1400
                 $size    = $use_desc_4_label
1401
-                    ? self::get_label_size_class($OPT->value() . ' ' . $OPT->desc())
1401
+                    ? self::get_label_size_class($OPT->value().' '.$OPT->desc())
1402 1402
                     : self::get_label_size_class($OPT->value());
1403
-                $desc    = $OPT->desc();// no self::prep_answer
1403
+                $desc    = $OPT->desc(); // no self::prep_answer
1404 1404
                 $answer  = is_numeric($value) && empty($answer) ? 0 : $answer;
1405
-                $value  = is_numeric($answer) && empty($value) ? 0 : $value;
1405
+                $value = is_numeric($answer) && empty($value) ? 0 : $value;
1406 1406
                 $checked = (string) $value == (string) $answer ? ' checked' : '';
1407
-                $opt     = '-' . sanitize_key($value);
1407
+                $opt     = '-'.sanitize_key($value);
1408 1408
 
1409
-                $input_html .= "\n\t\t\t\t" . '<li' . $size . '>';
1410
-                $input_html .= "\n\t\t\t\t\t" . '<label class="' . $radio_class . ' espresso-radio-btn-lbl">';
1411
-                $input_html .= $label_b4 ? "\n\t\t\t\t\t\t" . '<span>' . $label . '</span>&nbsp;' : '';
1409
+                $input_html .= "\n\t\t\t\t".'<li'.$size.'>';
1410
+                $input_html .= "\n\t\t\t\t\t".'<label class="'.$radio_class.' espresso-radio-btn-lbl">';
1411
+                $input_html .= $label_b4 ? "\n\t\t\t\t\t\t".'<span>'.$label.'</span>&nbsp;' : '';
1412 1412
                 $input_html .= "\n\t\t\t\t\t\t"
1413
-                               . '<input type="radio" name="' . $name . '" id="' . $id . $opt . '" '
1414
-                               . 'class="' . $class . '" value="' . $value . '" '
1415
-                               . 'aria-label="' . esc_attr($required['msg']) . '" ' . $disabled
1416
-                               . $checked . ' ' . $extra . '/>';
1413
+                               . '<input type="radio" name="'.$name.'" id="'.$id.$opt.'" '
1414
+                               . 'class="'.$class.'" value="'.$value.'" '
1415
+                               . 'aria-label="'.esc_attr($required['msg']).'" '.$disabled
1416
+                               . $checked.' '.$extra.'/>';
1417 1417
                 $input_html .= ! $label_b4
1418 1418
                     ? "\n\t\t\t\t\t\t"
1419 1419
                       . '&nbsp;<span class="espresso-radio-btn-desc">'
1420 1420
                       . $label
1421 1421
                       . '</span>'
1422 1422
                     : '';
1423
-                $input_html .= "\n\t\t\t\t\t" . '</label>';
1423
+                $input_html .= "\n\t\t\t\t\t".'</label>';
1424 1424
                 $input_html .= $use_desc_4_label
1425 1425
                     ? ''
1426
-                    : '<span class="espresso-radio-btn-option-desc small-text grey-text">' . $desc . '</span>';
1427
-                $input_html .= "\n\t\t\t\t" . '</li>';
1426
+                    : '<span class="espresso-radio-btn-option-desc small-text grey-text">'.$desc.'</span>';
1427
+                $input_html .= "\n\t\t\t\t".'</li>';
1428 1428
             }
1429 1429
         }
1430 1430
 
1431
-        $input_html .= "\n\t\t\t" . '</ul>';
1431
+        $input_html .= "\n\t\t\t".'</ul>';
1432 1432
 
1433 1433
         $input_html = apply_filters('FHEE__EEH_Form_Fields__input_html', $input_html, $label_html, $id);
1434
-        return $label_html . $input_html;
1434
+        return $label_html.$input_html;
1435 1435
     }
1436 1436
 
1437 1437
 
@@ -1467,7 +1467,7 @@  discard block
 block discarded – undo
1467 1467
         $add_mobile_label = false
1468 1468
     ) {
1469 1469
         // need these
1470
-        if (! $question || ! $name || ! $options || empty($options) || ! is_array($options)) {
1470
+        if ( ! $question || ! $name || ! $options || empty($options) || ! is_array($options)) {
1471 1471
             return null;
1472 1472
         }
1473 1473
         $answer = maybe_unserialize($answer);
@@ -1477,7 +1477,7 @@  discard block
 block discarded – undo
1477 1477
 
1478 1478
         foreach ($answer as $key => $value) {
1479 1479
             $key            = self::prep_option_value($key);
1480
-            $answer[ $key ] = self::prep_answer($value, $use_html_entities);
1480
+            $answer[$key] = self::prep_answer($value, $use_html_entities);
1481 1481
         }
1482 1482
 
1483 1483
         // prep the required array
@@ -1499,42 +1499,42 @@  discard block
 block discarded – undo
1499 1499
         );
1500 1500
 
1501 1501
         $input_html = $mobile_label
1502
-            . '<ul id="' . $id . '-ul" class="espresso-checkbox-options-ul ' . $class . '-ul">';
1502
+            . '<ul id="'.$id.'-ul" class="espresso-checkbox-options-ul '.$class.'-ul">';
1503 1503
 
1504
-        $class .= ! empty($system_ID) ? ' ' . $system_ID : '';
1505
-        $class .= ! empty($required['class']) ? ' ' . $required['class'] : '';
1504
+        $class .= ! empty($system_ID) ? ' '.$system_ID : '';
1505
+        $class .= ! empty($required['class']) ? ' '.$required['class'] : '';
1506 1506
 
1507 1507
         foreach ($options as $OPT) {
1508
-            $value = $OPT->value();// self::prep_option_value( $OPT->value() );
1509
-            $size  = self::get_label_size_class($OPT->value() . ' ' . $OPT->desc());
1508
+            $value = $OPT->value(); // self::prep_option_value( $OPT->value() );
1509
+            $size  = self::get_label_size_class($OPT->value().' '.$OPT->desc());
1510 1510
             $text  = self::prep_answer($OPT->value());
1511 1511
             $desc  = $OPT->desc();
1512
-            $opt   = '-' . sanitize_key($value);
1512
+            $opt   = '-'.sanitize_key($value);
1513 1513
 
1514 1514
             $checked = is_array($answer) && in_array($text, $answer) ? ' checked' : '';
1515 1515
 
1516
-            $input_html .= "\n\t\t\t\t" . '<li' . $size . '>';
1517
-            $input_html .= "\n\t\t\t\t\t" . '<label class="' . $radio_class . ' espresso-checkbox-lbl">';
1518
-            $input_html .= $label_b4 ? "\n\t\t\t\t\t\t" . '<span>' . $text . '</span>&nbsp;' : '';
1516
+            $input_html .= "\n\t\t\t\t".'<li'.$size.'>';
1517
+            $input_html .= "\n\t\t\t\t\t".'<label class="'.$radio_class.' espresso-checkbox-lbl">';
1518
+            $input_html .= $label_b4 ? "\n\t\t\t\t\t\t".'<span>'.$text.'</span>&nbsp;' : '';
1519 1519
             $input_html .= "\n\t\t\t\t\t\t"
1520
-                           . '<input type="checkbox" name="' . $name . '[' . $OPT->ID() . ']" '
1521
-                           . 'id="' . $id . $opt . '" class="' . $class . '" value="' . $value . '" '
1522
-                           . 'aria-label="' . esc_attr($required['msg']) . '" ' . $disabled . $checked . ' ' . $extra . '/>';
1523
-            $input_html .= ! $label_b4 ? "\n\t\t\t\t\t\t" . '&nbsp;<span>' . $text . '</span>' : '';
1524
-            $input_html .= "\n\t\t\t\t\t" . '</label>';
1525
-            if (! empty($desc) && $desc != $text) {
1520
+                           . '<input type="checkbox" name="'.$name.'['.$OPT->ID().']" '
1521
+                           . 'id="'.$id.$opt.'" class="'.$class.'" value="'.$value.'" '
1522
+                           . 'aria-label="'.esc_attr($required['msg']).'" '.$disabled.$checked.' '.$extra.'/>';
1523
+            $input_html .= ! $label_b4 ? "\n\t\t\t\t\t\t".'&nbsp;<span>'.$text.'</span>' : '';
1524
+            $input_html .= "\n\t\t\t\t\t".'</label>';
1525
+            if ( ! empty($desc) && $desc != $text) {
1526 1526
                 $input_html .= "\n\t\t\t\t\t"
1527 1527
                                . ' &nbsp; <br/><div class="espresso-checkbox-option-desc small-text grey-text">'
1528 1528
                                . $desc
1529 1529
                                . '</div>';
1530 1530
             }
1531
-            $input_html .= "\n\t\t\t\t" . '</li>';
1531
+            $input_html .= "\n\t\t\t\t".'</li>';
1532 1532
         }
1533 1533
 
1534
-        $input_html .= "\n\t\t\t" . '</ul>';
1534
+        $input_html .= "\n\t\t\t".'</ul>';
1535 1535
 
1536 1536
         $input_html = apply_filters('FHEE__EEH_Form_Fields__input_html', $input_html, $label_html, $id);
1537
-        return $label_html . $input_html;
1537
+        return $label_html.$input_html;
1538 1538
     }
1539 1539
 
1540 1540
 
@@ -1567,7 +1567,7 @@  discard block
 block discarded – undo
1567 1567
         $add_mobile_label = false
1568 1568
     ) {
1569 1569
         // need these
1570
-        if (! $question || ! $name) {
1570
+        if ( ! $question || ! $name) {
1571 1571
             return null;
1572 1572
         }
1573 1573
         // prep the answer
@@ -1579,7 +1579,7 @@  discard block
 block discarded – undo
1579 1579
         // ya gots ta have style man!!!
1580 1580
         $txt_class = is_admin() ? 'regular-text' : 'espresso-datepicker-inp';
1581 1581
         $class     = empty($class) ? $txt_class : $class;
1582
-        $class     .= ! empty($system_ID) ? ' ' . $system_ID : '';
1582
+        $class .= ! empty($system_ID) ? ' '.$system_ID : '';
1583 1583
         $class = self::appendInputSizeClass($class, $answer);
1584 1584
         $extra     = apply_filters('FHEE__EEH_Form_Fields__additional_form_field_attributes', '');
1585 1585
 
@@ -1594,14 +1594,14 @@  discard block
 block discarded – undo
1594 1594
         );
1595 1595
 
1596 1596
         $input_html = $mobile_label
1597
-            . '<input type="text" name="' . $name . '" id="' . $id . '" '
1598
-            . 'class="' . $class . ' ' . $required['class'] . ' datepicker" value="' . $answer . '"  '
1599
-            . 'aria-label="' . esc_attr($required['msg']) . '" ' . $disabled . ' ' . $extra . '/>';
1597
+            . '<input type="text" name="'.$name.'" id="'.$id.'" '
1598
+            . 'class="'.$class.' '.$required['class'].' datepicker" value="'.$answer.'"  '
1599
+            . 'aria-label="'.esc_attr($required['msg']).'" '.$disabled.' '.$extra.'/>';
1600 1600
 
1601 1601
         // enqueue scripts
1602 1602
         wp_register_style(
1603 1603
             'espresso-ui-theme',
1604
-            EE_GLOBAL_ASSETS_URL . 'css/espresso-ui-theme/jquery-ui-1.10.3.custom.min.css',
1604
+            EE_GLOBAL_ASSETS_URL.'css/espresso-ui-theme/jquery-ui-1.10.3.custom.min.css',
1605 1605
             [],
1606 1606
             EVENT_ESPRESSO_VERSION
1607 1607
         );
@@ -1609,7 +1609,7 @@  discard block
 block discarded – undo
1609 1609
         wp_enqueue_script('jquery-ui-datepicker');
1610 1610
 
1611 1611
         $input_html = apply_filters('FHEE__EEH_Form_Fields__input_html', $input_html, $label_html, $id);
1612
-        return $label_html . $input_html;
1612
+        return $label_html.$input_html;
1613 1613
     }
1614 1614
 
1615 1615
 
@@ -1636,7 +1636,7 @@  discard block
 block discarded – undo
1636 1636
     public static function hidden_input($name, $value, $id = '')
1637 1637
     {
1638 1638
         $id = ! empty($id) ? $id : $name;
1639
-        return '<input id="' . $id . '" type="hidden" name="' . $name . '" value="' . $value . '"/>';
1639
+        return '<input id="'.$id.'" type="hidden" name="'.$name.'" value="'.$value.'"/>';
1640 1640
     }
1641 1641
 
1642 1642
 
@@ -1681,7 +1681,7 @@  discard block
 block discarded – undo
1681 1681
         $prepped_answer_options = [];
1682 1682
         if (is_array($QSOs) && ! empty($QSOs)) {
1683 1683
             foreach ($QSOs as $key => $QSO) {
1684
-                if (! $QSO instanceof EE_Question_Option) {
1684
+                if ( ! $QSO instanceof EE_Question_Option) {
1685 1685
                     $QSO = EE_Question_Option::new_instance(
1686 1686
                         [
1687 1687
                             'QSO_value' => is_array($QSO) && isset($QSO['id'])
@@ -1694,7 +1694,7 @@  discard block
 block discarded – undo
1694 1694
                     );
1695 1695
                 }
1696 1696
                 if ($QSO->opt_group()) {
1697
-                    $prepped_answer_options[ $QSO->opt_group() ][] = $QSO;
1697
+                    $prepped_answer_options[$QSO->opt_group()][] = $QSO;
1698 1698
                 } else {
1699 1699
                     $prepped_answer_options[] = $QSO;
1700 1700
                 }
@@ -1906,7 +1906,7 @@  discard block
 block discarded – undo
1906 1906
         $options = [];
1907 1907
         for ($x = 1; $x <= 12; $x++) {
1908 1908
             $mm             = str_pad($x, 2, '0', STR_PAD_LEFT);
1909
-            $options[ $mm ] = $mm;
1909
+            $options[$mm] = $mm;
1910 1910
         }
1911 1911
         return EEH_Form_Fields::prep_answer_options($options);
1912 1912
     }
@@ -1924,7 +1924,7 @@  discard block
 block discarded – undo
1924 1924
         $next_decade  = $current_year + 10;
1925 1925
         for ($x = $current_year; $x <= $next_decade; $x++) {
1926 1926
             $yy             = str_pad($x, 2, '0', STR_PAD_LEFT);
1927
-            $options[ $yy ] = $yy;
1927
+            $options[$yy] = $yy;
1928 1928
         }
1929 1929
         return EEH_Form_Fields::prep_answer_options($options);
1930 1930
     }
@@ -1943,7 +1943,7 @@  discard block
 block discarded – undo
1943 1943
     public static function generate_registration_months_dropdown($cur_date = '', $status = '', $evt_category = 0)
1944 1944
     {
1945 1945
         $_where = [];
1946
-        if (! empty($status)) {
1946
+        if ( ! empty($status)) {
1947 1947
             $_where['STS_ID'] = $status;
1948 1948
         }
1949 1949
 
@@ -1962,7 +1962,7 @@  discard block
 block discarded – undo
1962 1962
         ];
1963 1963
 
1964 1964
         foreach ($regdtts as $regdtt) {
1965
-            $date      = $regdtt->reg_month . ' ' . $regdtt->reg_year;
1965
+            $date      = $regdtt->reg_month.' '.$regdtt->reg_year;
1966 1966
             $options[] = [
1967 1967
                 'text' => $date,
1968 1968
                 'id'   => $date,
@@ -2006,7 +2006,7 @@  discard block
 block discarded – undo
2006 2006
         }
2007 2007
 
2008 2008
         // categories?
2009
-        if (! empty($evt_category) and $evt_category > 0) {
2009
+        if ( ! empty($evt_category) and $evt_category > 0) {
2010 2010
             $where['Event.Term_Taxonomy.taxonomy'] = 'espresso_event_categories';
2011 2011
             $where['Event.Term_Taxonomy.term_id']  = $evt_category;
2012 2012
         }
@@ -2028,8 +2028,8 @@  discard block
 block discarded – undo
2028 2028
         global $wp_locale;
2029 2029
 
2030 2030
         foreach ($DTTS as $DTT) {
2031
-            $localized_date = $wp_locale->get_month($DTT->dtt_month_num) . ' ' . $DTT->dtt_year;
2032
-            $id             = $DTT->dtt_month . ' ' . $DTT->dtt_year;
2031
+            $localized_date = $wp_locale->get_month($DTT->dtt_month_num).' '.$DTT->dtt_year;
2032
+            $id             = $DTT->dtt_month.' '.$DTT->dtt_year;
2033 2033
             $options[]      = [
2034 2034
                 'text' => $localized_date,
2035 2035
                 'id'   => $id,
@@ -2102,16 +2102,16 @@  discard block
 block discarded – undo
2102 2102
             return $btn;
2103 2103
         }
2104 2104
         $text = ! empty($text) ? $text : esc_html__('Submit', 'event_espresso');
2105
-        $btn  .= '<input id="' . $ID . '-btn" class="' . $class . '" '
2106
-                 . 'type="submit" value="' . $text . '" ' . $extra_attributes . '/>';
2107
-        if (! $input_only) {
2108
-            $btn_frm = '<form id="' . $ID . '-frm" method="POST" action="' . $url . '">';
2105
+        $btn .= '<input id="'.$ID.'-btn" class="'.$class.'" '
2106
+                 . 'type="submit" value="'.$text.'" '.$extra_attributes.'/>';
2107
+        if ( ! $input_only) {
2108
+            $btn_frm = '<form id="'.$ID.'-frm" method="POST" action="'.$url.'">';
2109 2109
             $btn_frm .= ! empty($nonce_action)
2110
-                ? wp_nonce_field($nonce_action, $nonce_action . '_nonce', true, false)
2110
+                ? wp_nonce_field($nonce_action, $nonce_action.'_nonce', true, false)
2111 2111
                 : '';
2112 2112
             $btn_frm .= $btn;
2113 2113
             $btn_frm .= '</form>';
2114
-            $btn     = $btn_frm;
2114
+            $btn = $btn_frm;
2115 2115
             unset($btn_frm);
2116 2116
         }
2117 2117
         return $btn;
Please login to merge, or discard this patch.
core/helpers/EEH_MSG_Template.helper.php 1 patch
Indentation   +1258 added lines, -1258 removed lines patch added patch discarded remove patch
@@ -14,1265 +14,1265 @@
 block discarded – undo
14 14
  */
15 15
 class EEH_MSG_Template
16 16
 {
17
-    /**
18
-     * Holds a collection of EE_Message_Template_Pack objects.
19
-     * @type EE_Messages_Template_Pack_Collection
20
-     */
21
-    protected static $_template_pack_collection;
22
-
23
-
24
-    /**
25
-     * @throws EE_Error
26
-     */
27
-    private static function _set_autoloader()
28
-    {
29
-        EED_Messages::set_autoloaders();
30
-    }
31
-
32
-
33
-    /**
34
-     * generate_new_templates
35
-     * This will handle the messenger, message_type selection when "adding a new custom template" for an event and will
36
-     * automatically create the defaults for the event.  The user would then be redirected to edit the default context
37
-     * for the event.
38
-     *
39
-     * @access protected
40
-     * @param string $messenger     the messenger we are generating templates for
41
-     * @param array  $message_types array of message types that the templates are generated for.
42
-     * @param int    $GRP_ID        If a non global template is being generated then it is expected we'll have a GRP_ID
43
-     *                              to use as the base for the new generated template.
44
-     * @param bool   $global        true indicates generating templates on messenger activation. false requires GRP_ID
45
-     *                              for event specific template generation.
46
-     * @return array  @see EEH_MSG_Template::_create_new_templates for the return value of each element in the array
47
-     *                for templates that are generated.  If this is an empty array then it means no templates were
48
-     *                generated which usually means there was an error.  Anything in the array with an empty value for
49
-     *                `MTP_context` means that it was not a new generated template but just reactivated (which only
50
-     *                happens for global templates that already exist in the database.
51
-     * @throws EE_Error
52
-     * @throws ReflectionException
53
-     */
54
-    public static function generate_new_templates($messenger, $message_types, $GRP_ID = 0, $global = false)
55
-    {
56
-        // make sure message_type is an array.
57
-        $message_types = (array) $message_types;
58
-        $templates = array();
59
-
60
-        if (empty($messenger)) {
61
-            throw new EE_Error(esc_html__('We need a messenger to generate templates!', 'event_espresso'));
62
-        }
63
-
64
-        // if we STILL have empty $message_types then we need to generate an error message b/c we NEED message types to do the template files.
65
-        if (empty($message_types)) {
66
-            throw new EE_Error(esc_html__('We need at least one message type to generate templates!', 'event_espresso'));
67
-        }
68
-
69
-        EEH_MSG_Template::_set_autoloader();
70
-        foreach ($message_types as $message_type) {
71
-
72
-            // if this is global template generation.
73
-            if ($global) {
74
-                // let's attempt to get the GRP_ID for this combo IF GRP_ID is empty.
75
-                if (empty($GRP_ID)) {
76
-                    $GRP_ID = EEM_Message_Template_Group::instance()->get_one(
77
-                        array(
78
-                            array(
79
-                                'MTP_messenger'    => $messenger,
80
-                                'MTP_message_type' => $message_type,
81
-                                'MTP_is_global'    => true,
82
-                            ),
83
-                        )
84
-                    );
85
-                    $GRP_ID = $GRP_ID instanceof EE_Message_Template_Group ? $GRP_ID->ID() : 0;
86
-                }
87
-                // First let's determine if we already HAVE global templates for this messenger and message_type combination.
88
-                //  If we do then NO generation!!
89
-                if (EEH_MSG_Template::already_generated($messenger, $message_type, $GRP_ID)) {
90
-                    $templates[] = array(
91
-                        'GRP_ID' => $GRP_ID,
92
-                        'MTP_context' => '',
93
-                    );
94
-                    // we already have generated templates for this so let's go to the next message type.
95
-                    continue;
96
-                }
97
-            }
98
-            $new_message_template_group = EEH_MSG_Template::create_new_templates(
99
-                $messenger,
100
-                $message_type,
101
-                $GRP_ID,
102
-                $global
103
-            );
104
-
105
-            if (! $new_message_template_group) {
106
-                continue;
107
-            }
108
-            $templates[] = $new_message_template_group;
109
-        }
110
-
111
-        return $templates;
112
-    }
113
-
114
-
115
-    /**
116
-     * The purpose of this method is to determine if there are already generated templates in the database for the
117
-     * given variables.
118
-     *
119
-     * @param string $messenger    messenger
120
-     * @param string $message_type message type
121
-     * @param int    $GRP_ID       GRP ID ( if a custom template) (if not provided then we're just doing global
122
-     *                             template check)
123
-     * @return bool                true = generated, false = hasn't been generated.
124
-     * @throws EE_Error
125
-     */
126
-    public static function already_generated($messenger, $message_type, $GRP_ID = 0)
127
-    {
128
-        EEH_MSG_Template::_set_autoloader();
129
-        // what method we use depends on whether we have an GRP_ID or not
130
-        $count = empty($GRP_ID)
131
-            ? EEM_Message_Template::instance()->count(
132
-                array(
133
-                    array(
134
-                        'Message_Template_Group.MTP_messenger'    => $messenger,
135
-                        'Message_Template_Group.MTP_message_type' => $message_type,
136
-                        'Message_Template_Group.MTP_is_global'    => true
137
-                    )
138
-                )
139
-            )
140
-            : EEM_Message_Template::instance()->count(array( array( 'GRP_ID' => $GRP_ID ) ));
141
-
142
-        return $count > 0;
143
-    }
144
-
145
-
146
-    /**
147
-     * Updates all message templates matching the incoming messengers and message types to active status.
148
-     *
149
-     * @static
150
-     * @param array $messenger_names    Messenger slug
151
-     * @param array $message_type_names Message type slug
152
-     * @return  int                         count of updated records.
153
-     * @throws EE_Error
154
-     */
155
-    public static function update_to_active($messenger_names, $message_type_names)
156
-    {
157
-        $messenger_names = is_array($messenger_names) ? $messenger_names : array( $messenger_names );
158
-        $message_type_names = is_array($message_type_names) ? $message_type_names : array( $message_type_names );
159
-        return EEM_Message_Template_Group::instance()->update(
160
-            array( 'MTP_is_active' => 1 ),
161
-            array(
162
-                array(
163
-                    'MTP_messenger'     => array( 'IN', $messenger_names ),
164
-                    'MTP_message_type'  => array( 'IN', $message_type_names )
165
-                )
166
-            )
167
-        );
168
-    }
169
-
170
-
171
-    /**
172
-     * Updates all message template groups matching the incoming arguments to inactive status.
173
-     *
174
-     * @static
175
-     * @param array $messenger_names    The messenger slugs.
176
-     *                                  If empty then all templates matching the message types are marked inactive.
177
-     *                                  Otherwise only templates matching the messengers and message types.
178
-     * @param array $message_type_names The message type slugs.
179
-     *                                  If empty then all templates matching the messengers are marked inactive.
180
-     *                                  Otherwise only templates matching the messengers and message types.
181
-     *
182
-     * @return int  count of updated records.
183
-     * @throws EE_Error
184
-     */
185
-    public static function update_to_inactive($messenger_names = array(), $message_type_names = array())
186
-    {
187
-        return EEM_Message_Template_Group::instance()->deactivate_message_template_groups_for(
188
-            $messenger_names,
189
-            $message_type_names
190
-        );
191
-    }
192
-
193
-
194
-    /**
195
-     * The purpose of this function is to return all installed message objects
196
-     * (messengers and message type regardless of whether they are ACTIVE or not)
197
-     *
198
-     * @param string $type
199
-     * @return array array consisting of installed messenger objects and installed message type objects.
200
-     * @throws EE_Error
201
-     * @throws ReflectionException
202
-     * @deprecated 4.9.0
203
-     * @static
204
-     */
205
-    public static function get_installed_message_objects($type = 'all')
206
-    {
207
-        self::_set_autoloader();
208
-        $message_resource_manager = EE_Registry::instance()->load_lib('Message_Resource_Manager');
209
-        return array(
210
-            'messenger' => $message_resource_manager->installed_messengers(),
211
-            'message_type' => $message_resource_manager->installed_message_types()
212
-        );
213
-    }
214
-
215
-
216
-    /**
217
-     * This will return an array of shortcodes => labels from the
218
-     * messenger and message_type objects associated with this
219
-     * template.
220
-     *
221
-     * @param string $message_type
222
-     * @param string $messenger
223
-     * @param array  $fields                        What fields we're returning valid shortcodes for.
224
-     *                                              If empty then we assume all fields are to be returned. Optional.
225
-     * @param string $context                       What context we're going to return shortcodes for. Optional.
226
-     * @param bool   $merged                        If TRUE then we don't return shortcodes indexed by field,
227
-     *                                              but instead an array of the unique shortcodes for all the given (
228
-     *                                              or all) fields. Optional.
229
-     * @return array                                an array of shortcodes in the format
230
-     *                                              array( '[shortcode] => 'label')
231
-     *                                              OR
232
-     *                                              FALSE if no shortcodes found.
233
-     * @throws ReflectionException
234
-     * @throws EE_Error*@since 4.3.0
235
-     *
236
-     */
237
-    public static function get_shortcodes(
238
-        $message_type,
239
-        $messenger,
240
-        $fields = array(),
241
-        $context = 'admin',
242
-        $merged = false
243
-    ) {
244
-        $messenger_name = str_replace(' ', '_', ucwords(str_replace('_', ' ', $messenger)));
245
-        $mt_name = str_replace(' ', '_', ucwords(str_replace('_', ' ', $message_type)));
246
-        /** @var EE_Message_Resource_Manager $message_resource_manager */
247
-        $message_resource_manager = EE_Registry::instance()->load_lib('Message_Resource_Manager');
248
-        // convert slug to object
249
-        $messenger = $message_resource_manager->get_messenger($messenger);
250
-
251
-        // if messenger isn't a EE_messenger resource then bail.
252
-        if (! $messenger instanceof EE_messenger) {
253
-            return array();
254
-        }
255
-
256
-        // validate class for getting our list of shortcodes
257
-        $classname = 'EE_Messages_' . $messenger_name . '_' . $mt_name . '_Validator';
258
-        if (! class_exists($classname)) {
259
-            $msg[] = esc_html__('The Validator class was unable to load', 'event_espresso');
260
-            $msg[] = sprintf(
261
-                esc_html__('The class name compiled was %s. Please check and make sure the spelling and case is correct for the class name and that there is an autoloader in place for this class', 'event_espresso'),
262
-                $classname
263
-            );
264
-            throw new EE_Error(implode('||', $msg));
265
-        }
266
-
267
-        /** @type EE_Messages_Validator $_VLD */
268
-        $_VLD = new $classname(array(), $context);
269
-        $valid_shortcodes = $_VLD->get_validators();
270
-
271
-        // let's make sure we're only getting the shortcode part of the validators
272
-        $shortcodes = array();
273
-        foreach ($valid_shortcodes as $field => $validators) {
274
-            $shortcodes[ $field ] = $validators['shortcodes'];
275
-        }
276
-        $valid_shortcodes = $shortcodes;
277
-
278
-        // if not all fields let's make sure we ONLY include the shortcodes for the specified fields.
279
-        if (! empty($fields)) {
280
-            $specified_shortcodes = array();
281
-            foreach ($fields as $field) {
282
-                if (isset($valid_shortcodes[ $field ])) {
283
-                    $specified_shortcodes[ $field ] = $valid_shortcodes[ $field ];
284
-                }
285
-            }
286
-            $valid_shortcodes = $specified_shortcodes;
287
-        }
288
-
289
-        // if not merged then let's replace the fields with the localized fields
290
-        if (! $merged) {
291
-            // let's get all the fields for the set messenger so that we can get the localized label and use that in the returned array.
292
-            $field_settings = $messenger->get_template_fields();
293
-            $localized = array();
294
-            foreach ($valid_shortcodes as $field => $shortcodes) {
295
-                // get localized field label
296
-                if (isset($field_settings[ $field ])) {
297
-                    // possible that this is used as a main field.
298
-                    if (empty($field_settings[ $field ])) {
299
-                        if (isset($field_settings['extra'][ $field ])) {
300
-                            $_field = $field_settings['extra'][ $field ]['main']['label'];
301
-                        } else {
302
-                            $_field = $field;
303
-                        }
304
-                    } else {
305
-                        $_field = $field_settings[ $field ]['label'];
306
-                    }
307
-                } elseif (isset($field_settings['extra'])) {
308
-                    // loop through extra "main fields" and see if any of their children have our field
309
-                    foreach ($field_settings['extra'] as $fields) {
310
-                        if (isset($fields[ $field ])) {
311
-                            $_field = $fields[ $field ]['label'];
312
-                        } else {
313
-                            $_field = $field;
314
-                        }
315
-                    }
316
-                } else {
317
-                    $_field = $field;
318
-                }
319
-                if (isset($_field)) {
320
-                    $localized[ (string) $_field ] = $shortcodes;
321
-                }
322
-            }
323
-            $valid_shortcodes = $localized;
324
-        }
325
-
326
-        // if $merged then let's merge all the shortcodes into one list NOT indexed by field.
327
-        if ($merged) {
328
-            $merged_codes = array();
329
-            foreach ($valid_shortcodes as $shortcode) {
330
-                foreach ($shortcode as $code => $label) {
331
-                    if (isset($merged_codes[ $code ])) {
332
-                        continue;
333
-                    } else {
334
-                        $merged_codes[ $code ] = $label;
335
-                    }
336
-                }
337
-            }
338
-            $valid_shortcodes = $merged_codes;
339
-        }
340
-
341
-        return $valid_shortcodes;
342
-    }
343
-
344
-
345
-    /**
346
-     * Get Messenger object.
347
-     *
348
-     * @param string $messenger messenger slug for the messenger object we want to retrieve.
349
-     * @return EE_messenger
350
-     * @throws ReflectionException
351
-     * @throws EE_Error*@since 4.3.0
352
-     * @deprecated 4.9.0
353
-     */
354
-    public static function messenger_obj($messenger)
355
-    {
356
-        /** @type EE_Message_Resource_Manager $Message_Resource_Manager */
357
-        $Message_Resource_Manager = EE_Registry::instance()->load_lib('Message_Resource_Manager');
358
-        return $Message_Resource_Manager->get_messenger($messenger);
359
-    }
360
-
361
-
362
-    /**
363
-     * get Message type object
364
-     *
365
-     * @param string $message_type the slug for the message type object to retrieve
366
-     * @return EE_message_type
367
-     * @throws ReflectionException
368
-     * @throws EE_Error*@since 4.3.0
369
-     * @deprecated 4.9.0
370
-     */
371
-    public static function message_type_obj($message_type)
372
-    {
373
-        /** @type EE_Message_Resource_Manager $Message_Resource_Manager */
374
-        $Message_Resource_Manager = EE_Registry::instance()->load_lib('Message_Resource_Manager');
375
-        return $Message_Resource_Manager->get_message_type($message_type);
376
-    }
377
-
378
-
379
-    /**
380
-     * Given a message_type slug, will return whether that message type is active in the system or not.
381
-     *
382
-     * @since    4.3.0
383
-     * @param string $message_type message type to check for.
384
-     * @return boolean
385
-     * @throws EE_Error
386
-     * @throws ReflectionException
387
-     */
388
-    public static function is_mt_active($message_type)
389
-    {
390
-        /** @type EE_Message_Resource_Manager $Message_Resource_Manager */
391
-        $Message_Resource_Manager = EE_Registry::instance()->load_lib('Message_Resource_Manager');
392
-        $active_mts = $Message_Resource_Manager->list_of_active_message_types();
393
-        return in_array($message_type, $active_mts);
394
-    }
395
-
396
-
397
-    /**
398
-     * Given a messenger slug, will return whether that messenger is active in the system or not.
399
-     *
400
-     * @since    4.3.0
401
-     *
402
-     * @param string $messenger slug for messenger to check.
403
-     * @return boolean
404
-     * @throws EE_Error
405
-     * @throws ReflectionException
406
-     */
407
-    public static function is_messenger_active($messenger)
408
-    {
409
-        /** @type EE_Message_Resource_Manager $Message_Resource_Manager */
410
-        $Message_Resource_Manager = EE_Registry::instance()->load_lib('Message_Resource_Manager');
411
-        $active_messenger = $Message_Resource_Manager->get_active_messenger($messenger);
412
-        return $active_messenger instanceof EE_messenger;
413
-    }
414
-
415
-
416
-    /**
417
-     * Used to return active messengers array stored in the wp options table.
418
-     * If no value is present in the option then an empty array is returned.
419
-     *
420
-     * @deprecated 4.9
421
-     * @since      4.3.1
422
-     *
423
-     * @return array
424
-     * @throws EE_Error
425
-     * @throws ReflectionException
426
-     */
427
-    public static function get_active_messengers_in_db()
428
-    {
429
-        EE_Error::doing_it_wrong(
430
-            __METHOD__,
431
-            esc_html__('Please use EE_Message_Resource_Manager::get_active_messengers_option() instead.', 'event_espresso'),
432
-            '4.9.0'
433
-        );
434
-        /** @var EE_Message_Resource_Manager $Message_Resource_Manager */
435
-        $Message_Resource_Manager = EE_Registry::instance()->load_lib('Message_Resource_Manager');
436
-        return $Message_Resource_Manager->get_active_messengers_option();
437
-    }
438
-
439
-
440
-    /**
441
-     * Used to update the active messengers array stored in the wp options table.
442
-     *
443
-     * @since      4.3.1
444
-     * @deprecated 4.9.0
445
-     *
446
-     * @param array $data_to_save Incoming data to save.
447
-     *
448
-     * @return bool FALSE if not updated, TRUE if updated.
449
-     * @throws EE_Error
450
-     * @throws ReflectionException
451
-     */
452
-    public static function update_active_messengers_in_db($data_to_save)
453
-    {
454
-        EE_Error::doing_it_wrong(
455
-            __METHOD__,
456
-            esc_html__('Please use EE_Message_Resource_Manager::update_active_messengers_option() instead.', 'event_espresso'),
457
-            '4.9.0'
458
-        );
459
-        /** @var EE_Message_Resource_Manager $Message_Resource_Manager */
460
-        $Message_Resource_Manager = EE_Registry::instance()->load_lib('Message_Resource_Manager');
461
-        return $Message_Resource_Manager->update_active_messengers_option($data_to_save);
462
-    }
463
-
464
-
465
-    /**
466
-     * This does some validation of incoming params, determines what type of url is being prepped and returns the
467
-     * appropriate url trigger
468
-     *
469
-     * @param EE_message_type $message_type
470
-     * @param EE_Message $message
471
-     * @param EE_Registration | null $registration  The registration object must be included if this
472
-     *                                              is going to be a registration trigger url.
473
-     * @param string $sending_messenger             The (optional) sending messenger for the url.
474
-     *
475
-     * @return string
476
-     * @throws EE_Error
477
-     */
478
-    public static function get_url_trigger(
479
-        EE_message_type $message_type,
480
-        EE_Message $message,
481
-        $registration = null,
482
-        $sending_messenger = ''
483
-    ) {
484
-        // first determine if the url can be to the EE_Message object.
485
-        if (! $message_type->always_generate()) {
486
-            return EEH_MSG_Template::generate_browser_trigger($message);
487
-        }
488
-
489
-        // if $registration object is not valid then exit early because there's nothing that can be generated.
490
-        if (! $registration instanceof EE_Registration) {
491
-            throw new EE_Error(
492
-                esc_html__('Incoming value for registration is not a valid EE_Registration object.', 'event_espresso')
493
-            );
494
-        }
495
-
496
-        // validate given context
497
-        $contexts = $message_type->get_contexts();
498
-        if ($message->context() !== '' && ! isset($contexts[ $message->context() ])) {
499
-            throw new EE_Error(
500
-                sprintf(
501
-                    esc_html__('The context %s is not a valid context for %s.', 'event_espresso'),
502
-                    $message->context(),
503
-                    get_class($message_type)
504
-                )
505
-            );
506
-        }
507
-
508
-        // valid sending messenger but only if sending messenger set.  Otherwise generating messenger is used.
509
-        if (! empty($sending_messenger)) {
510
-            $with_messengers = $message_type->with_messengers();
511
-            if (
512
-                ! isset($with_messengers[ $message->messenger() ])
513
-                 || ! in_array($sending_messenger, $with_messengers[ $message->messenger() ])
514
-            ) {
515
-                throw new EE_Error(
516
-                    sprintf(
517
-                        esc_html__(
518
-                            'The given sending messenger string (%1$s) does not match a valid sending messenger with the %2$s.  If this is incorrect, make sure that the message type has defined this messenger as a sending messenger in its $_with_messengers array.',
519
-                            'event_espresso'
520
-                        ),
521
-                        $sending_messenger,
522
-                        get_class($message_type)
523
-                    )
524
-                );
525
-            }
526
-        } else {
527
-            $sending_messenger = $message->messenger();
528
-        }
529
-        return EEH_MSG_Template::generate_url_trigger(
530
-            $sending_messenger,
531
-            $message->messenger(),
532
-            $message->context(),
533
-            $message->message_type(),
534
-            $registration,
535
-            $message->GRP_ID()
536
-        );
537
-    }
538
-
539
-
540
-    /**
541
-     * This returns the url for triggering a in browser view of a specific EE_Message object.
542
-     * @param EE_Message $message
543
-     * @return string.
544
-     */
545
-    public static function generate_browser_trigger(EE_Message $message)
546
-    {
547
-        $query_args = array(
548
-            'ee' => 'msg_browser_trigger',
549
-            'token' => $message->MSG_token()
550
-        );
551
-        return apply_filters(
552
-            'FHEE__EEH_MSG_Template__generate_browser_trigger',
553
-            add_query_arg($query_args, site_url()),
554
-            $message
555
-        );
556
-    }
557
-
558
-
559
-
560
-
561
-
562
-
563
-    /**
564
-     * This returns the url for triggering an in browser view of the error saved on the incoming message object.
565
-     * @param EE_Message $message
566
-     * @return string
567
-     */
568
-    public static function generate_error_display_trigger(EE_Message $message)
569
-    {
570
-        return apply_filters(
571
-            'FHEE__EEH_MSG_Template__generate_error_display_trigger',
572
-            add_query_arg(
573
-                array(
574
-                    'ee' => 'msg_browser_error_trigger',
575
-                    'token' => $message->MSG_token()
576
-                ),
577
-                site_url()
578
-            ),
579
-            $message
580
-        );
581
-    }
582
-
583
-
584
-    /**
585
-     * This generates a url trigger for the msg_url_trigger route using the given arguments
586
-     *
587
-     * @param string          $sending_messenger      The sending messenger slug.
588
-     * @param string          $generating_messenger   The generating messenger slug.
589
-     * @param string          $context                The context for the template.
590
-     * @param string          $message_type           The message type slug
591
-     * @param EE_Registration $registration
592
-     * @param integer         $message_template_group id   The EE_Message_Template_Group ID for the template.
593
-     * @param integer         $data_id                The id to the EE_Base_Class for getting the data used by the
594
-     *                                                trigger.
595
-     * @return string          The generated url.
596
-     * @throws EE_Error
597
-     */
598
-    public static function generate_url_trigger(
599
-        $sending_messenger,
600
-        $generating_messenger,
601
-        $context,
602
-        $message_type,
603
-        EE_Registration $registration,
604
-        $message_template_group,
605
-        $data_id = 0
606
-    ) {
607
-        $query_args = array(
608
-            'ee' => 'msg_url_trigger',
609
-            'snd_msgr' => $sending_messenger,
610
-            'gen_msgr' => $generating_messenger,
611
-            'message_type' => $message_type,
612
-            'context' => $context,
613
-            'token' => $registration->reg_url_link(),
614
-            'GRP_ID' => $message_template_group,
615
-            'id' => $data_id
616
-            );
617
-        $url = add_query_arg($query_args, get_home_url());
618
-
619
-        // made it here so now we can just get the url and filter it.  Filtered globally and by message type.
620
-        return apply_filters(
621
-            'FHEE__EEH_MSG_Template__generate_url_trigger',
622
-            $url,
623
-            $sending_messenger,
624
-            $generating_messenger,
625
-            $context,
626
-            $message_type,
627
-            $registration,
628
-            $message_template_group,
629
-            $data_id
630
-        );
631
-    }
632
-
633
-
634
-
635
-
636
-    /**
637
-     * Return the specific css for the action icon given.
638
-     *
639
-     * @param string $type  What action to return.
640
-     * @return string[]
641
-     * @since 4.9.0
642
-     */
643
-    public static function get_message_action_icon($type)
644
-    {
645
-        $action_icons = self::get_message_action_icons();
646
-        return isset($action_icons[ $type ]) ? $action_icons[ $type ] : [];
647
-    }
648
-
649
-
650
-    /**
651
-     * This is used for retrieving the css classes used for the icons representing message actions.
652
-     *
653
-     * @since 4.9.0
654
-     *
655
-     * @return array
656
-     */
657
-    public static function get_message_action_icons()
658
-    {
659
-        return apply_filters(
660
-            'FHEE__EEH_MSG_Template__message_action_icons',
661
-            array(
662
-                'view' => array(
663
-                    'label' => esc_html__('View Message', 'event_espresso'),
664
-                    'css_class' => 'dashicons dashicons-visibility',
665
-                ),
666
-                'error' => array(
667
-                    'label' => esc_html__('View Error Message', 'event_espresso'),
668
-                    'css_class' => 'dashicons dashicons-info',
669
-                ),
670
-                'see_notifications_for' => array(
671
-                    'label' => esc_html__('View Related Messages', 'event_espresso'),
672
-                    'css_class' => 'dashicons dashicons-megaphone',
673
-                ),
674
-                'generate_now' => array(
675
-                    'label' => esc_html__('Generate the message now.', 'event_espresso'),
676
-                    'css_class' => 'dashicons dashicons-admin-tools',
677
-                ),
678
-                'send_now' => array(
679
-                    'label' => esc_html__('Send Immediately', 'event_espresso'),
680
-                    'css_class' => 'dashicons dashicons-controls-forward',
681
-                ),
682
-                'queue_for_resending' => array(
683
-                    'label' => esc_html__('Queue for Resending', 'event_espresso'),
684
-                    'css_class' => 'dashicons dashicons-controls-repeat',
685
-                ),
686
-                'view_transaction' => array(
687
-                    'label' => esc_html__('View related Transaction', 'event_espresso'),
688
-                    'css_class' => 'dashicons dashicons-cart',
689
-                )
690
-            )
691
-        );
692
-    }
693
-
694
-
695
-    /**
696
-     * This returns the url for a given action related to EE_Message.
697
-     *
698
-     * @param string     $type         What type of action to return the url for.
699
-     * @param EE_Message $message      Required for generating the correct url for some types.
700
-     * @param array      $query_params Any additional query params to be included with the generated url.
701
-     *
702
-     * @return string
703
-     * @throws EE_Error
704
-     * @throws ReflectionException
705
-     * @since 4.9.0
706
-     *
707
-     */
708
-    public static function get_message_action_url($type, EE_Message $message = null, $query_params = array())
709
-    {
710
-        $action_urls = self::get_message_action_urls($message, $query_params);
711
-        return isset($action_urls[ $type ])  ? $action_urls[ $type ] : '';
712
-    }
713
-
714
-
715
-    /**
716
-     * This returns all the current urls for EE_Message actions.
717
-     *
718
-     * @since 4.9.0
719
-     *
720
-     * @param EE_Message $message      The EE_Message object required to generate correct urls for some types.
721
-     * @param array      $query_params Any additional query_params to be included with the generated url.
722
-     *
723
-     * @return array
724
-     * @throws EE_Error
725
-     * @throws ReflectionException
726
-     */
727
-    public static function get_message_action_urls(EE_Message $message = null, $query_params = array())
728
-    {
729
-        EE_Registry::instance()->load_helper('URL');
730
-        // if $message is not an instance of EE_Message then let's just do a dummy.
731
-        $message = empty($message) ? EE_Message_Factory::create() : $message;
732
-        $action_urls =  apply_filters(
733
-            'FHEE__EEH_MSG_Template__get_message_action_url',
734
-            array(
735
-                'view' => EEH_MSG_Template::generate_browser_trigger($message),
736
-                'error' => EEH_MSG_Template::generate_error_display_trigger($message),
737
-                'see_notifications_for' => EEH_URL::add_query_args_and_nonce(
738
-                    array_merge(
739
-                        array(
740
-                            'page' => 'espresso_messages',
741
-                            'action' => 'default',
742
-                            'filterby' => 1,
743
-                        ),
744
-                        $query_params
745
-                    ),
746
-                    admin_url('admin.php')
747
-                ),
748
-                'generate_now' => EEH_URL::add_query_args_and_nonce(
749
-                    array(
750
-                        'page' => 'espresso_messages',
751
-                        'action' => 'generate_now',
752
-                        'MSG_ID' => $message->ID()
753
-                    ),
754
-                    admin_url('admin.php')
755
-                ),
756
-                'send_now' => EEH_URL::add_query_args_and_nonce(
757
-                    array(
758
-                        'page' => 'espresso_messages',
759
-                        'action' => 'send_now',
760
-                        'MSG_ID' => $message->ID()
761
-                    ),
762
-                    admin_url('admin.php')
763
-                ),
764
-                'queue_for_resending' => EEH_URL::add_query_args_and_nonce(
765
-                    array(
766
-                        'page' => 'espresso_messages',
767
-                        'action' => 'queue_for_resending',
768
-                        'MSG_ID' => $message->ID()
769
-                    ),
770
-                    admin_url('admin.php')
771
-                ),
772
-            )
773
-        );
774
-        if (
775
-            $message->TXN_ID() > 0
776
-            && EE_Registry::instance()->CAP->current_user_can(
777
-                'ee_read_transaction',
778
-                'espresso_transactions_default',
779
-                $message->TXN_ID()
780
-            )
781
-        ) {
782
-            $action_urls['view_transaction'] = EEH_URL::add_query_args_and_nonce(
783
-                array(
784
-                    'page' => 'espresso_transactions',
785
-                    'action' => 'view_transaction',
786
-                    'TXN_ID' => $message->TXN_ID()
787
-                ),
788
-                admin_url('admin.php')
789
-            );
790
-        } else {
791
-            $action_urls['view_transaction'] = '';
792
-        }
793
-        return $action_urls;
794
-    }
795
-
796
-
797
-    /**
798
-     * This returns a generated link html including the icon used for the action link for EE_Message actions.
799
-     *
800
-     * @param string          $type         What type of action the link is for (if invalid type is passed in then an
801
-     *                                      empty string is returned)
802
-     * @param EE_Message|null $message      The EE_Message object (required for some actions to generate correctly)
803
-     * @param array           $query_params Any extra query params to include in the generated link.
804
-     *
805
-     * @return string
806
-     * @throws EE_Error
807
-     * @throws ReflectionException
808
-     * @since 4.9.0
809
-     *
810
-     */
811
-    public static function get_message_action_link($type, EE_Message $message = null, $query_params = array())
812
-    {
813
-        $url = EEH_MSG_Template::get_message_action_url($type, $message, $query_params);
814
-        $icon_css = EEH_MSG_Template::get_message_action_icon($type);
815
-        $label = $icon_css['label'] ?? null;
816
-        $label = $label ? 'aria-label="' . $label . '"' : '';
817
-        $class = $label ? ' ee-aria-tooltip' : '';
818
-
819
-        if (empty($url) || empty($icon_css) || ! isset($icon_css['css_class'])) {
820
-            return '';
821
-        }
822
-
823
-        $icon_css_class = $icon_css['css_class'] . apply_filters(
824
-            'FHEE__EEH_MSG_Template__get_message_action_link__icon_css_class',
825
-            ' js-ee-message-action-link ee-message-action-link-' . $type,
826
-            $type,
827
-            $message,
828
-            $query_params
829
-        );
830
-
831
-        return '
17
+	/**
18
+	 * Holds a collection of EE_Message_Template_Pack objects.
19
+	 * @type EE_Messages_Template_Pack_Collection
20
+	 */
21
+	protected static $_template_pack_collection;
22
+
23
+
24
+	/**
25
+	 * @throws EE_Error
26
+	 */
27
+	private static function _set_autoloader()
28
+	{
29
+		EED_Messages::set_autoloaders();
30
+	}
31
+
32
+
33
+	/**
34
+	 * generate_new_templates
35
+	 * This will handle the messenger, message_type selection when "adding a new custom template" for an event and will
36
+	 * automatically create the defaults for the event.  The user would then be redirected to edit the default context
37
+	 * for the event.
38
+	 *
39
+	 * @access protected
40
+	 * @param string $messenger     the messenger we are generating templates for
41
+	 * @param array  $message_types array of message types that the templates are generated for.
42
+	 * @param int    $GRP_ID        If a non global template is being generated then it is expected we'll have a GRP_ID
43
+	 *                              to use as the base for the new generated template.
44
+	 * @param bool   $global        true indicates generating templates on messenger activation. false requires GRP_ID
45
+	 *                              for event specific template generation.
46
+	 * @return array  @see EEH_MSG_Template::_create_new_templates for the return value of each element in the array
47
+	 *                for templates that are generated.  If this is an empty array then it means no templates were
48
+	 *                generated which usually means there was an error.  Anything in the array with an empty value for
49
+	 *                `MTP_context` means that it was not a new generated template but just reactivated (which only
50
+	 *                happens for global templates that already exist in the database.
51
+	 * @throws EE_Error
52
+	 * @throws ReflectionException
53
+	 */
54
+	public static function generate_new_templates($messenger, $message_types, $GRP_ID = 0, $global = false)
55
+	{
56
+		// make sure message_type is an array.
57
+		$message_types = (array) $message_types;
58
+		$templates = array();
59
+
60
+		if (empty($messenger)) {
61
+			throw new EE_Error(esc_html__('We need a messenger to generate templates!', 'event_espresso'));
62
+		}
63
+
64
+		// if we STILL have empty $message_types then we need to generate an error message b/c we NEED message types to do the template files.
65
+		if (empty($message_types)) {
66
+			throw new EE_Error(esc_html__('We need at least one message type to generate templates!', 'event_espresso'));
67
+		}
68
+
69
+		EEH_MSG_Template::_set_autoloader();
70
+		foreach ($message_types as $message_type) {
71
+
72
+			// if this is global template generation.
73
+			if ($global) {
74
+				// let's attempt to get the GRP_ID for this combo IF GRP_ID is empty.
75
+				if (empty($GRP_ID)) {
76
+					$GRP_ID = EEM_Message_Template_Group::instance()->get_one(
77
+						array(
78
+							array(
79
+								'MTP_messenger'    => $messenger,
80
+								'MTP_message_type' => $message_type,
81
+								'MTP_is_global'    => true,
82
+							),
83
+						)
84
+					);
85
+					$GRP_ID = $GRP_ID instanceof EE_Message_Template_Group ? $GRP_ID->ID() : 0;
86
+				}
87
+				// First let's determine if we already HAVE global templates for this messenger and message_type combination.
88
+				//  If we do then NO generation!!
89
+				if (EEH_MSG_Template::already_generated($messenger, $message_type, $GRP_ID)) {
90
+					$templates[] = array(
91
+						'GRP_ID' => $GRP_ID,
92
+						'MTP_context' => '',
93
+					);
94
+					// we already have generated templates for this so let's go to the next message type.
95
+					continue;
96
+				}
97
+			}
98
+			$new_message_template_group = EEH_MSG_Template::create_new_templates(
99
+				$messenger,
100
+				$message_type,
101
+				$GRP_ID,
102
+				$global
103
+			);
104
+
105
+			if (! $new_message_template_group) {
106
+				continue;
107
+			}
108
+			$templates[] = $new_message_template_group;
109
+		}
110
+
111
+		return $templates;
112
+	}
113
+
114
+
115
+	/**
116
+	 * The purpose of this method is to determine if there are already generated templates in the database for the
117
+	 * given variables.
118
+	 *
119
+	 * @param string $messenger    messenger
120
+	 * @param string $message_type message type
121
+	 * @param int    $GRP_ID       GRP ID ( if a custom template) (if not provided then we're just doing global
122
+	 *                             template check)
123
+	 * @return bool                true = generated, false = hasn't been generated.
124
+	 * @throws EE_Error
125
+	 */
126
+	public static function already_generated($messenger, $message_type, $GRP_ID = 0)
127
+	{
128
+		EEH_MSG_Template::_set_autoloader();
129
+		// what method we use depends on whether we have an GRP_ID or not
130
+		$count = empty($GRP_ID)
131
+			? EEM_Message_Template::instance()->count(
132
+				array(
133
+					array(
134
+						'Message_Template_Group.MTP_messenger'    => $messenger,
135
+						'Message_Template_Group.MTP_message_type' => $message_type,
136
+						'Message_Template_Group.MTP_is_global'    => true
137
+					)
138
+				)
139
+			)
140
+			: EEM_Message_Template::instance()->count(array( array( 'GRP_ID' => $GRP_ID ) ));
141
+
142
+		return $count > 0;
143
+	}
144
+
145
+
146
+	/**
147
+	 * Updates all message templates matching the incoming messengers and message types to active status.
148
+	 *
149
+	 * @static
150
+	 * @param array $messenger_names    Messenger slug
151
+	 * @param array $message_type_names Message type slug
152
+	 * @return  int                         count of updated records.
153
+	 * @throws EE_Error
154
+	 */
155
+	public static function update_to_active($messenger_names, $message_type_names)
156
+	{
157
+		$messenger_names = is_array($messenger_names) ? $messenger_names : array( $messenger_names );
158
+		$message_type_names = is_array($message_type_names) ? $message_type_names : array( $message_type_names );
159
+		return EEM_Message_Template_Group::instance()->update(
160
+			array( 'MTP_is_active' => 1 ),
161
+			array(
162
+				array(
163
+					'MTP_messenger'     => array( 'IN', $messenger_names ),
164
+					'MTP_message_type'  => array( 'IN', $message_type_names )
165
+				)
166
+			)
167
+		);
168
+	}
169
+
170
+
171
+	/**
172
+	 * Updates all message template groups matching the incoming arguments to inactive status.
173
+	 *
174
+	 * @static
175
+	 * @param array $messenger_names    The messenger slugs.
176
+	 *                                  If empty then all templates matching the message types are marked inactive.
177
+	 *                                  Otherwise only templates matching the messengers and message types.
178
+	 * @param array $message_type_names The message type slugs.
179
+	 *                                  If empty then all templates matching the messengers are marked inactive.
180
+	 *                                  Otherwise only templates matching the messengers and message types.
181
+	 *
182
+	 * @return int  count of updated records.
183
+	 * @throws EE_Error
184
+	 */
185
+	public static function update_to_inactive($messenger_names = array(), $message_type_names = array())
186
+	{
187
+		return EEM_Message_Template_Group::instance()->deactivate_message_template_groups_for(
188
+			$messenger_names,
189
+			$message_type_names
190
+		);
191
+	}
192
+
193
+
194
+	/**
195
+	 * The purpose of this function is to return all installed message objects
196
+	 * (messengers and message type regardless of whether they are ACTIVE or not)
197
+	 *
198
+	 * @param string $type
199
+	 * @return array array consisting of installed messenger objects and installed message type objects.
200
+	 * @throws EE_Error
201
+	 * @throws ReflectionException
202
+	 * @deprecated 4.9.0
203
+	 * @static
204
+	 */
205
+	public static function get_installed_message_objects($type = 'all')
206
+	{
207
+		self::_set_autoloader();
208
+		$message_resource_manager = EE_Registry::instance()->load_lib('Message_Resource_Manager');
209
+		return array(
210
+			'messenger' => $message_resource_manager->installed_messengers(),
211
+			'message_type' => $message_resource_manager->installed_message_types()
212
+		);
213
+	}
214
+
215
+
216
+	/**
217
+	 * This will return an array of shortcodes => labels from the
218
+	 * messenger and message_type objects associated with this
219
+	 * template.
220
+	 *
221
+	 * @param string $message_type
222
+	 * @param string $messenger
223
+	 * @param array  $fields                        What fields we're returning valid shortcodes for.
224
+	 *                                              If empty then we assume all fields are to be returned. Optional.
225
+	 * @param string $context                       What context we're going to return shortcodes for. Optional.
226
+	 * @param bool   $merged                        If TRUE then we don't return shortcodes indexed by field,
227
+	 *                                              but instead an array of the unique shortcodes for all the given (
228
+	 *                                              or all) fields. Optional.
229
+	 * @return array                                an array of shortcodes in the format
230
+	 *                                              array( '[shortcode] => 'label')
231
+	 *                                              OR
232
+	 *                                              FALSE if no shortcodes found.
233
+	 * @throws ReflectionException
234
+	 * @throws EE_Error*@since 4.3.0
235
+	 *
236
+	 */
237
+	public static function get_shortcodes(
238
+		$message_type,
239
+		$messenger,
240
+		$fields = array(),
241
+		$context = 'admin',
242
+		$merged = false
243
+	) {
244
+		$messenger_name = str_replace(' ', '_', ucwords(str_replace('_', ' ', $messenger)));
245
+		$mt_name = str_replace(' ', '_', ucwords(str_replace('_', ' ', $message_type)));
246
+		/** @var EE_Message_Resource_Manager $message_resource_manager */
247
+		$message_resource_manager = EE_Registry::instance()->load_lib('Message_Resource_Manager');
248
+		// convert slug to object
249
+		$messenger = $message_resource_manager->get_messenger($messenger);
250
+
251
+		// if messenger isn't a EE_messenger resource then bail.
252
+		if (! $messenger instanceof EE_messenger) {
253
+			return array();
254
+		}
255
+
256
+		// validate class for getting our list of shortcodes
257
+		$classname = 'EE_Messages_' . $messenger_name . '_' . $mt_name . '_Validator';
258
+		if (! class_exists($classname)) {
259
+			$msg[] = esc_html__('The Validator class was unable to load', 'event_espresso');
260
+			$msg[] = sprintf(
261
+				esc_html__('The class name compiled was %s. Please check and make sure the spelling and case is correct for the class name and that there is an autoloader in place for this class', 'event_espresso'),
262
+				$classname
263
+			);
264
+			throw new EE_Error(implode('||', $msg));
265
+		}
266
+
267
+		/** @type EE_Messages_Validator $_VLD */
268
+		$_VLD = new $classname(array(), $context);
269
+		$valid_shortcodes = $_VLD->get_validators();
270
+
271
+		// let's make sure we're only getting the shortcode part of the validators
272
+		$shortcodes = array();
273
+		foreach ($valid_shortcodes as $field => $validators) {
274
+			$shortcodes[ $field ] = $validators['shortcodes'];
275
+		}
276
+		$valid_shortcodes = $shortcodes;
277
+
278
+		// if not all fields let's make sure we ONLY include the shortcodes for the specified fields.
279
+		if (! empty($fields)) {
280
+			$specified_shortcodes = array();
281
+			foreach ($fields as $field) {
282
+				if (isset($valid_shortcodes[ $field ])) {
283
+					$specified_shortcodes[ $field ] = $valid_shortcodes[ $field ];
284
+				}
285
+			}
286
+			$valid_shortcodes = $specified_shortcodes;
287
+		}
288
+
289
+		// if not merged then let's replace the fields with the localized fields
290
+		if (! $merged) {
291
+			// let's get all the fields for the set messenger so that we can get the localized label and use that in the returned array.
292
+			$field_settings = $messenger->get_template_fields();
293
+			$localized = array();
294
+			foreach ($valid_shortcodes as $field => $shortcodes) {
295
+				// get localized field label
296
+				if (isset($field_settings[ $field ])) {
297
+					// possible that this is used as a main field.
298
+					if (empty($field_settings[ $field ])) {
299
+						if (isset($field_settings['extra'][ $field ])) {
300
+							$_field = $field_settings['extra'][ $field ]['main']['label'];
301
+						} else {
302
+							$_field = $field;
303
+						}
304
+					} else {
305
+						$_field = $field_settings[ $field ]['label'];
306
+					}
307
+				} elseif (isset($field_settings['extra'])) {
308
+					// loop through extra "main fields" and see if any of their children have our field
309
+					foreach ($field_settings['extra'] as $fields) {
310
+						if (isset($fields[ $field ])) {
311
+							$_field = $fields[ $field ]['label'];
312
+						} else {
313
+							$_field = $field;
314
+						}
315
+					}
316
+				} else {
317
+					$_field = $field;
318
+				}
319
+				if (isset($_field)) {
320
+					$localized[ (string) $_field ] = $shortcodes;
321
+				}
322
+			}
323
+			$valid_shortcodes = $localized;
324
+		}
325
+
326
+		// if $merged then let's merge all the shortcodes into one list NOT indexed by field.
327
+		if ($merged) {
328
+			$merged_codes = array();
329
+			foreach ($valid_shortcodes as $shortcode) {
330
+				foreach ($shortcode as $code => $label) {
331
+					if (isset($merged_codes[ $code ])) {
332
+						continue;
333
+					} else {
334
+						$merged_codes[ $code ] = $label;
335
+					}
336
+				}
337
+			}
338
+			$valid_shortcodes = $merged_codes;
339
+		}
340
+
341
+		return $valid_shortcodes;
342
+	}
343
+
344
+
345
+	/**
346
+	 * Get Messenger object.
347
+	 *
348
+	 * @param string $messenger messenger slug for the messenger object we want to retrieve.
349
+	 * @return EE_messenger
350
+	 * @throws ReflectionException
351
+	 * @throws EE_Error*@since 4.3.0
352
+	 * @deprecated 4.9.0
353
+	 */
354
+	public static function messenger_obj($messenger)
355
+	{
356
+		/** @type EE_Message_Resource_Manager $Message_Resource_Manager */
357
+		$Message_Resource_Manager = EE_Registry::instance()->load_lib('Message_Resource_Manager');
358
+		return $Message_Resource_Manager->get_messenger($messenger);
359
+	}
360
+
361
+
362
+	/**
363
+	 * get Message type object
364
+	 *
365
+	 * @param string $message_type the slug for the message type object to retrieve
366
+	 * @return EE_message_type
367
+	 * @throws ReflectionException
368
+	 * @throws EE_Error*@since 4.3.0
369
+	 * @deprecated 4.9.0
370
+	 */
371
+	public static function message_type_obj($message_type)
372
+	{
373
+		/** @type EE_Message_Resource_Manager $Message_Resource_Manager */
374
+		$Message_Resource_Manager = EE_Registry::instance()->load_lib('Message_Resource_Manager');
375
+		return $Message_Resource_Manager->get_message_type($message_type);
376
+	}
377
+
378
+
379
+	/**
380
+	 * Given a message_type slug, will return whether that message type is active in the system or not.
381
+	 *
382
+	 * @since    4.3.0
383
+	 * @param string $message_type message type to check for.
384
+	 * @return boolean
385
+	 * @throws EE_Error
386
+	 * @throws ReflectionException
387
+	 */
388
+	public static function is_mt_active($message_type)
389
+	{
390
+		/** @type EE_Message_Resource_Manager $Message_Resource_Manager */
391
+		$Message_Resource_Manager = EE_Registry::instance()->load_lib('Message_Resource_Manager');
392
+		$active_mts = $Message_Resource_Manager->list_of_active_message_types();
393
+		return in_array($message_type, $active_mts);
394
+	}
395
+
396
+
397
+	/**
398
+	 * Given a messenger slug, will return whether that messenger is active in the system or not.
399
+	 *
400
+	 * @since    4.3.0
401
+	 *
402
+	 * @param string $messenger slug for messenger to check.
403
+	 * @return boolean
404
+	 * @throws EE_Error
405
+	 * @throws ReflectionException
406
+	 */
407
+	public static function is_messenger_active($messenger)
408
+	{
409
+		/** @type EE_Message_Resource_Manager $Message_Resource_Manager */
410
+		$Message_Resource_Manager = EE_Registry::instance()->load_lib('Message_Resource_Manager');
411
+		$active_messenger = $Message_Resource_Manager->get_active_messenger($messenger);
412
+		return $active_messenger instanceof EE_messenger;
413
+	}
414
+
415
+
416
+	/**
417
+	 * Used to return active messengers array stored in the wp options table.
418
+	 * If no value is present in the option then an empty array is returned.
419
+	 *
420
+	 * @deprecated 4.9
421
+	 * @since      4.3.1
422
+	 *
423
+	 * @return array
424
+	 * @throws EE_Error
425
+	 * @throws ReflectionException
426
+	 */
427
+	public static function get_active_messengers_in_db()
428
+	{
429
+		EE_Error::doing_it_wrong(
430
+			__METHOD__,
431
+			esc_html__('Please use EE_Message_Resource_Manager::get_active_messengers_option() instead.', 'event_espresso'),
432
+			'4.9.0'
433
+		);
434
+		/** @var EE_Message_Resource_Manager $Message_Resource_Manager */
435
+		$Message_Resource_Manager = EE_Registry::instance()->load_lib('Message_Resource_Manager');
436
+		return $Message_Resource_Manager->get_active_messengers_option();
437
+	}
438
+
439
+
440
+	/**
441
+	 * Used to update the active messengers array stored in the wp options table.
442
+	 *
443
+	 * @since      4.3.1
444
+	 * @deprecated 4.9.0
445
+	 *
446
+	 * @param array $data_to_save Incoming data to save.
447
+	 *
448
+	 * @return bool FALSE if not updated, TRUE if updated.
449
+	 * @throws EE_Error
450
+	 * @throws ReflectionException
451
+	 */
452
+	public static function update_active_messengers_in_db($data_to_save)
453
+	{
454
+		EE_Error::doing_it_wrong(
455
+			__METHOD__,
456
+			esc_html__('Please use EE_Message_Resource_Manager::update_active_messengers_option() instead.', 'event_espresso'),
457
+			'4.9.0'
458
+		);
459
+		/** @var EE_Message_Resource_Manager $Message_Resource_Manager */
460
+		$Message_Resource_Manager = EE_Registry::instance()->load_lib('Message_Resource_Manager');
461
+		return $Message_Resource_Manager->update_active_messengers_option($data_to_save);
462
+	}
463
+
464
+
465
+	/**
466
+	 * This does some validation of incoming params, determines what type of url is being prepped and returns the
467
+	 * appropriate url trigger
468
+	 *
469
+	 * @param EE_message_type $message_type
470
+	 * @param EE_Message $message
471
+	 * @param EE_Registration | null $registration  The registration object must be included if this
472
+	 *                                              is going to be a registration trigger url.
473
+	 * @param string $sending_messenger             The (optional) sending messenger for the url.
474
+	 *
475
+	 * @return string
476
+	 * @throws EE_Error
477
+	 */
478
+	public static function get_url_trigger(
479
+		EE_message_type $message_type,
480
+		EE_Message $message,
481
+		$registration = null,
482
+		$sending_messenger = ''
483
+	) {
484
+		// first determine if the url can be to the EE_Message object.
485
+		if (! $message_type->always_generate()) {
486
+			return EEH_MSG_Template::generate_browser_trigger($message);
487
+		}
488
+
489
+		// if $registration object is not valid then exit early because there's nothing that can be generated.
490
+		if (! $registration instanceof EE_Registration) {
491
+			throw new EE_Error(
492
+				esc_html__('Incoming value for registration is not a valid EE_Registration object.', 'event_espresso')
493
+			);
494
+		}
495
+
496
+		// validate given context
497
+		$contexts = $message_type->get_contexts();
498
+		if ($message->context() !== '' && ! isset($contexts[ $message->context() ])) {
499
+			throw new EE_Error(
500
+				sprintf(
501
+					esc_html__('The context %s is not a valid context for %s.', 'event_espresso'),
502
+					$message->context(),
503
+					get_class($message_type)
504
+				)
505
+			);
506
+		}
507
+
508
+		// valid sending messenger but only if sending messenger set.  Otherwise generating messenger is used.
509
+		if (! empty($sending_messenger)) {
510
+			$with_messengers = $message_type->with_messengers();
511
+			if (
512
+				! isset($with_messengers[ $message->messenger() ])
513
+				 || ! in_array($sending_messenger, $with_messengers[ $message->messenger() ])
514
+			) {
515
+				throw new EE_Error(
516
+					sprintf(
517
+						esc_html__(
518
+							'The given sending messenger string (%1$s) does not match a valid sending messenger with the %2$s.  If this is incorrect, make sure that the message type has defined this messenger as a sending messenger in its $_with_messengers array.',
519
+							'event_espresso'
520
+						),
521
+						$sending_messenger,
522
+						get_class($message_type)
523
+					)
524
+				);
525
+			}
526
+		} else {
527
+			$sending_messenger = $message->messenger();
528
+		}
529
+		return EEH_MSG_Template::generate_url_trigger(
530
+			$sending_messenger,
531
+			$message->messenger(),
532
+			$message->context(),
533
+			$message->message_type(),
534
+			$registration,
535
+			$message->GRP_ID()
536
+		);
537
+	}
538
+
539
+
540
+	/**
541
+	 * This returns the url for triggering a in browser view of a specific EE_Message object.
542
+	 * @param EE_Message $message
543
+	 * @return string.
544
+	 */
545
+	public static function generate_browser_trigger(EE_Message $message)
546
+	{
547
+		$query_args = array(
548
+			'ee' => 'msg_browser_trigger',
549
+			'token' => $message->MSG_token()
550
+		);
551
+		return apply_filters(
552
+			'FHEE__EEH_MSG_Template__generate_browser_trigger',
553
+			add_query_arg($query_args, site_url()),
554
+			$message
555
+		);
556
+	}
557
+
558
+
559
+
560
+
561
+
562
+
563
+	/**
564
+	 * This returns the url for triggering an in browser view of the error saved on the incoming message object.
565
+	 * @param EE_Message $message
566
+	 * @return string
567
+	 */
568
+	public static function generate_error_display_trigger(EE_Message $message)
569
+	{
570
+		return apply_filters(
571
+			'FHEE__EEH_MSG_Template__generate_error_display_trigger',
572
+			add_query_arg(
573
+				array(
574
+					'ee' => 'msg_browser_error_trigger',
575
+					'token' => $message->MSG_token()
576
+				),
577
+				site_url()
578
+			),
579
+			$message
580
+		);
581
+	}
582
+
583
+
584
+	/**
585
+	 * This generates a url trigger for the msg_url_trigger route using the given arguments
586
+	 *
587
+	 * @param string          $sending_messenger      The sending messenger slug.
588
+	 * @param string          $generating_messenger   The generating messenger slug.
589
+	 * @param string          $context                The context for the template.
590
+	 * @param string          $message_type           The message type slug
591
+	 * @param EE_Registration $registration
592
+	 * @param integer         $message_template_group id   The EE_Message_Template_Group ID for the template.
593
+	 * @param integer         $data_id                The id to the EE_Base_Class for getting the data used by the
594
+	 *                                                trigger.
595
+	 * @return string          The generated url.
596
+	 * @throws EE_Error
597
+	 */
598
+	public static function generate_url_trigger(
599
+		$sending_messenger,
600
+		$generating_messenger,
601
+		$context,
602
+		$message_type,
603
+		EE_Registration $registration,
604
+		$message_template_group,
605
+		$data_id = 0
606
+	) {
607
+		$query_args = array(
608
+			'ee' => 'msg_url_trigger',
609
+			'snd_msgr' => $sending_messenger,
610
+			'gen_msgr' => $generating_messenger,
611
+			'message_type' => $message_type,
612
+			'context' => $context,
613
+			'token' => $registration->reg_url_link(),
614
+			'GRP_ID' => $message_template_group,
615
+			'id' => $data_id
616
+			);
617
+		$url = add_query_arg($query_args, get_home_url());
618
+
619
+		// made it here so now we can just get the url and filter it.  Filtered globally and by message type.
620
+		return apply_filters(
621
+			'FHEE__EEH_MSG_Template__generate_url_trigger',
622
+			$url,
623
+			$sending_messenger,
624
+			$generating_messenger,
625
+			$context,
626
+			$message_type,
627
+			$registration,
628
+			$message_template_group,
629
+			$data_id
630
+		);
631
+	}
632
+
633
+
634
+
635
+
636
+	/**
637
+	 * Return the specific css for the action icon given.
638
+	 *
639
+	 * @param string $type  What action to return.
640
+	 * @return string[]
641
+	 * @since 4.9.0
642
+	 */
643
+	public static function get_message_action_icon($type)
644
+	{
645
+		$action_icons = self::get_message_action_icons();
646
+		return isset($action_icons[ $type ]) ? $action_icons[ $type ] : [];
647
+	}
648
+
649
+
650
+	/**
651
+	 * This is used for retrieving the css classes used for the icons representing message actions.
652
+	 *
653
+	 * @since 4.9.0
654
+	 *
655
+	 * @return array
656
+	 */
657
+	public static function get_message_action_icons()
658
+	{
659
+		return apply_filters(
660
+			'FHEE__EEH_MSG_Template__message_action_icons',
661
+			array(
662
+				'view' => array(
663
+					'label' => esc_html__('View Message', 'event_espresso'),
664
+					'css_class' => 'dashicons dashicons-visibility',
665
+				),
666
+				'error' => array(
667
+					'label' => esc_html__('View Error Message', 'event_espresso'),
668
+					'css_class' => 'dashicons dashicons-info',
669
+				),
670
+				'see_notifications_for' => array(
671
+					'label' => esc_html__('View Related Messages', 'event_espresso'),
672
+					'css_class' => 'dashicons dashicons-megaphone',
673
+				),
674
+				'generate_now' => array(
675
+					'label' => esc_html__('Generate the message now.', 'event_espresso'),
676
+					'css_class' => 'dashicons dashicons-admin-tools',
677
+				),
678
+				'send_now' => array(
679
+					'label' => esc_html__('Send Immediately', 'event_espresso'),
680
+					'css_class' => 'dashicons dashicons-controls-forward',
681
+				),
682
+				'queue_for_resending' => array(
683
+					'label' => esc_html__('Queue for Resending', 'event_espresso'),
684
+					'css_class' => 'dashicons dashicons-controls-repeat',
685
+				),
686
+				'view_transaction' => array(
687
+					'label' => esc_html__('View related Transaction', 'event_espresso'),
688
+					'css_class' => 'dashicons dashicons-cart',
689
+				)
690
+			)
691
+		);
692
+	}
693
+
694
+
695
+	/**
696
+	 * This returns the url for a given action related to EE_Message.
697
+	 *
698
+	 * @param string     $type         What type of action to return the url for.
699
+	 * @param EE_Message $message      Required for generating the correct url for some types.
700
+	 * @param array      $query_params Any additional query params to be included with the generated url.
701
+	 *
702
+	 * @return string
703
+	 * @throws EE_Error
704
+	 * @throws ReflectionException
705
+	 * @since 4.9.0
706
+	 *
707
+	 */
708
+	public static function get_message_action_url($type, EE_Message $message = null, $query_params = array())
709
+	{
710
+		$action_urls = self::get_message_action_urls($message, $query_params);
711
+		return isset($action_urls[ $type ])  ? $action_urls[ $type ] : '';
712
+	}
713
+
714
+
715
+	/**
716
+	 * This returns all the current urls for EE_Message actions.
717
+	 *
718
+	 * @since 4.9.0
719
+	 *
720
+	 * @param EE_Message $message      The EE_Message object required to generate correct urls for some types.
721
+	 * @param array      $query_params Any additional query_params to be included with the generated url.
722
+	 *
723
+	 * @return array
724
+	 * @throws EE_Error
725
+	 * @throws ReflectionException
726
+	 */
727
+	public static function get_message_action_urls(EE_Message $message = null, $query_params = array())
728
+	{
729
+		EE_Registry::instance()->load_helper('URL');
730
+		// if $message is not an instance of EE_Message then let's just do a dummy.
731
+		$message = empty($message) ? EE_Message_Factory::create() : $message;
732
+		$action_urls =  apply_filters(
733
+			'FHEE__EEH_MSG_Template__get_message_action_url',
734
+			array(
735
+				'view' => EEH_MSG_Template::generate_browser_trigger($message),
736
+				'error' => EEH_MSG_Template::generate_error_display_trigger($message),
737
+				'see_notifications_for' => EEH_URL::add_query_args_and_nonce(
738
+					array_merge(
739
+						array(
740
+							'page' => 'espresso_messages',
741
+							'action' => 'default',
742
+							'filterby' => 1,
743
+						),
744
+						$query_params
745
+					),
746
+					admin_url('admin.php')
747
+				),
748
+				'generate_now' => EEH_URL::add_query_args_and_nonce(
749
+					array(
750
+						'page' => 'espresso_messages',
751
+						'action' => 'generate_now',
752
+						'MSG_ID' => $message->ID()
753
+					),
754
+					admin_url('admin.php')
755
+				),
756
+				'send_now' => EEH_URL::add_query_args_and_nonce(
757
+					array(
758
+						'page' => 'espresso_messages',
759
+						'action' => 'send_now',
760
+						'MSG_ID' => $message->ID()
761
+					),
762
+					admin_url('admin.php')
763
+				),
764
+				'queue_for_resending' => EEH_URL::add_query_args_and_nonce(
765
+					array(
766
+						'page' => 'espresso_messages',
767
+						'action' => 'queue_for_resending',
768
+						'MSG_ID' => $message->ID()
769
+					),
770
+					admin_url('admin.php')
771
+				),
772
+			)
773
+		);
774
+		if (
775
+			$message->TXN_ID() > 0
776
+			&& EE_Registry::instance()->CAP->current_user_can(
777
+				'ee_read_transaction',
778
+				'espresso_transactions_default',
779
+				$message->TXN_ID()
780
+			)
781
+		) {
782
+			$action_urls['view_transaction'] = EEH_URL::add_query_args_and_nonce(
783
+				array(
784
+					'page' => 'espresso_transactions',
785
+					'action' => 'view_transaction',
786
+					'TXN_ID' => $message->TXN_ID()
787
+				),
788
+				admin_url('admin.php')
789
+			);
790
+		} else {
791
+			$action_urls['view_transaction'] = '';
792
+		}
793
+		return $action_urls;
794
+	}
795
+
796
+
797
+	/**
798
+	 * This returns a generated link html including the icon used for the action link for EE_Message actions.
799
+	 *
800
+	 * @param string          $type         What type of action the link is for (if invalid type is passed in then an
801
+	 *                                      empty string is returned)
802
+	 * @param EE_Message|null $message      The EE_Message object (required for some actions to generate correctly)
803
+	 * @param array           $query_params Any extra query params to include in the generated link.
804
+	 *
805
+	 * @return string
806
+	 * @throws EE_Error
807
+	 * @throws ReflectionException
808
+	 * @since 4.9.0
809
+	 *
810
+	 */
811
+	public static function get_message_action_link($type, EE_Message $message = null, $query_params = array())
812
+	{
813
+		$url = EEH_MSG_Template::get_message_action_url($type, $message, $query_params);
814
+		$icon_css = EEH_MSG_Template::get_message_action_icon($type);
815
+		$label = $icon_css['label'] ?? null;
816
+		$label = $label ? 'aria-label="' . $label . '"' : '';
817
+		$class = $label ? ' ee-aria-tooltip' : '';
818
+
819
+		if (empty($url) || empty($icon_css) || ! isset($icon_css['css_class'])) {
820
+			return '';
821
+		}
822
+
823
+		$icon_css_class = $icon_css['css_class'] . apply_filters(
824
+			'FHEE__EEH_MSG_Template__get_message_action_link__icon_css_class',
825
+			' js-ee-message-action-link ee-message-action-link-' . $type,
826
+			$type,
827
+			$message,
828
+			$query_params
829
+		);
830
+
831
+		return '
832 832
             <a href="' . $url . '" ' . $label . ' class="button button--icon-only' . $class . '">
833 833
                 <span class="' .  esc_attr($icon_css_class) . '"></span>
834 834
             </a>';
835
-    }
836
-
837
-
838
-
839
-
840
-
841
-    /**
842
-     * This returns an array with keys as reg statuses and values as the corresponding message type slug (filtered).
843
-     *
844
-     * @since 4.9.0
845
-     * @return array
846
-     */
847
-    public static function reg_status_to_message_type_array()
848
-    {
849
-        return (array) apply_filters(
850
-            'FHEE__EEH_MSG_Template__reg_status_to_message_type_array',
851
-            array(
852
-                RegStatus::APPROVED => 'registration',
853
-                RegStatus::PENDING_PAYMENT => 'pending_approval',
854
-                RegStatus::AWAITING_REVIEW => 'not_approved_registration',
855
-                RegStatus::CANCELLED => 'cancelled_registration',
856
-                RegStatus::DECLINED => 'declined_registration'
857
-            )
858
-        );
859
-    }
860
-
861
-
862
-
863
-
864
-    /**
865
-     * This returns the corresponding registration message type slug to the given reg status. If there isn't a
866
-     * match, then returns an empty string.
867
-     *
868
-     * @since 4.9.0
869
-     * @param $reg_status
870
-     * @return string
871
-     */
872
-    public static function convert_reg_status_to_message_type($reg_status)
873
-    {
874
-        $reg_status_array = self::reg_status_to_message_type_array();
875
-        return isset($reg_status_array[ $reg_status ]) ? $reg_status_array[ $reg_status ] : '';
876
-    }
877
-
878
-
879
-    /**
880
-     * This returns an array with keys as payment stati and values as the corresponding message type slug (filtered).
881
-     *
882
-     * @since 4.9.0
883
-     * @return array
884
-     */
885
-    public static function payment_status_to_message_type_array()
886
-    {
887
-        return (array) apply_filters(
888
-            'FHEE__EEH_MSG_Template__payment_status_to_message_type_array',
889
-            array(
890
-                EEM_Payment::status_id_approved => 'payment',
891
-                EEM_Payment::status_id_pending => 'payment_pending',
892
-                EEM_Payment::status_id_cancelled => 'payment_cancelled',
893
-                EEM_Payment::status_id_declined => 'payment_declined',
894
-                EEM_Payment::status_id_failed => 'payment_failed'
895
-            )
896
-        );
897
-    }
898
-
899
-
900
-
901
-
902
-    /**
903
-     * This returns the corresponding payment message type slug to the given payment status. If there isn't a match then
904
-     * an empty string is returned
905
-     *
906
-     * @since 4.9.0
907
-     * @param $payment_status
908
-     * @return string
909
-     */
910
-    public static function convert_payment_status_to_message_type($payment_status)
911
-    {
912
-        $payment_status_array = self::payment_status_to_message_type_array();
913
-        return isset($payment_status_array[ $payment_status ]) ? $payment_status_array[ $payment_status ] : '';
914
-    }
915
-
916
-
917
-    /**
918
-     * This is used to retrieve the template pack for the given name.
919
-     *
920
-     * @param string $template_pack_name  should match the set `dbref` property value on the EE_Messages_Template_Pack.
921
-     *
922
-     * @return EE_Messages_Template_Pack
923
-     */
924
-    public static function get_template_pack($template_pack_name)
925
-    {
926
-        if (! self::$_template_pack_collection instanceof EE_Object_Collection) {
927
-            self::$_template_pack_collection = new EE_Messages_Template_Pack_Collection();
928
-        }
929
-
930
-        // first see if in collection already
931
-        $template_pack = self::$_template_pack_collection->get_by_name($template_pack_name);
932
-
933
-        if ($template_pack instanceof EE_Messages_Template_Pack) {
934
-            return $template_pack;
935
-        }
936
-
937
-        // nope...let's get it.
938
-        // not set yet so let's attempt to get it.
939
-        $pack_class_name = 'EE_Messages_Template_Pack_' . str_replace(
940
-            ' ',
941
-            '_',
942
-            ucwords(
943
-                str_replace('_', ' ', $template_pack_name)
944
-            )
945
-        );
946
-        if (! class_exists($pack_class_name) && $template_pack_name !== 'default') {
947
-            return self::get_template_pack('default');
948
-        } else {
949
-            $template_pack = new $pack_class_name();
950
-            self::$_template_pack_collection->add($template_pack);
951
-            return $template_pack;
952
-        }
953
-    }
954
-
955
-
956
-
957
-
958
-    /**
959
-     * Globs template packs installed in core and returns the template pack collection with all installed template packs
960
-     * in it.
961
-     *
962
-     * @since 4.9.0
963
-     *
964
-     * @return EE_Messages_Template_Pack_Collection
965
-     */
966
-    public static function get_template_pack_collection()
967
-    {
968
-        $new_collection = false;
969
-        if (! self::$_template_pack_collection instanceof EE_Messages_Template_Pack_Collection) {
970
-            self::$_template_pack_collection = new EE_Messages_Template_Pack_Collection();
971
-            $new_collection = true;
972
-        }
973
-
974
-        // glob the defaults directory for messages
975
-        $templates = glob(EE_LIBRARIES . 'messages/defaults/*', GLOB_ONLYDIR);
976
-        foreach ($templates as $template_path) {
977
-            // grab folder name
978
-            $template = basename($template_path);
979
-
980
-            if (! $new_collection) {
981
-                // already have it?
982
-                if (self::$_template_pack_collection->get_by_name($template) instanceof EE_Messages_Template_Pack) {
983
-                    continue;
984
-                }
985
-            }
986
-
987
-            // setup classname.
988
-            $template_pack_class_name = 'EE_Messages_Template_Pack_' . str_replace(
989
-                ' ',
990
-                '_',
991
-                ucwords(
992
-                    str_replace(
993
-                        '_',
994
-                        ' ',
995
-                        $template
996
-                    )
997
-                )
998
-            );
999
-            if (! class_exists($template_pack_class_name)) {
1000
-                continue;
1001
-            }
1002
-            self::$_template_pack_collection->add(new $template_pack_class_name());
1003
-        }
1004
-
1005
-        /**
1006
-         * Filter for plugins to add in any additional template packs
1007
-         * Note the filter name here is for backward compat, this used to be found in EED_Messages.
1008
-         */
1009
-        $additional_template_packs = apply_filters('FHEE__EED_Messages__get_template_packs__template_packs', array());
1010
-        foreach ((array) $additional_template_packs as $template_pack) {
1011
-            if (
1012
-                self::$_template_pack_collection->get_by_name(
1013
-                    $template_pack->dbref
1014
-                ) instanceof EE_Messages_Template_Pack
1015
-            ) {
1016
-                continue;
1017
-            }
1018
-            self::$_template_pack_collection->add($template_pack);
1019
-        }
1020
-        return self::$_template_pack_collection;
1021
-    }
1022
-
1023
-
1024
-    /**
1025
-     * This is a wrapper for the protected _create_new_templates function
1026
-     *
1027
-     * @param string $messenger_name
1028
-     * @param string $message_type_name message type that the templates are being created for
1029
-     * @param int    $GRP_ID
1030
-     * @param bool   $global
1031
-     * @return array
1032
-     * @throws EE_Error
1033
-     * @throws ReflectionException
1034
-     */
1035
-    public static function create_new_templates($messenger_name, $message_type_name, $GRP_ID = 0, $global = false)
1036
-    {
1037
-        /** @type EE_Message_Resource_Manager $Message_Resource_Manager */
1038
-        $Message_Resource_Manager = EE_Registry::instance()->load_lib('Message_Resource_Manager');
1039
-        $messenger = $Message_Resource_Manager->valid_messenger($messenger_name);
1040
-        $message_type = $Message_Resource_Manager->valid_message_type($message_type_name);
1041
-        if (! EEH_MSG_Template::message_type_has_active_templates_for_messenger($messenger, $message_type, $global)) {
1042
-            return array();
1043
-        }
1044
-        // whew made it this far!  Okay, let's go ahead and create the templates then
1045
-        return EEH_MSG_Template::_create_new_templates($messenger, $message_type, $GRP_ID, $global);
1046
-    }
1047
-
1048
-
1049
-    /**
1050
-     * @param EE_messenger     $messenger
1051
-     * @param EE_message_type  $message_type
1052
-     * @param                  $GRP_ID
1053
-     * @param                  $global
1054
-     * @return array|mixed
1055
-     * @throws EE_Error
1056
-     * @throws ReflectionException
1057
-     */
1058
-    protected static function _create_new_templates(EE_messenger $messenger, EE_message_type $message_type, $GRP_ID, $global)
1059
-    {
1060
-        // if we're creating a custom template then we don't need to use the defaults class
1061
-        if (! $global) {
1062
-            return EEH_MSG_Template::_create_custom_template_group($messenger, $message_type, $GRP_ID);
1063
-        }
1064
-        /** @type EE_Messages_Template_Defaults $Message_Template_Defaults */
1065
-        $Message_Template_Defaults = EE_Registry::factory(
1066
-            'EE_Messages_Template_Defaults',
1067
-            array( $messenger, $message_type, $GRP_ID )
1068
-        );
1069
-        // generate templates
1070
-        $success = $Message_Template_Defaults->create_new_templates();
1071
-
1072
-        // if creating the template failed.  Then we should deactivate the related message_type for the messenger because
1073
-        // its not active if it doesn't have a template.  Note this is only happening for GLOBAL template creation
1074
-        // attempts.
1075
-        if (! $success) {
1076
-            /** @var EE_Message_Resource_Manager $message_resource_manager */
1077
-            $message_resource_manager = EE_Registry::instance()->load_lib('Message_Resource_Manager');
1078
-            $message_resource_manager->deactivate_message_type_for_messenger($message_type->name, $messenger->name);
1079
-        }
1080
-
1081
-        /**
1082
-         * $success is in an array in the following format
1083
-         * array(
1084
-         *    'GRP_ID' => $new_grp_id,
1085
-         *    'MTP_context' => $first_context_in_new_templates,
1086
-         * )
1087
-         */
1088
-        return $success;
1089
-    }
1090
-
1091
-
1092
-    /**
1093
-     * This creates a custom template using the incoming GRP_ID
1094
-     *
1095
-     * @param EE_messenger    $messenger
1096
-     * @param EE_message_type $message_type
1097
-     * @param int             $GRP_ID           GRP_ID for the template_group being used as the base
1098
-     * @return  array $success              This will be an array in the format:
1099
-     *                                          array(
1100
-     *                                          'GRP_ID' => $new_grp_id,
1101
-     *                                          'MTP_context' => $first_context_in_created_template
1102
-     *                                          )
1103
-     * @throws EE_Error
1104
-     * @throws ReflectionException
1105
-     * @access private
1106
-     */
1107
-    private static function _create_custom_template_group(EE_messenger $messenger, EE_message_type $message_type, $GRP_ID)
1108
-    {
1109
-        // defaults
1110
-        $success = array( 'GRP_ID' => null, 'MTP_context' => '' );
1111
-        // get the template group to use as a template from the db.  If $GRP_ID is empty then we'll assume the base will be the global template matching the messenger and message type.
1112
-        $Message_Template_Group = empty($GRP_ID)
1113
-            ? EEM_Message_Template_Group::instance()->get_one(
1114
-                array(
1115
-                    array(
1116
-                        'MTP_messenger'    => $messenger->name,
1117
-                        'MTP_message_type' => $message_type->name,
1118
-                        'MTP_is_global'    => true
1119
-                    )
1120
-                )
1121
-            )
1122
-            : EEM_Message_Template_Group::instance()->get_one_by_ID($GRP_ID);
1123
-        // if we don't have a mtg at this point then we need to bail.
1124
-        if (! $Message_Template_Group instanceof EE_Message_Template_Group) {
1125
-            EE_Error::add_error(
1126
-                sprintf(
1127
-                    esc_html__(
1128
-                        'Something went wrong with generating the custom template from this group id: %s.  This usually happens when there is no matching message template group in the db.',
1129
-                        'event_espresso'
1130
-                    ),
1131
-                    $GRP_ID
1132
-                ),
1133
-                __FILE__,
1134
-                __FUNCTION__,
1135
-                __LINE__
1136
-            );
1137
-            return $success;
1138
-        }
1139
-        // let's get all the related message_template objects for this group.
1140
-        $message_templates = $Message_Template_Group->message_templates();
1141
-        // now we have what we need to setup the new template
1142
-        $new_mtg = clone $Message_Template_Group;
1143
-        $new_mtg->set('GRP_ID', 0);
1144
-        $new_mtg->set('MTP_is_global', false);
1145
-
1146
-        /** @var RequestInterface $request */
1147
-        $request = LoaderFactory::getLoader()->getShared(RequestInterface::class);
1148
-        $template_name = $request->isAjax() && $request->requestParamIsSet('templateName')
1149
-            ? $request->getRequestParam('templateName')
1150
-            : sprintf(
1151
-                esc_html__('Custom %1$s', 'event_espresso'),
1152
-                ucwords($message_type->label['singular']) ?? esc_html__('Template', 'event_espresso')
1153
-            );
1154
-        $template_description = $request->isAjax() && $request->requestParamIsSet('templateDescription')
1155
-            ? $request->getRequestParam('templateDescription')
1156
-            : sprintf(
1157
-                esc_html__(
1158
-                    'This is a custom template that was created for the %s messenger and %s message type.',
1159
-                    'event_espresso'
1160
-                ),
1161
-                $new_mtg->messenger_obj()->label['singular'],
1162
-                $new_mtg->message_type_obj()->label['singular']
1163
-            );
1164
-        $new_mtg->set('MTP_name', $template_name);
1165
-        $new_mtg->set('MTP_description', $template_description);
1166
-        // remove ALL relations on this template group so they don't get saved!
1167
-        $new_mtg->_remove_relations('Message_Template');
1168
-        $new_mtg->save();
1169
-        $success['GRP_ID'] = $new_mtg->ID();
1170
-        $success['template_name'] = $template_name;
1171
-        // add new message templates and add relation to.
1172
-        foreach ($message_templates as $message_template) {
1173
-            if (! $message_template instanceof EE_Message_Template) {
1174
-                continue;
1175
-            }
1176
-            $new_message_template = clone $message_template;
1177
-            $new_message_template->set('MTP_ID', 0);
1178
-            $new_message_template->set('GRP_ID', $new_mtg->ID()); // relation
1179
-            $new_message_template->save();
1180
-            if (empty($success['MTP_context']) && $new_message_template->get('MTP_context') !== 'admin') {
1181
-                $success['MTP_context'] = $new_message_template->get('MTP_context');
1182
-            }
1183
-        }
1184
-        return $success;
1185
-    }
1186
-
1187
-
1188
-    /**
1189
-     * message_type_has_active_templates_for_messenger
1190
-     *
1191
-     * @param EE_messenger    $messenger
1192
-     * @param EE_message_type $message_type
1193
-     * @param bool            $global
1194
-     * @return bool
1195
-     * @throws EE_Error
1196
-     */
1197
-    public static function message_type_has_active_templates_for_messenger(
1198
-        EE_messenger $messenger,
1199
-        EE_message_type $message_type,
1200
-        $global = false
1201
-    ) {
1202
-        // is given message_type valid for given messenger (if this is not a global save)
1203
-        if ($global) {
1204
-            return true;
1205
-        }
1206
-        $active_templates = EEM_Message_Template_Group::instance()->count(
1207
-            array(
1208
-                array(
1209
-                    'MTP_is_active'    => true,
1210
-                    'MTP_messenger'    => $messenger->name,
1211
-                    'MTP_message_type' => $message_type->name
1212
-                )
1213
-            )
1214
-        );
1215
-        if ($active_templates > 0) {
1216
-            return true;
1217
-        }
1218
-        EE_Error::add_error(
1219
-            sprintf(
1220
-                esc_html__(
1221
-                    'The %1$s message type is not registered with the %2$s messenger. Please visit the Messenger activation page to assign this message type first if you want to use it.',
1222
-                    'event_espresso'
1223
-                ),
1224
-                $message_type->name,
1225
-                $messenger->name
1226
-            ),
1227
-            __FILE__,
1228
-            __FUNCTION__,
1229
-            __LINE__
1230
-        );
1231
-        return false;
1232
-    }
1233
-
1234
-
1235
-    /**
1236
-     * get_fields
1237
-     * This takes a given messenger and message type and returns all the template fields indexed by context (and with field type).
1238
-     *
1239
-     * @param string $messenger_name    name of EE_messenger
1240
-     * @param string $message_type_name name of EE_message_type
1241
-     * @return array
1242
-     * @throws EE_Error
1243
-     * @throws ReflectionException
1244
-     */
1245
-    public static function get_fields($messenger_name, $message_type_name)
1246
-    {
1247
-        $template_fields = array();
1248
-        /** @type EE_Message_Resource_Manager $Message_Resource_Manager */
1249
-        $Message_Resource_Manager = EE_Registry::instance()->load_lib('Message_Resource_Manager');
1250
-        $messenger = $Message_Resource_Manager->valid_messenger($messenger_name);
1251
-        $message_type = $Message_Resource_Manager->valid_message_type($message_type_name);
1252
-        if (! EEH_MSG_Template::message_type_has_active_templates_for_messenger($messenger, $message_type)) {
1253
-            return array();
1254
-        }
1255
-
1256
-        $excluded_fields_for_messenger = $message_type->excludedFieldsForMessenger($messenger_name);
1257
-
1258
-        // okay now let's assemble an array with the messenger template fields added to the message_type contexts.
1259
-        foreach ($message_type->get_contexts() as $context => $details) {
1260
-            foreach ($messenger->get_template_fields() as $field => $value) {
1261
-                if (in_array($field, $excluded_fields_for_messenger, true)) {
1262
-                    continue;
1263
-                }
1264
-                $template_fields[ $context ][ $field ] = $value;
1265
-            }
1266
-        }
1267
-        if (empty($template_fields)) {
1268
-            EE_Error::add_error(
1269
-                esc_html__('Something went wrong and we couldn\'t get any templates assembled', 'event_espresso'),
1270
-                __FILE__,
1271
-                __FUNCTION__,
1272
-                __LINE__
1273
-            );
1274
-            return array();
1275
-        }
1276
-        return $template_fields;
1277
-    }
835
+	}
836
+
837
+
838
+
839
+
840
+
841
+	/**
842
+	 * This returns an array with keys as reg statuses and values as the corresponding message type slug (filtered).
843
+	 *
844
+	 * @since 4.9.0
845
+	 * @return array
846
+	 */
847
+	public static function reg_status_to_message_type_array()
848
+	{
849
+		return (array) apply_filters(
850
+			'FHEE__EEH_MSG_Template__reg_status_to_message_type_array',
851
+			array(
852
+				RegStatus::APPROVED => 'registration',
853
+				RegStatus::PENDING_PAYMENT => 'pending_approval',
854
+				RegStatus::AWAITING_REVIEW => 'not_approved_registration',
855
+				RegStatus::CANCELLED => 'cancelled_registration',
856
+				RegStatus::DECLINED => 'declined_registration'
857
+			)
858
+		);
859
+	}
860
+
861
+
862
+
863
+
864
+	/**
865
+	 * This returns the corresponding registration message type slug to the given reg status. If there isn't a
866
+	 * match, then returns an empty string.
867
+	 *
868
+	 * @since 4.9.0
869
+	 * @param $reg_status
870
+	 * @return string
871
+	 */
872
+	public static function convert_reg_status_to_message_type($reg_status)
873
+	{
874
+		$reg_status_array = self::reg_status_to_message_type_array();
875
+		return isset($reg_status_array[ $reg_status ]) ? $reg_status_array[ $reg_status ] : '';
876
+	}
877
+
878
+
879
+	/**
880
+	 * This returns an array with keys as payment stati and values as the corresponding message type slug (filtered).
881
+	 *
882
+	 * @since 4.9.0
883
+	 * @return array
884
+	 */
885
+	public static function payment_status_to_message_type_array()
886
+	{
887
+		return (array) apply_filters(
888
+			'FHEE__EEH_MSG_Template__payment_status_to_message_type_array',
889
+			array(
890
+				EEM_Payment::status_id_approved => 'payment',
891
+				EEM_Payment::status_id_pending => 'payment_pending',
892
+				EEM_Payment::status_id_cancelled => 'payment_cancelled',
893
+				EEM_Payment::status_id_declined => 'payment_declined',
894
+				EEM_Payment::status_id_failed => 'payment_failed'
895
+			)
896
+		);
897
+	}
898
+
899
+
900
+
901
+
902
+	/**
903
+	 * This returns the corresponding payment message type slug to the given payment status. If there isn't a match then
904
+	 * an empty string is returned
905
+	 *
906
+	 * @since 4.9.0
907
+	 * @param $payment_status
908
+	 * @return string
909
+	 */
910
+	public static function convert_payment_status_to_message_type($payment_status)
911
+	{
912
+		$payment_status_array = self::payment_status_to_message_type_array();
913
+		return isset($payment_status_array[ $payment_status ]) ? $payment_status_array[ $payment_status ] : '';
914
+	}
915
+
916
+
917
+	/**
918
+	 * This is used to retrieve the template pack for the given name.
919
+	 *
920
+	 * @param string $template_pack_name  should match the set `dbref` property value on the EE_Messages_Template_Pack.
921
+	 *
922
+	 * @return EE_Messages_Template_Pack
923
+	 */
924
+	public static function get_template_pack($template_pack_name)
925
+	{
926
+		if (! self::$_template_pack_collection instanceof EE_Object_Collection) {
927
+			self::$_template_pack_collection = new EE_Messages_Template_Pack_Collection();
928
+		}
929
+
930
+		// first see if in collection already
931
+		$template_pack = self::$_template_pack_collection->get_by_name($template_pack_name);
932
+
933
+		if ($template_pack instanceof EE_Messages_Template_Pack) {
934
+			return $template_pack;
935
+		}
936
+
937
+		// nope...let's get it.
938
+		// not set yet so let's attempt to get it.
939
+		$pack_class_name = 'EE_Messages_Template_Pack_' . str_replace(
940
+			' ',
941
+			'_',
942
+			ucwords(
943
+				str_replace('_', ' ', $template_pack_name)
944
+			)
945
+		);
946
+		if (! class_exists($pack_class_name) && $template_pack_name !== 'default') {
947
+			return self::get_template_pack('default');
948
+		} else {
949
+			$template_pack = new $pack_class_name();
950
+			self::$_template_pack_collection->add($template_pack);
951
+			return $template_pack;
952
+		}
953
+	}
954
+
955
+
956
+
957
+
958
+	/**
959
+	 * Globs template packs installed in core and returns the template pack collection with all installed template packs
960
+	 * in it.
961
+	 *
962
+	 * @since 4.9.0
963
+	 *
964
+	 * @return EE_Messages_Template_Pack_Collection
965
+	 */
966
+	public static function get_template_pack_collection()
967
+	{
968
+		$new_collection = false;
969
+		if (! self::$_template_pack_collection instanceof EE_Messages_Template_Pack_Collection) {
970
+			self::$_template_pack_collection = new EE_Messages_Template_Pack_Collection();
971
+			$new_collection = true;
972
+		}
973
+
974
+		// glob the defaults directory for messages
975
+		$templates = glob(EE_LIBRARIES . 'messages/defaults/*', GLOB_ONLYDIR);
976
+		foreach ($templates as $template_path) {
977
+			// grab folder name
978
+			$template = basename($template_path);
979
+
980
+			if (! $new_collection) {
981
+				// already have it?
982
+				if (self::$_template_pack_collection->get_by_name($template) instanceof EE_Messages_Template_Pack) {
983
+					continue;
984
+				}
985
+			}
986
+
987
+			// setup classname.
988
+			$template_pack_class_name = 'EE_Messages_Template_Pack_' . str_replace(
989
+				' ',
990
+				'_',
991
+				ucwords(
992
+					str_replace(
993
+						'_',
994
+						' ',
995
+						$template
996
+					)
997
+				)
998
+			);
999
+			if (! class_exists($template_pack_class_name)) {
1000
+				continue;
1001
+			}
1002
+			self::$_template_pack_collection->add(new $template_pack_class_name());
1003
+		}
1004
+
1005
+		/**
1006
+		 * Filter for plugins to add in any additional template packs
1007
+		 * Note the filter name here is for backward compat, this used to be found in EED_Messages.
1008
+		 */
1009
+		$additional_template_packs = apply_filters('FHEE__EED_Messages__get_template_packs__template_packs', array());
1010
+		foreach ((array) $additional_template_packs as $template_pack) {
1011
+			if (
1012
+				self::$_template_pack_collection->get_by_name(
1013
+					$template_pack->dbref
1014
+				) instanceof EE_Messages_Template_Pack
1015
+			) {
1016
+				continue;
1017
+			}
1018
+			self::$_template_pack_collection->add($template_pack);
1019
+		}
1020
+		return self::$_template_pack_collection;
1021
+	}
1022
+
1023
+
1024
+	/**
1025
+	 * This is a wrapper for the protected _create_new_templates function
1026
+	 *
1027
+	 * @param string $messenger_name
1028
+	 * @param string $message_type_name message type that the templates are being created for
1029
+	 * @param int    $GRP_ID
1030
+	 * @param bool   $global
1031
+	 * @return array
1032
+	 * @throws EE_Error
1033
+	 * @throws ReflectionException
1034
+	 */
1035
+	public static function create_new_templates($messenger_name, $message_type_name, $GRP_ID = 0, $global = false)
1036
+	{
1037
+		/** @type EE_Message_Resource_Manager $Message_Resource_Manager */
1038
+		$Message_Resource_Manager = EE_Registry::instance()->load_lib('Message_Resource_Manager');
1039
+		$messenger = $Message_Resource_Manager->valid_messenger($messenger_name);
1040
+		$message_type = $Message_Resource_Manager->valid_message_type($message_type_name);
1041
+		if (! EEH_MSG_Template::message_type_has_active_templates_for_messenger($messenger, $message_type, $global)) {
1042
+			return array();
1043
+		}
1044
+		// whew made it this far!  Okay, let's go ahead and create the templates then
1045
+		return EEH_MSG_Template::_create_new_templates($messenger, $message_type, $GRP_ID, $global);
1046
+	}
1047
+
1048
+
1049
+	/**
1050
+	 * @param EE_messenger     $messenger
1051
+	 * @param EE_message_type  $message_type
1052
+	 * @param                  $GRP_ID
1053
+	 * @param                  $global
1054
+	 * @return array|mixed
1055
+	 * @throws EE_Error
1056
+	 * @throws ReflectionException
1057
+	 */
1058
+	protected static function _create_new_templates(EE_messenger $messenger, EE_message_type $message_type, $GRP_ID, $global)
1059
+	{
1060
+		// if we're creating a custom template then we don't need to use the defaults class
1061
+		if (! $global) {
1062
+			return EEH_MSG_Template::_create_custom_template_group($messenger, $message_type, $GRP_ID);
1063
+		}
1064
+		/** @type EE_Messages_Template_Defaults $Message_Template_Defaults */
1065
+		$Message_Template_Defaults = EE_Registry::factory(
1066
+			'EE_Messages_Template_Defaults',
1067
+			array( $messenger, $message_type, $GRP_ID )
1068
+		);
1069
+		// generate templates
1070
+		$success = $Message_Template_Defaults->create_new_templates();
1071
+
1072
+		// if creating the template failed.  Then we should deactivate the related message_type for the messenger because
1073
+		// its not active if it doesn't have a template.  Note this is only happening for GLOBAL template creation
1074
+		// attempts.
1075
+		if (! $success) {
1076
+			/** @var EE_Message_Resource_Manager $message_resource_manager */
1077
+			$message_resource_manager = EE_Registry::instance()->load_lib('Message_Resource_Manager');
1078
+			$message_resource_manager->deactivate_message_type_for_messenger($message_type->name, $messenger->name);
1079
+		}
1080
+
1081
+		/**
1082
+		 * $success is in an array in the following format
1083
+		 * array(
1084
+		 *    'GRP_ID' => $new_grp_id,
1085
+		 *    'MTP_context' => $first_context_in_new_templates,
1086
+		 * )
1087
+		 */
1088
+		return $success;
1089
+	}
1090
+
1091
+
1092
+	/**
1093
+	 * This creates a custom template using the incoming GRP_ID
1094
+	 *
1095
+	 * @param EE_messenger    $messenger
1096
+	 * @param EE_message_type $message_type
1097
+	 * @param int             $GRP_ID           GRP_ID for the template_group being used as the base
1098
+	 * @return  array $success              This will be an array in the format:
1099
+	 *                                          array(
1100
+	 *                                          'GRP_ID' => $new_grp_id,
1101
+	 *                                          'MTP_context' => $first_context_in_created_template
1102
+	 *                                          )
1103
+	 * @throws EE_Error
1104
+	 * @throws ReflectionException
1105
+	 * @access private
1106
+	 */
1107
+	private static function _create_custom_template_group(EE_messenger $messenger, EE_message_type $message_type, $GRP_ID)
1108
+	{
1109
+		// defaults
1110
+		$success = array( 'GRP_ID' => null, 'MTP_context' => '' );
1111
+		// get the template group to use as a template from the db.  If $GRP_ID is empty then we'll assume the base will be the global template matching the messenger and message type.
1112
+		$Message_Template_Group = empty($GRP_ID)
1113
+			? EEM_Message_Template_Group::instance()->get_one(
1114
+				array(
1115
+					array(
1116
+						'MTP_messenger'    => $messenger->name,
1117
+						'MTP_message_type' => $message_type->name,
1118
+						'MTP_is_global'    => true
1119
+					)
1120
+				)
1121
+			)
1122
+			: EEM_Message_Template_Group::instance()->get_one_by_ID($GRP_ID);
1123
+		// if we don't have a mtg at this point then we need to bail.
1124
+		if (! $Message_Template_Group instanceof EE_Message_Template_Group) {
1125
+			EE_Error::add_error(
1126
+				sprintf(
1127
+					esc_html__(
1128
+						'Something went wrong with generating the custom template from this group id: %s.  This usually happens when there is no matching message template group in the db.',
1129
+						'event_espresso'
1130
+					),
1131
+					$GRP_ID
1132
+				),
1133
+				__FILE__,
1134
+				__FUNCTION__,
1135
+				__LINE__
1136
+			);
1137
+			return $success;
1138
+		}
1139
+		// let's get all the related message_template objects for this group.
1140
+		$message_templates = $Message_Template_Group->message_templates();
1141
+		// now we have what we need to setup the new template
1142
+		$new_mtg = clone $Message_Template_Group;
1143
+		$new_mtg->set('GRP_ID', 0);
1144
+		$new_mtg->set('MTP_is_global', false);
1145
+
1146
+		/** @var RequestInterface $request */
1147
+		$request = LoaderFactory::getLoader()->getShared(RequestInterface::class);
1148
+		$template_name = $request->isAjax() && $request->requestParamIsSet('templateName')
1149
+			? $request->getRequestParam('templateName')
1150
+			: sprintf(
1151
+				esc_html__('Custom %1$s', 'event_espresso'),
1152
+				ucwords($message_type->label['singular']) ?? esc_html__('Template', 'event_espresso')
1153
+			);
1154
+		$template_description = $request->isAjax() && $request->requestParamIsSet('templateDescription')
1155
+			? $request->getRequestParam('templateDescription')
1156
+			: sprintf(
1157
+				esc_html__(
1158
+					'This is a custom template that was created for the %s messenger and %s message type.',
1159
+					'event_espresso'
1160
+				),
1161
+				$new_mtg->messenger_obj()->label['singular'],
1162
+				$new_mtg->message_type_obj()->label['singular']
1163
+			);
1164
+		$new_mtg->set('MTP_name', $template_name);
1165
+		$new_mtg->set('MTP_description', $template_description);
1166
+		// remove ALL relations on this template group so they don't get saved!
1167
+		$new_mtg->_remove_relations('Message_Template');
1168
+		$new_mtg->save();
1169
+		$success['GRP_ID'] = $new_mtg->ID();
1170
+		$success['template_name'] = $template_name;
1171
+		// add new message templates and add relation to.
1172
+		foreach ($message_templates as $message_template) {
1173
+			if (! $message_template instanceof EE_Message_Template) {
1174
+				continue;
1175
+			}
1176
+			$new_message_template = clone $message_template;
1177
+			$new_message_template->set('MTP_ID', 0);
1178
+			$new_message_template->set('GRP_ID', $new_mtg->ID()); // relation
1179
+			$new_message_template->save();
1180
+			if (empty($success['MTP_context']) && $new_message_template->get('MTP_context') !== 'admin') {
1181
+				$success['MTP_context'] = $new_message_template->get('MTP_context');
1182
+			}
1183
+		}
1184
+		return $success;
1185
+	}
1186
+
1187
+
1188
+	/**
1189
+	 * message_type_has_active_templates_for_messenger
1190
+	 *
1191
+	 * @param EE_messenger    $messenger
1192
+	 * @param EE_message_type $message_type
1193
+	 * @param bool            $global
1194
+	 * @return bool
1195
+	 * @throws EE_Error
1196
+	 */
1197
+	public static function message_type_has_active_templates_for_messenger(
1198
+		EE_messenger $messenger,
1199
+		EE_message_type $message_type,
1200
+		$global = false
1201
+	) {
1202
+		// is given message_type valid for given messenger (if this is not a global save)
1203
+		if ($global) {
1204
+			return true;
1205
+		}
1206
+		$active_templates = EEM_Message_Template_Group::instance()->count(
1207
+			array(
1208
+				array(
1209
+					'MTP_is_active'    => true,
1210
+					'MTP_messenger'    => $messenger->name,
1211
+					'MTP_message_type' => $message_type->name
1212
+				)
1213
+			)
1214
+		);
1215
+		if ($active_templates > 0) {
1216
+			return true;
1217
+		}
1218
+		EE_Error::add_error(
1219
+			sprintf(
1220
+				esc_html__(
1221
+					'The %1$s message type is not registered with the %2$s messenger. Please visit the Messenger activation page to assign this message type first if you want to use it.',
1222
+					'event_espresso'
1223
+				),
1224
+				$message_type->name,
1225
+				$messenger->name
1226
+			),
1227
+			__FILE__,
1228
+			__FUNCTION__,
1229
+			__LINE__
1230
+		);
1231
+		return false;
1232
+	}
1233
+
1234
+
1235
+	/**
1236
+	 * get_fields
1237
+	 * This takes a given messenger and message type and returns all the template fields indexed by context (and with field type).
1238
+	 *
1239
+	 * @param string $messenger_name    name of EE_messenger
1240
+	 * @param string $message_type_name name of EE_message_type
1241
+	 * @return array
1242
+	 * @throws EE_Error
1243
+	 * @throws ReflectionException
1244
+	 */
1245
+	public static function get_fields($messenger_name, $message_type_name)
1246
+	{
1247
+		$template_fields = array();
1248
+		/** @type EE_Message_Resource_Manager $Message_Resource_Manager */
1249
+		$Message_Resource_Manager = EE_Registry::instance()->load_lib('Message_Resource_Manager');
1250
+		$messenger = $Message_Resource_Manager->valid_messenger($messenger_name);
1251
+		$message_type = $Message_Resource_Manager->valid_message_type($message_type_name);
1252
+		if (! EEH_MSG_Template::message_type_has_active_templates_for_messenger($messenger, $message_type)) {
1253
+			return array();
1254
+		}
1255
+
1256
+		$excluded_fields_for_messenger = $message_type->excludedFieldsForMessenger($messenger_name);
1257
+
1258
+		// okay now let's assemble an array with the messenger template fields added to the message_type contexts.
1259
+		foreach ($message_type->get_contexts() as $context => $details) {
1260
+			foreach ($messenger->get_template_fields() as $field => $value) {
1261
+				if (in_array($field, $excluded_fields_for_messenger, true)) {
1262
+					continue;
1263
+				}
1264
+				$template_fields[ $context ][ $field ] = $value;
1265
+			}
1266
+		}
1267
+		if (empty($template_fields)) {
1268
+			EE_Error::add_error(
1269
+				esc_html__('Something went wrong and we couldn\'t get any templates assembled', 'event_espresso'),
1270
+				__FILE__,
1271
+				__FUNCTION__,
1272
+				__LINE__
1273
+			);
1274
+			return array();
1275
+		}
1276
+		return $template_fields;
1277
+	}
1278 1278
 }
Please login to merge, or discard this patch.
core/helpers/EEH_Event_View.helper.php 1 patch
Indentation   +640 added lines, -640 removed lines patch added patch discarded remove patch
@@ -11,375 +11,375 @@  discard block
 block discarded – undo
11 11
  */
12 12
 class EEH_Event_View extends EEH_Base
13 13
 {
14
-    private static ?EE_Event $_event = null;
15
-
16
-
17
-    /**
18
-     * get_event
19
-     * attempts to retrieve an EE_Event object any way it can
20
-     *
21
-     * @param int|WP_Post $EVT_ID
22
-     * @return EE_Event|null
23
-     * @throws EE_Error
24
-     * @throws ReflectionException
25
-     */
26
-    public static function get_event($EVT_ID = 0): ?EE_Event
27
-    {
28
-        // international newspaper?
29
-        global $post;
30
-        $EVT_ID = $EVT_ID instanceof WP_Post && $EVT_ID->post_type === EspressoPostType::EVENTS
31
-            ? $EVT_ID->ID
32
-            : absint($EVT_ID);
33
-        // do we already have the Event  you are looking for?
34
-        if (EEH_Event_View::$_event instanceof EE_Event && $EVT_ID && EEH_Event_View::$_event->ID() === $EVT_ID) {
35
-            return EEH_Event_View::$_event;
36
-        }
37
-        // reset property so that the new event is cached.
38
-        EEH_Event_View::$_event = null;
39
-        if (! $EVT_ID && $post instanceof EE_Event) {
40
-            EEH_Event_View::$_event = $post;
41
-            return EEH_Event_View::$_event;
42
-        }
43
-        // if the post type is for an event and it has a cached event and we don't have a different incoming $EVT_ID
44
-        // then let's just use that cached event on the $post object.
45
-        if (
46
-            $post instanceof WP_Post
47
-            && $post->post_type === EspressoPostType::EVENTS
48
-            && isset($post->EE_Event)
49
-            && (
50
-                $EVT_ID === 0
51
-                || $EVT_ID === $post->ID
52
-            )
53
-        ) {
54
-            EEH_Event_View::$_event = $post->EE_Event;
55
-            return EEH_Event_View::$_event;
56
-        }
57
-        // If the event we have isn't an event but we do have an EVT_ID, let's try getting the event using the ID.
58
-        if (! EEH_Event_View::$_event instanceof EE_Event && $EVT_ID) {
59
-            EEH_Event_View::$_event = EEM_Event::instance()->get_one_by_ID($EVT_ID);
60
-        }
61
-        // no? ok let's try getting the event using the ID.
62
-        if (! EEH_Event_View::$_event instanceof EE_Event && $post->ID) {
63
-            $maybe_an_event = EEM_Event::instance()->get_one_by_ID($post->ID);
64
-            EEH_Event_View::$_event = $maybe_an_event instanceof EE_Event ? $maybe_an_event : EEH_Event_View::$_event;
65
-        }
66
-        // ensure Event object is added to WP post object
67
-        if (
68
-            $post instanceof WP_Post
69
-            && $post->post_type === EspressoPostType::EVENTS
70
-            && EEH_Event_View::$_event instanceof EE_Event
71
-            && EEH_Event_View::$_event->ID() === $post->ID
72
-        ) {
73
-            $post->EE_Event = EEH_Event_View::$_event;
74
-        }
75
-        return EEH_Event_View::$_event;
76
-    }
77
-
78
-
79
-    /**
80
-     *    display_ticket_selector
81
-     *
82
-     * @param int $EVT_ID
83
-     * @return    boolean
84
-     * @throws EE_Error
85
-     * @throws EE_Error
86
-     * @throws ReflectionException
87
-     */
88
-    public static function display_ticket_selector($EVT_ID = 0)
89
-    {
90
-        $event = EEH_Event_View::get_event($EVT_ID);
91
-        return $event instanceof EE_Event && $event->display_ticket_selector();
92
-    }
93
-
94
-
95
-    /**
96
-     *    event_status
97
-     *
98
-     * @param int $EVT_ID
99
-     * @return    string
100
-     * @throws EE_Error
101
-     * @throws EE_Error
102
-     * @throws ReflectionException
103
-     */
104
-    public static function event_status($EVT_ID = 0)
105
-    {
106
-        $event = EEH_Event_View::get_event($EVT_ID);
107
-        return $event instanceof EE_Event ? $event->pretty_active_status(false) : '';
108
-    }
109
-
110
-
111
-    /**
112
-     *  event_active_status
113
-     *
114
-     * @param int $EVT_ID
115
-     * @return     string
116
-     * @throws EE_Error
117
-     * @throws EE_Error
118
-     * @throws ReflectionException
119
-     */
120
-    public static function event_active_status($EVT_ID = 0, $echo = true)
121
-    {
122
-        $event = EEH_Event_View::get_event($EVT_ID);
123
-        return $event instanceof EE_Event ? $event->pretty_active_status($echo) : 'inactive';
124
-    }
125
-
126
-
127
-    /**
128
-     *  event_has_content_or_excerpt
129
-     *
130
-     * @param int $EVT_ID
131
-     * @return     bool
132
-     * @throws EE_Error
133
-     * @throws EE_Error
134
-     * @throws ReflectionException
135
-     */
136
-    public static function event_has_content_or_excerpt($EVT_ID = 0)
137
-    {
138
-        $event                  = EEH_Event_View::get_event($EVT_ID);
139
-        $has_content_or_excerpt = false;
140
-        if ($event instanceof EE_Event) {
141
-            $has_content_or_excerpt = $event->description() != '' || $event->short_description(null, null, true) != '';
142
-        }
143
-        if (
144
-            is_archive()
145
-            && ! (espresso_display_full_description_in_event_list()
146
-                  || espresso_display_excerpt_in_event_list())
147
-        ) {
148
-            $has_content_or_excerpt = false;
149
-        }
150
-        return $has_content_or_excerpt;
151
-    }
152
-
153
-
154
-    /**
155
-     *    event_active_status
156
-     *
157
-     * @param null $num_words
158
-     * @param null $more
159
-     * @return    string
160
-     */
161
-    public static function event_content_or_excerpt($num_words = null, $more = null)
162
-    {
163
-        global $post;
164
-        ob_start();
165
-        if ((is_single()) || (is_archive() && espresso_display_full_description_in_event_list())) {
166
-            // admin has chosen "full description"
167
-            // for the "Event Espresso - Events > Templates > Display Description" option
168
-            the_content();
169
-        } elseif ((is_archive() && espresso_display_excerpt_in_event_list())) {
170
-            if (has_excerpt($post->ID)) {
171
-                // admin has chosen "excerpt (short desc)"
172
-                // for the "Event Espresso - Events > Templates > Display Description" option
173
-                // AND an excerpt actually exists
174
-                the_excerpt();
175
-            } else {
176
-                // admin has chosen "excerpt (short desc)"
177
-                // for the "Event Espresso - Events > Templates > Display Description" option
178
-                // but NO excerpt actually exists, so we need to create one
179
-                if (! empty($num_words)) {
180
-                    if (empty($more)) {
181
-                        $more_link_text = esc_html__('(more&hellip;)', 'event_espresso');
182
-                        $more           = ' <a href="' . get_permalink() . '"';
183
-                        $more           .= ' class="more-link"';
184
-                        $more           .= EED_Events_Archive::link_target();
185
-                        $more           .= '>' . $more_link_text . '</a>';
186
-                        $more           = apply_filters('the_content_more_link', $more, $more_link_text);
187
-                    }
188
-                    $content = str_replace('NOMORELINK', '', get_the_content('NOMORELINK'));
189
-
190
-                    $content = wp_trim_words($content, $num_words, ' ') . $more;
191
-                } else {
192
-                    $content = get_the_content();
193
-                }
194
-                global $allowedtags;
195
-                // make sure links are allowed
196
-                $allowedtags['a'] = isset($allowedtags['a'])
197
-                    ? $allowedtags['a']
198
-                    : [];
199
-                // as well as target attribute
200
-                $allowedtags['a']['target'] = isset($allowedtags['a']['target'])
201
-                    ? $allowedtags['a']['target']
202
-                    : false;
203
-                // but get previous value so we can reset it
204
-                $prev_value                 = $allowedtags['a']['target'];
205
-                $allowedtags['a']['target'] = true;
206
-                $content                    = wp_kses($content, $allowedtags);
207
-                $content                    = strip_shortcodes($content);
208
-                echo apply_filters('the_content', $content);
209
-                $allowedtags['a']['target'] = $prev_value;
210
-            }
211
-        } else {
212
-            // admin has chosen "none"
213
-            // for the "Event Espresso - Events > Templates > Display Description" option
214
-            echo apply_filters('the_content', '');
215
-        }
216
-        return ob_get_clean();
217
-    }
218
-
219
-
220
-    /**
221
-     *  event_tickets_available
222
-     *
223
-     * @param int $EVT_ID
224
-     * @return     EE_Ticket[]
225
-     * @throws EE_Error
226
-     * @throws ReflectionException
227
-     */
228
-    public static function event_tickets_available($EVT_ID = 0)
229
-    {
230
-        $event                          = EEH_Event_View::get_event($EVT_ID);
231
-        $tickets_available_for_purchase = [];
232
-        if ($event instanceof EE_Event) {
233
-            $datetimes = EEH_Event_View::get_all_date_obj($EVT_ID, false);
234
-            foreach ($datetimes as $datetime) {
235
-                $tickets_available_for_purchase =
236
-                    array_merge($tickets_available_for_purchase, $datetime->ticket_types_available_for_purchase());
237
-            }
238
-        }
239
-        return $tickets_available_for_purchase;
240
-    }
241
-
242
-
243
-    /**
244
-     *    the_event_date
245
-     *
246
-     * @param int  $EVT_ID
247
-     * @param bool $hide_uncategorized
248
-     * @return    string
249
-     * @throws EE_Error
250
-     * @throws ReflectionException
251
-     */
252
-    public static function event_categories($EVT_ID = 0, $hide_uncategorized = true)
253
-    {
254
-        $category_links = [];
255
-        $event          = EEH_Event_View::get_event($EVT_ID);
256
-        if ($event instanceof EE_Event) {
257
-            $event_categories = get_the_terms($event->ID(), 'espresso_event_categories');
258
-            if ($event_categories) {
259
-                // loop thru terms and create links
260
-                foreach ($event_categories as $term) {
261
-                    $url = get_term_link($term, 'espresso_venue_categories');
262
-                    if (
263
-                        ! is_wp_error($url)
264
-                        && (
265
-                            (
266
-                                $hide_uncategorized
267
-                                && strtolower($term->name) != esc_html__('uncategorized', 'event_espresso')
268
-                            )
269
-                            || ! $hide_uncategorized
270
-                        )
271
-                    ) {
272
-                        $category_links[] = '<a href="' . esc_url_raw($url) . '" '
273
-                                            . 'rel="tag" ' . EED_Events_Archive::link_target() . '>'
274
-                                            . esc_html($term->name)
275
-                                            . '</a>';
276
-                    }
277
-                }
278
-            }
279
-        }
280
-        return implode(', ', $category_links);
281
-    }
282
-
283
-
284
-    /**
285
-     *    the_event_date - first date by date order
286
-     *
287
-     * @param string $date_format
288
-     * @param string $time_format
289
-     * @param int    $EVT_ID
290
-     * @return    string
291
-     * @throws EE_Error
292
-     * @throws ReflectionException
293
-     */
294
-    public static function the_event_date($date_format = 'D M jS', $time_format = 'g:i a', $EVT_ID = 0)
295
-    {
296
-        $datetime = EEH_Event_View::get_primary_date_obj($EVT_ID);
297
-        $format   = ! empty($date_format) && ! empty($time_format)
298
-                ? $date_format . ' ' . $time_format
299
-                : $date_format . $time_format;
300
-        return $datetime instanceof EE_Datetime ? $datetime->get_i18n_datetime('DTT_EVT_start', $format) : '';
301
-    }
302
-
303
-
304
-    /**
305
-     *    the_event_end_date - last date by date order
306
-     *
307
-     * @param string $date_format
308
-     * @param string $time_format
309
-     * @param int    $EVT_ID
310
-     * @return    string
311
-     * @throws EE_Error
312
-     * @throws ReflectionException
313
-     */
314
-    public static function the_event_end_date($date_format = 'D M jS', $time_format = 'g:i a', $EVT_ID = 0)
315
-    {
316
-        $datetime = EEH_Event_View::get_last_date_obj($EVT_ID);
317
-        $format   =
318
-            ! empty($date_format) && ! empty($time_format)
319
-                ? $date_format . ' ' . $time_format
320
-                : $date_format
321
-                  . $time_format;
322
-        return $datetime instanceof EE_Datetime ? $datetime->get_i18n_datetime('DTT_EVT_end', $format) : '';
323
-    }
324
-
325
-
326
-    /**
327
-     *    the_earliest_event_date - first date chronologically
328
-     *
329
-     * @param string $date_format
330
-     * @param string $time_format
331
-     * @param int    $EVT_ID
332
-     * @return    string
333
-     * @throws EE_Error
334
-     * @throws ReflectionException
335
-     */
336
-    public static function the_earliest_event_date($date_format = 'D M jS', $time_format = 'g:i a', $EVT_ID = 0)
337
-    {
338
-        $datetime = EEH_Event_View::get_earliest_date_obj($EVT_ID);
339
-        $format   =
340
-            ! empty($date_format) && ! empty($time_format)
341
-                ? $date_format . ' ' . $time_format
342
-                : $date_format
343
-                  . $time_format;
344
-        return $datetime instanceof EE_Datetime ? $datetime->get_i18n_datetime('DTT_EVT_start', $format) : '';
345
-    }
346
-
347
-
348
-    /**
349
-     *    the_latest_event_date - latest date chronologically
350
-     *
351
-     * @param string $date_format
352
-     * @param string $time_format
353
-     * @param int    $EVT_ID
354
-     * @return    string
355
-     * @throws EE_Error
356
-     * @throws ReflectionException
357
-     */
358
-    public static function the_latest_event_date($date_format = 'D M jS', $time_format = 'g:i a', $EVT_ID = 0)
359
-    {
360
-        $datetime = EEH_Event_View::get_latest_date_obj($EVT_ID);
361
-        $format   =
362
-            ! empty($date_format) && ! empty($time_format)
363
-                ? $date_format . ' ' . $time_format
364
-                : $date_format
365
-                  . $time_format;
366
-        return $datetime instanceof EE_Datetime ? $datetime->get_i18n_datetime('DTT_EVT_end', $format) : '';
367
-    }
368
-
369
-
370
-    /**
371
-     *    event_date_as_calendar_page
372
-     *
373
-     * @param int $EVT_ID
374
-     * @return    void
375
-     * @throws EE_Error
376
-     * @throws ReflectionException
377
-     */
378
-    public static function event_date_as_calendar_page($EVT_ID = 0)
379
-    {
380
-        $datetime = EEH_Event_View::get_primary_date_obj($EVT_ID);
381
-        if ($datetime instanceof EE_Datetime) {
382
-            ?>
14
+	private static ?EE_Event $_event = null;
15
+
16
+
17
+	/**
18
+	 * get_event
19
+	 * attempts to retrieve an EE_Event object any way it can
20
+	 *
21
+	 * @param int|WP_Post $EVT_ID
22
+	 * @return EE_Event|null
23
+	 * @throws EE_Error
24
+	 * @throws ReflectionException
25
+	 */
26
+	public static function get_event($EVT_ID = 0): ?EE_Event
27
+	{
28
+		// international newspaper?
29
+		global $post;
30
+		$EVT_ID = $EVT_ID instanceof WP_Post && $EVT_ID->post_type === EspressoPostType::EVENTS
31
+			? $EVT_ID->ID
32
+			: absint($EVT_ID);
33
+		// do we already have the Event  you are looking for?
34
+		if (EEH_Event_View::$_event instanceof EE_Event && $EVT_ID && EEH_Event_View::$_event->ID() === $EVT_ID) {
35
+			return EEH_Event_View::$_event;
36
+		}
37
+		// reset property so that the new event is cached.
38
+		EEH_Event_View::$_event = null;
39
+		if (! $EVT_ID && $post instanceof EE_Event) {
40
+			EEH_Event_View::$_event = $post;
41
+			return EEH_Event_View::$_event;
42
+		}
43
+		// if the post type is for an event and it has a cached event and we don't have a different incoming $EVT_ID
44
+		// then let's just use that cached event on the $post object.
45
+		if (
46
+			$post instanceof WP_Post
47
+			&& $post->post_type === EspressoPostType::EVENTS
48
+			&& isset($post->EE_Event)
49
+			&& (
50
+				$EVT_ID === 0
51
+				|| $EVT_ID === $post->ID
52
+			)
53
+		) {
54
+			EEH_Event_View::$_event = $post->EE_Event;
55
+			return EEH_Event_View::$_event;
56
+		}
57
+		// If the event we have isn't an event but we do have an EVT_ID, let's try getting the event using the ID.
58
+		if (! EEH_Event_View::$_event instanceof EE_Event && $EVT_ID) {
59
+			EEH_Event_View::$_event = EEM_Event::instance()->get_one_by_ID($EVT_ID);
60
+		}
61
+		// no? ok let's try getting the event using the ID.
62
+		if (! EEH_Event_View::$_event instanceof EE_Event && $post->ID) {
63
+			$maybe_an_event = EEM_Event::instance()->get_one_by_ID($post->ID);
64
+			EEH_Event_View::$_event = $maybe_an_event instanceof EE_Event ? $maybe_an_event : EEH_Event_View::$_event;
65
+		}
66
+		// ensure Event object is added to WP post object
67
+		if (
68
+			$post instanceof WP_Post
69
+			&& $post->post_type === EspressoPostType::EVENTS
70
+			&& EEH_Event_View::$_event instanceof EE_Event
71
+			&& EEH_Event_View::$_event->ID() === $post->ID
72
+		) {
73
+			$post->EE_Event = EEH_Event_View::$_event;
74
+		}
75
+		return EEH_Event_View::$_event;
76
+	}
77
+
78
+
79
+	/**
80
+	 *    display_ticket_selector
81
+	 *
82
+	 * @param int $EVT_ID
83
+	 * @return    boolean
84
+	 * @throws EE_Error
85
+	 * @throws EE_Error
86
+	 * @throws ReflectionException
87
+	 */
88
+	public static function display_ticket_selector($EVT_ID = 0)
89
+	{
90
+		$event = EEH_Event_View::get_event($EVT_ID);
91
+		return $event instanceof EE_Event && $event->display_ticket_selector();
92
+	}
93
+
94
+
95
+	/**
96
+	 *    event_status
97
+	 *
98
+	 * @param int $EVT_ID
99
+	 * @return    string
100
+	 * @throws EE_Error
101
+	 * @throws EE_Error
102
+	 * @throws ReflectionException
103
+	 */
104
+	public static function event_status($EVT_ID = 0)
105
+	{
106
+		$event = EEH_Event_View::get_event($EVT_ID);
107
+		return $event instanceof EE_Event ? $event->pretty_active_status(false) : '';
108
+	}
109
+
110
+
111
+	/**
112
+	 *  event_active_status
113
+	 *
114
+	 * @param int $EVT_ID
115
+	 * @return     string
116
+	 * @throws EE_Error
117
+	 * @throws EE_Error
118
+	 * @throws ReflectionException
119
+	 */
120
+	public static function event_active_status($EVT_ID = 0, $echo = true)
121
+	{
122
+		$event = EEH_Event_View::get_event($EVT_ID);
123
+		return $event instanceof EE_Event ? $event->pretty_active_status($echo) : 'inactive';
124
+	}
125
+
126
+
127
+	/**
128
+	 *  event_has_content_or_excerpt
129
+	 *
130
+	 * @param int $EVT_ID
131
+	 * @return     bool
132
+	 * @throws EE_Error
133
+	 * @throws EE_Error
134
+	 * @throws ReflectionException
135
+	 */
136
+	public static function event_has_content_or_excerpt($EVT_ID = 0)
137
+	{
138
+		$event                  = EEH_Event_View::get_event($EVT_ID);
139
+		$has_content_or_excerpt = false;
140
+		if ($event instanceof EE_Event) {
141
+			$has_content_or_excerpt = $event->description() != '' || $event->short_description(null, null, true) != '';
142
+		}
143
+		if (
144
+			is_archive()
145
+			&& ! (espresso_display_full_description_in_event_list()
146
+				  || espresso_display_excerpt_in_event_list())
147
+		) {
148
+			$has_content_or_excerpt = false;
149
+		}
150
+		return $has_content_or_excerpt;
151
+	}
152
+
153
+
154
+	/**
155
+	 *    event_active_status
156
+	 *
157
+	 * @param null $num_words
158
+	 * @param null $more
159
+	 * @return    string
160
+	 */
161
+	public static function event_content_or_excerpt($num_words = null, $more = null)
162
+	{
163
+		global $post;
164
+		ob_start();
165
+		if ((is_single()) || (is_archive() && espresso_display_full_description_in_event_list())) {
166
+			// admin has chosen "full description"
167
+			// for the "Event Espresso - Events > Templates > Display Description" option
168
+			the_content();
169
+		} elseif ((is_archive() && espresso_display_excerpt_in_event_list())) {
170
+			if (has_excerpt($post->ID)) {
171
+				// admin has chosen "excerpt (short desc)"
172
+				// for the "Event Espresso - Events > Templates > Display Description" option
173
+				// AND an excerpt actually exists
174
+				the_excerpt();
175
+			} else {
176
+				// admin has chosen "excerpt (short desc)"
177
+				// for the "Event Espresso - Events > Templates > Display Description" option
178
+				// but NO excerpt actually exists, so we need to create one
179
+				if (! empty($num_words)) {
180
+					if (empty($more)) {
181
+						$more_link_text = esc_html__('(more&hellip;)', 'event_espresso');
182
+						$more           = ' <a href="' . get_permalink() . '"';
183
+						$more           .= ' class="more-link"';
184
+						$more           .= EED_Events_Archive::link_target();
185
+						$more           .= '>' . $more_link_text . '</a>';
186
+						$more           = apply_filters('the_content_more_link', $more, $more_link_text);
187
+					}
188
+					$content = str_replace('NOMORELINK', '', get_the_content('NOMORELINK'));
189
+
190
+					$content = wp_trim_words($content, $num_words, ' ') . $more;
191
+				} else {
192
+					$content = get_the_content();
193
+				}
194
+				global $allowedtags;
195
+				// make sure links are allowed
196
+				$allowedtags['a'] = isset($allowedtags['a'])
197
+					? $allowedtags['a']
198
+					: [];
199
+				// as well as target attribute
200
+				$allowedtags['a']['target'] = isset($allowedtags['a']['target'])
201
+					? $allowedtags['a']['target']
202
+					: false;
203
+				// but get previous value so we can reset it
204
+				$prev_value                 = $allowedtags['a']['target'];
205
+				$allowedtags['a']['target'] = true;
206
+				$content                    = wp_kses($content, $allowedtags);
207
+				$content                    = strip_shortcodes($content);
208
+				echo apply_filters('the_content', $content);
209
+				$allowedtags['a']['target'] = $prev_value;
210
+			}
211
+		} else {
212
+			// admin has chosen "none"
213
+			// for the "Event Espresso - Events > Templates > Display Description" option
214
+			echo apply_filters('the_content', '');
215
+		}
216
+		return ob_get_clean();
217
+	}
218
+
219
+
220
+	/**
221
+	 *  event_tickets_available
222
+	 *
223
+	 * @param int $EVT_ID
224
+	 * @return     EE_Ticket[]
225
+	 * @throws EE_Error
226
+	 * @throws ReflectionException
227
+	 */
228
+	public static function event_tickets_available($EVT_ID = 0)
229
+	{
230
+		$event                          = EEH_Event_View::get_event($EVT_ID);
231
+		$tickets_available_for_purchase = [];
232
+		if ($event instanceof EE_Event) {
233
+			$datetimes = EEH_Event_View::get_all_date_obj($EVT_ID, false);
234
+			foreach ($datetimes as $datetime) {
235
+				$tickets_available_for_purchase =
236
+					array_merge($tickets_available_for_purchase, $datetime->ticket_types_available_for_purchase());
237
+			}
238
+		}
239
+		return $tickets_available_for_purchase;
240
+	}
241
+
242
+
243
+	/**
244
+	 *    the_event_date
245
+	 *
246
+	 * @param int  $EVT_ID
247
+	 * @param bool $hide_uncategorized
248
+	 * @return    string
249
+	 * @throws EE_Error
250
+	 * @throws ReflectionException
251
+	 */
252
+	public static function event_categories($EVT_ID = 0, $hide_uncategorized = true)
253
+	{
254
+		$category_links = [];
255
+		$event          = EEH_Event_View::get_event($EVT_ID);
256
+		if ($event instanceof EE_Event) {
257
+			$event_categories = get_the_terms($event->ID(), 'espresso_event_categories');
258
+			if ($event_categories) {
259
+				// loop thru terms and create links
260
+				foreach ($event_categories as $term) {
261
+					$url = get_term_link($term, 'espresso_venue_categories');
262
+					if (
263
+						! is_wp_error($url)
264
+						&& (
265
+							(
266
+								$hide_uncategorized
267
+								&& strtolower($term->name) != esc_html__('uncategorized', 'event_espresso')
268
+							)
269
+							|| ! $hide_uncategorized
270
+						)
271
+					) {
272
+						$category_links[] = '<a href="' . esc_url_raw($url) . '" '
273
+											. 'rel="tag" ' . EED_Events_Archive::link_target() . '>'
274
+											. esc_html($term->name)
275
+											. '</a>';
276
+					}
277
+				}
278
+			}
279
+		}
280
+		return implode(', ', $category_links);
281
+	}
282
+
283
+
284
+	/**
285
+	 *    the_event_date - first date by date order
286
+	 *
287
+	 * @param string $date_format
288
+	 * @param string $time_format
289
+	 * @param int    $EVT_ID
290
+	 * @return    string
291
+	 * @throws EE_Error
292
+	 * @throws ReflectionException
293
+	 */
294
+	public static function the_event_date($date_format = 'D M jS', $time_format = 'g:i a', $EVT_ID = 0)
295
+	{
296
+		$datetime = EEH_Event_View::get_primary_date_obj($EVT_ID);
297
+		$format   = ! empty($date_format) && ! empty($time_format)
298
+				? $date_format . ' ' . $time_format
299
+				: $date_format . $time_format;
300
+		return $datetime instanceof EE_Datetime ? $datetime->get_i18n_datetime('DTT_EVT_start', $format) : '';
301
+	}
302
+
303
+
304
+	/**
305
+	 *    the_event_end_date - last date by date order
306
+	 *
307
+	 * @param string $date_format
308
+	 * @param string $time_format
309
+	 * @param int    $EVT_ID
310
+	 * @return    string
311
+	 * @throws EE_Error
312
+	 * @throws ReflectionException
313
+	 */
314
+	public static function the_event_end_date($date_format = 'D M jS', $time_format = 'g:i a', $EVT_ID = 0)
315
+	{
316
+		$datetime = EEH_Event_View::get_last_date_obj($EVT_ID);
317
+		$format   =
318
+			! empty($date_format) && ! empty($time_format)
319
+				? $date_format . ' ' . $time_format
320
+				: $date_format
321
+				  . $time_format;
322
+		return $datetime instanceof EE_Datetime ? $datetime->get_i18n_datetime('DTT_EVT_end', $format) : '';
323
+	}
324
+
325
+
326
+	/**
327
+	 *    the_earliest_event_date - first date chronologically
328
+	 *
329
+	 * @param string $date_format
330
+	 * @param string $time_format
331
+	 * @param int    $EVT_ID
332
+	 * @return    string
333
+	 * @throws EE_Error
334
+	 * @throws ReflectionException
335
+	 */
336
+	public static function the_earliest_event_date($date_format = 'D M jS', $time_format = 'g:i a', $EVT_ID = 0)
337
+	{
338
+		$datetime = EEH_Event_View::get_earliest_date_obj($EVT_ID);
339
+		$format   =
340
+			! empty($date_format) && ! empty($time_format)
341
+				? $date_format . ' ' . $time_format
342
+				: $date_format
343
+				  . $time_format;
344
+		return $datetime instanceof EE_Datetime ? $datetime->get_i18n_datetime('DTT_EVT_start', $format) : '';
345
+	}
346
+
347
+
348
+	/**
349
+	 *    the_latest_event_date - latest date chronologically
350
+	 *
351
+	 * @param string $date_format
352
+	 * @param string $time_format
353
+	 * @param int    $EVT_ID
354
+	 * @return    string
355
+	 * @throws EE_Error
356
+	 * @throws ReflectionException
357
+	 */
358
+	public static function the_latest_event_date($date_format = 'D M jS', $time_format = 'g:i a', $EVT_ID = 0)
359
+	{
360
+		$datetime = EEH_Event_View::get_latest_date_obj($EVT_ID);
361
+		$format   =
362
+			! empty($date_format) && ! empty($time_format)
363
+				? $date_format . ' ' . $time_format
364
+				: $date_format
365
+				  . $time_format;
366
+		return $datetime instanceof EE_Datetime ? $datetime->get_i18n_datetime('DTT_EVT_end', $format) : '';
367
+	}
368
+
369
+
370
+	/**
371
+	 *    event_date_as_calendar_page
372
+	 *
373
+	 * @param int $EVT_ID
374
+	 * @return    void
375
+	 * @throws EE_Error
376
+	 * @throws ReflectionException
377
+	 */
378
+	public static function event_date_as_calendar_page($EVT_ID = 0)
379
+	{
380
+		$datetime = EEH_Event_View::get_primary_date_obj($EVT_ID);
381
+		if ($datetime instanceof EE_Datetime) {
382
+			?>
383 383
             <div class="event-date-calendar-page-dv">
384 384
                 <div class="event-date-calendar-page-month-dv">
385 385
                     <?php echo esc_html($datetime->get_i18n_datetime('DTT_EVT_start', 'M')); ?>
@@ -389,275 +389,275 @@  discard block
 block discarded – undo
389 389
                 </div>
390 390
             </div>
391 391
             <?php
392
-        }
393
-    }
394
-
395
-
396
-    /**
397
-     *    get_primary_date_obj - orders date by DTT_order
398
-     *
399
-     * @param int $EVT_ID
400
-     * @return EE_Datetime
401
-     * @throws EE_Error
402
-     * @throws ReflectionException
403
-     */
404
-    public static function get_primary_date_obj($EVT_ID = 0)
405
-    {
406
-        $event = EEH_Event_View::get_event($EVT_ID);
407
-        if ($event instanceof EE_Event) {
408
-            $datetimes = $event->get_many_related(
409
-                'Datetime',
410
-                [
411
-                    'limit'    => 1,
412
-                    'order_by' => ['DTT_order' => 'ASC'],
413
-                ]
414
-            );
415
-            return reset($datetimes);
416
-        }
417
-        return null;
418
-    }
419
-
420
-
421
-    /**
422
-     *    get_last_date_obj - orders date by DTT_order
423
-     *
424
-     * @param int $EVT_ID
425
-     * @return EE_Datetime
426
-     * @throws EE_Error
427
-     * @throws ReflectionException
428
-     */
429
-    public static function get_last_date_obj($EVT_ID = 0)
430
-    {
431
-        $event = EEH_Event_View::get_event($EVT_ID);
432
-        if ($event instanceof EE_Event) {
433
-            $datetimes = $event->get_many_related(
434
-                'Datetime',
435
-                [
436
-                    'limit'    => 1,
437
-                    'order_by' => ['DTT_order' => 'DESC'],
438
-                ]
439
-            );
440
-            return end($datetimes);
441
-        }
442
-        return null;
443
-    }
444
-
445
-
446
-    /**
447
-     *    get_earliest_date_obj - orders date chronologically
448
-     *
449
-     * @param int $EVT_ID
450
-     * @return EE_Datetime
451
-     * @throws EE_Error
452
-     * @throws ReflectionException
453
-     */
454
-    public static function get_earliest_date_obj($EVT_ID = 0)
455
-    {
456
-        $event = EEH_Event_View::get_event($EVT_ID);
457
-        if ($event instanceof EE_Event) {
458
-            $datetimes = $event->get_many_related(
459
-                'Datetime',
460
-                [
461
-                    'limit'    => 1,
462
-                    'order_by' => ['DTT_EVT_start' => 'ASC'],
463
-                ]
464
-            );
465
-            return reset($datetimes);
466
-        }
467
-        return null;
468
-    }
469
-
470
-
471
-    /**
472
-     *    get_latest_date_obj - orders date chronologically
473
-     *
474
-     * @param int $EVT_ID
475
-     * @return EE_Datetime
476
-     * @throws EE_Error
477
-     * @throws ReflectionException
478
-     */
479
-    public static function get_latest_date_obj($EVT_ID = 0)
480
-    {
481
-        $event = EEH_Event_View::get_event($EVT_ID);
482
-        if ($event instanceof EE_Event) {
483
-            $datetimes = $event->get_many_related(
484
-                'Datetime',
485
-                [
486
-                    'limit'    => 1,
487
-                    'order_by' => ['DTT_EVT_start' => 'DESC'],
488
-                ]
489
-            );
490
-            return end($datetimes);
491
-        }
492
-        return null;
493
-    }
494
-
495
-
496
-    /**
497
-     *    get_next_upcoming_date_obj - return the next upcoming datetime
498
-     *
499
-     * @param int $EVT_ID
500
-     * @return    EE_Datetime|null
501
-     * @throws EE_Error
502
-     * @throws EE_Error
503
-     */
504
-    public static function get_next_upcoming_date_obj($EVT_ID = 0)
505
-    {
506
-        $datetime = EEM_Datetime::instance()->get_one(
507
-            [
508
-                [
509
-                    'Event.EVT_ID'  => $EVT_ID,
510
-                    'DTT_EVT_start' => ['>=', current_time('mysql', true)],
511
-                ],
512
-                'order_by' => ['DTT_EVT_start' => 'asc'],
513
-            ]
514
-        );
515
-        return $datetime instanceof EE_Datetime ? $datetime : null;
516
-    }
517
-
518
-
519
-    /**
520
-     *    get_next_upcoming_date_obj - return the next upcoming datetime
521
-     *
522
-     * @param int $DTT_ID
523
-     * @return EE_Datetime|null
524
-     * @throws EE_Error
525
-     * @throws ReflectionException
526
-     */
527
-    public static function get_date_obj(int $DTT_ID = 0): ?EE_Datetime
528
-    {
529
-        $datetime = EEM_Datetime::instance()->get_one_by_ID($DTT_ID);
530
-        return $datetime instanceof EE_Datetime ? $datetime : null;
531
-    }
532
-
533
-
534
-    /**
535
-     *    get_all_date_obj
536
-     *
537
-     * @param int  $EVT_ID
538
-     * @param null $include_expired
539
-     * @param bool $include_deleted
540
-     * @param null $limit
541
-     * @return EE_Datetime[]
542
-     * @throws EE_Error
543
-     * @throws EE_Error
544
-     * @throws ReflectionException
545
-     */
546
-    public static function get_all_date_obj(
547
-        $EVT_ID = 0,
548
-        $include_expired = null,
549
-        $include_deleted = false,
550
-        $limit = null
551
-    ) {
552
-        $event = EEH_Event_View::get_event($EVT_ID);
553
-        if ($include_expired === null) {
554
-            if ($event instanceof EE_Event && $event->is_expired()) {
555
-                $include_expired = true;
556
-            } else {
557
-                $include_expired = false;
558
-            }
559
-        }
560
-
561
-        if ($event instanceof EE_Event) {
562
-            return $event->datetimes_ordered($include_expired, $include_deleted, $limit);
563
-        }
564
-        return [];
565
-    }
566
-
567
-
568
-    /**
569
-     *    event_link_url
570
-     *
571
-     * @param int $EVT_ID
572
-     * @return string
573
-     * @throws EE_Error
574
-     * @throws ReflectionException
575
-     */
576
-    public static function event_link_url($EVT_ID = 0)
577
-    {
578
-        $event = EEH_Event_View::get_event($EVT_ID);
579
-        if ($event instanceof EE_Event) {
580
-            $url = $event->external_url() !== null && $event->external_url() !== ''
581
-                ? $event->external_url()
582
-                : get_permalink($event->ID());
583
-            $url = preg_match("~^(?:f|ht)tps?://~i", $url) ? $url : 'https://' . $url;
584
-            return esc_url_raw($url);
585
-        }
586
-        return '';
587
-    }
588
-
589
-
590
-    /**
591
-     *    event_phone
592
-     *
593
-     * @param int $EVT_ID
594
-     * @return    string
595
-     * @throws EE_Error
596
-     * @throws EE_Error
597
-     * @throws ReflectionException
598
-     */
599
-    public static function event_phone($EVT_ID = 0)
600
-    {
601
-        $event = EEH_Event_View::get_event($EVT_ID);
602
-        if ($event instanceof EE_Event) {
603
-            return EEH_Schema::telephone($event->phone());
604
-        }
605
-        return null;
606
-    }
607
-
608
-
609
-    /**
610
-     *    edit_event_link
611
-     *
612
-     * @param int    $EVT_ID
613
-     * @param string $link
614
-     * @param string $before
615
-     * @param string $after
616
-     * @return    string
617
-     * @throws EE_Error
618
-     * @throws ReflectionException
619
-     */
620
-    public static function edit_event_link($EVT_ID = 0, $link = '', $before = '', $after = '')
621
-    {
622
-        $event = EEH_Event_View::get_event($EVT_ID);
623
-        if ($event instanceof EE_Event) {
624
-            // can the user edit this post ?
625
-            if (current_user_can('edit_post', $event->ID())) {
626
-                // set link text
627
-                $link_text = ! empty($link) ? $link : esc_html__('edit this event', 'event_espresso');
628
-                // generate nonce
629
-                $nonce = wp_create_nonce('edit_nonce');
630
-                // generate url to event editor for this event
631
-                $url =
632
-                    add_query_arg(
633
-                        [
634
-                            'page'       => 'espresso_events',
635
-                            'action'     => 'edit',
636
-                            'post'       => $event->ID(),
637
-                            'edit_nonce' => $nonce,
638
-                        ],
639
-                        admin_url()
640
-                    );
641
-                // get edit CPT text
642
-                $post_type_obj = get_post_type_object(EspressoPostType::EVENTS);
643
-                // build final link html
644
-                $link = '<a class="post-edit-link" href="' . $url . '" ';
645
-                $link .= ' title="' . esc_attr($post_type_obj->labels->edit_item) . '"';
646
-                $link .= EED_Events_Archive::link_target();
647
-                $link .= '>' . $link_text . '</a>';
648
-                // put it all together
649
-                return $before . apply_filters('edit_post_link', $link, $event->ID()) . $after;
650
-            }
651
-        }
652
-        return '';
653
-    }
654
-
655
-
656
-    /**
657
-     * @return string
658
-     */
659
-    public static function event_archive_url()
660
-    {
661
-        return get_post_type_archive_link(EspressoPostType::EVENTS);
662
-    }
392
+		}
393
+	}
394
+
395
+
396
+	/**
397
+	 *    get_primary_date_obj - orders date by DTT_order
398
+	 *
399
+	 * @param int $EVT_ID
400
+	 * @return EE_Datetime
401
+	 * @throws EE_Error
402
+	 * @throws ReflectionException
403
+	 */
404
+	public static function get_primary_date_obj($EVT_ID = 0)
405
+	{
406
+		$event = EEH_Event_View::get_event($EVT_ID);
407
+		if ($event instanceof EE_Event) {
408
+			$datetimes = $event->get_many_related(
409
+				'Datetime',
410
+				[
411
+					'limit'    => 1,
412
+					'order_by' => ['DTT_order' => 'ASC'],
413
+				]
414
+			);
415
+			return reset($datetimes);
416
+		}
417
+		return null;
418
+	}
419
+
420
+
421
+	/**
422
+	 *    get_last_date_obj - orders date by DTT_order
423
+	 *
424
+	 * @param int $EVT_ID
425
+	 * @return EE_Datetime
426
+	 * @throws EE_Error
427
+	 * @throws ReflectionException
428
+	 */
429
+	public static function get_last_date_obj($EVT_ID = 0)
430
+	{
431
+		$event = EEH_Event_View::get_event($EVT_ID);
432
+		if ($event instanceof EE_Event) {
433
+			$datetimes = $event->get_many_related(
434
+				'Datetime',
435
+				[
436
+					'limit'    => 1,
437
+					'order_by' => ['DTT_order' => 'DESC'],
438
+				]
439
+			);
440
+			return end($datetimes);
441
+		}
442
+		return null;
443
+	}
444
+
445
+
446
+	/**
447
+	 *    get_earliest_date_obj - orders date chronologically
448
+	 *
449
+	 * @param int $EVT_ID
450
+	 * @return EE_Datetime
451
+	 * @throws EE_Error
452
+	 * @throws ReflectionException
453
+	 */
454
+	public static function get_earliest_date_obj($EVT_ID = 0)
455
+	{
456
+		$event = EEH_Event_View::get_event($EVT_ID);
457
+		if ($event instanceof EE_Event) {
458
+			$datetimes = $event->get_many_related(
459
+				'Datetime',
460
+				[
461
+					'limit'    => 1,
462
+					'order_by' => ['DTT_EVT_start' => 'ASC'],
463
+				]
464
+			);
465
+			return reset($datetimes);
466
+		}
467
+		return null;
468
+	}
469
+
470
+
471
+	/**
472
+	 *    get_latest_date_obj - orders date chronologically
473
+	 *
474
+	 * @param int $EVT_ID
475
+	 * @return EE_Datetime
476
+	 * @throws EE_Error
477
+	 * @throws ReflectionException
478
+	 */
479
+	public static function get_latest_date_obj($EVT_ID = 0)
480
+	{
481
+		$event = EEH_Event_View::get_event($EVT_ID);
482
+		if ($event instanceof EE_Event) {
483
+			$datetimes = $event->get_many_related(
484
+				'Datetime',
485
+				[
486
+					'limit'    => 1,
487
+					'order_by' => ['DTT_EVT_start' => 'DESC'],
488
+				]
489
+			);
490
+			return end($datetimes);
491
+		}
492
+		return null;
493
+	}
494
+
495
+
496
+	/**
497
+	 *    get_next_upcoming_date_obj - return the next upcoming datetime
498
+	 *
499
+	 * @param int $EVT_ID
500
+	 * @return    EE_Datetime|null
501
+	 * @throws EE_Error
502
+	 * @throws EE_Error
503
+	 */
504
+	public static function get_next_upcoming_date_obj($EVT_ID = 0)
505
+	{
506
+		$datetime = EEM_Datetime::instance()->get_one(
507
+			[
508
+				[
509
+					'Event.EVT_ID'  => $EVT_ID,
510
+					'DTT_EVT_start' => ['>=', current_time('mysql', true)],
511
+				],
512
+				'order_by' => ['DTT_EVT_start' => 'asc'],
513
+			]
514
+		);
515
+		return $datetime instanceof EE_Datetime ? $datetime : null;
516
+	}
517
+
518
+
519
+	/**
520
+	 *    get_next_upcoming_date_obj - return the next upcoming datetime
521
+	 *
522
+	 * @param int $DTT_ID
523
+	 * @return EE_Datetime|null
524
+	 * @throws EE_Error
525
+	 * @throws ReflectionException
526
+	 */
527
+	public static function get_date_obj(int $DTT_ID = 0): ?EE_Datetime
528
+	{
529
+		$datetime = EEM_Datetime::instance()->get_one_by_ID($DTT_ID);
530
+		return $datetime instanceof EE_Datetime ? $datetime : null;
531
+	}
532
+
533
+
534
+	/**
535
+	 *    get_all_date_obj
536
+	 *
537
+	 * @param int  $EVT_ID
538
+	 * @param null $include_expired
539
+	 * @param bool $include_deleted
540
+	 * @param null $limit
541
+	 * @return EE_Datetime[]
542
+	 * @throws EE_Error
543
+	 * @throws EE_Error
544
+	 * @throws ReflectionException
545
+	 */
546
+	public static function get_all_date_obj(
547
+		$EVT_ID = 0,
548
+		$include_expired = null,
549
+		$include_deleted = false,
550
+		$limit = null
551
+	) {
552
+		$event = EEH_Event_View::get_event($EVT_ID);
553
+		if ($include_expired === null) {
554
+			if ($event instanceof EE_Event && $event->is_expired()) {
555
+				$include_expired = true;
556
+			} else {
557
+				$include_expired = false;
558
+			}
559
+		}
560
+
561
+		if ($event instanceof EE_Event) {
562
+			return $event->datetimes_ordered($include_expired, $include_deleted, $limit);
563
+		}
564
+		return [];
565
+	}
566
+
567
+
568
+	/**
569
+	 *    event_link_url
570
+	 *
571
+	 * @param int $EVT_ID
572
+	 * @return string
573
+	 * @throws EE_Error
574
+	 * @throws ReflectionException
575
+	 */
576
+	public static function event_link_url($EVT_ID = 0)
577
+	{
578
+		$event = EEH_Event_View::get_event($EVT_ID);
579
+		if ($event instanceof EE_Event) {
580
+			$url = $event->external_url() !== null && $event->external_url() !== ''
581
+				? $event->external_url()
582
+				: get_permalink($event->ID());
583
+			$url = preg_match("~^(?:f|ht)tps?://~i", $url) ? $url : 'https://' . $url;
584
+			return esc_url_raw($url);
585
+		}
586
+		return '';
587
+	}
588
+
589
+
590
+	/**
591
+	 *    event_phone
592
+	 *
593
+	 * @param int $EVT_ID
594
+	 * @return    string
595
+	 * @throws EE_Error
596
+	 * @throws EE_Error
597
+	 * @throws ReflectionException
598
+	 */
599
+	public static function event_phone($EVT_ID = 0)
600
+	{
601
+		$event = EEH_Event_View::get_event($EVT_ID);
602
+		if ($event instanceof EE_Event) {
603
+			return EEH_Schema::telephone($event->phone());
604
+		}
605
+		return null;
606
+	}
607
+
608
+
609
+	/**
610
+	 *    edit_event_link
611
+	 *
612
+	 * @param int    $EVT_ID
613
+	 * @param string $link
614
+	 * @param string $before
615
+	 * @param string $after
616
+	 * @return    string
617
+	 * @throws EE_Error
618
+	 * @throws ReflectionException
619
+	 */
620
+	public static function edit_event_link($EVT_ID = 0, $link = '', $before = '', $after = '')
621
+	{
622
+		$event = EEH_Event_View::get_event($EVT_ID);
623
+		if ($event instanceof EE_Event) {
624
+			// can the user edit this post ?
625
+			if (current_user_can('edit_post', $event->ID())) {
626
+				// set link text
627
+				$link_text = ! empty($link) ? $link : esc_html__('edit this event', 'event_espresso');
628
+				// generate nonce
629
+				$nonce = wp_create_nonce('edit_nonce');
630
+				// generate url to event editor for this event
631
+				$url =
632
+					add_query_arg(
633
+						[
634
+							'page'       => 'espresso_events',
635
+							'action'     => 'edit',
636
+							'post'       => $event->ID(),
637
+							'edit_nonce' => $nonce,
638
+						],
639
+						admin_url()
640
+					);
641
+				// get edit CPT text
642
+				$post_type_obj = get_post_type_object(EspressoPostType::EVENTS);
643
+				// build final link html
644
+				$link = '<a class="post-edit-link" href="' . $url . '" ';
645
+				$link .= ' title="' . esc_attr($post_type_obj->labels->edit_item) . '"';
646
+				$link .= EED_Events_Archive::link_target();
647
+				$link .= '>' . $link_text . '</a>';
648
+				// put it all together
649
+				return $before . apply_filters('edit_post_link', $link, $event->ID()) . $after;
650
+			}
651
+		}
652
+		return '';
653
+	}
654
+
655
+
656
+	/**
657
+	 * @return string
658
+	 */
659
+	public static function event_archive_url()
660
+	{
661
+		return get_post_type_archive_link(EspressoPostType::EVENTS);
662
+	}
663 663
 }
Please login to merge, or discard this patch.
core/helpers/EEH_Event_Query.helper.php 2 patches
Indentation   +629 added lines, -629 removed lines patch added patch discarded remove patch
@@ -15,633 +15,633 @@
 block discarded – undo
15 15
  */
16 16
 class EEH_Event_Query
17 17
 {
18
-    /**
19
-     * Start Date
20
-     */
21
-    protected static string $_event_query_month;
22
-
23
-    /**
24
-     * Category
25
-     */
26
-    protected static string $_event_query_category;
27
-
28
-    /**
29
-     * whether to display expired events in the event list
30
-     */
31
-    protected static bool $_event_query_show_expired = false;
32
-
33
-    /**
34
-     * list of params for controlling how the query results are ordered
35
-     */
36
-    protected static array $_event_query_orderby = [];
37
-
38
-    /**
39
-     * direction list is sorted
40
-     */
41
-    protected static string $_event_query_sort;
42
-
43
-    /**
44
-     * list of params used to build the query's various clauses
45
-     */
46
-    protected static array $_query_params = [];
47
-
48
-
49
-    /**
50
-     * @return void
51
-     */
52
-    public static function add_query_filters()
53
-    {
54
-        // add query filters
55
-        add_action('pre_get_posts', ['EEH_Event_Query', 'filter_query_parts']);
56
-    }
57
-
58
-
59
-    /**
60
-     * @param WP_Query $WP_Query
61
-     * @return bool
62
-     * @noinspection PhpUnnecessaryBoolCastInspection
63
-     */
64
-    public static function apply_query_filters(WP_Query $WP_Query): bool
65
-    {
66
-        return (
67
-                isset($WP_Query->query['post_type'])
68
-                && $WP_Query->query['post_type'] === 'espresso_events'
69
-            )
70
-            || (bool) apply_filters('FHEE__EEH_Event_Query__apply_query_filters', false);
71
-    }
72
-
73
-
74
-    /**
75
-     * @param WP_Query $WP_Query
76
-     */
77
-    public static function filter_query_parts(WP_Query $WP_Query)
78
-    {
79
-        // ONLY add our filters if this isn't the main wp_query,
80
-        // because if this is the main wp_query we already have
81
-        // our cpt strategies take care of adding things in.
82
-        if (! $WP_Query->is_main_query()) {
83
-            // build event list query
84
-            add_filter('posts_fields', ['EEH_Event_Query', 'posts_fields'], 10, 2);
85
-            add_filter('posts_join', ['EEH_Event_Query', 'posts_join'], 10, 2);
86
-            add_filter('posts_where', ['EEH_Event_Query', 'posts_where'], 10, 2);
87
-            add_filter('posts_orderby', ['EEH_Event_Query', 'posts_orderby'], 10, 2);
88
-            add_filter('posts_clauses_request', ['EEH_Event_Query', 'posts_clauses'], 10, 2);
89
-        }
90
-    }
91
-
92
-
93
-    /**
94
-     * @param string|null  $month
95
-     * @param string|null  $category
96
-     * @param bool         $show_expired
97
-     * @param array|string $orderby
98
-     * @param string|null  $sort
99
-     */
100
-    public static function set_query_params(
101
-        ?string $month = '',
102
-        ?string $category = '',
103
-        bool $show_expired = false,
104
-        $orderby = 'start_date',
105
-        ?string $sort = 'ASC'
106
-    ) {
107
-        self::$_query_params                        = [];
108
-        EEH_Event_Query::$_event_query_month        = EEH_Event_Query::_display_month($month);
109
-        EEH_Event_Query::$_event_query_category     = EEH_Event_Query::_event_category_slug($category);
110
-        EEH_Event_Query::$_event_query_show_expired = EEH_Event_Query::_show_expired($show_expired);
111
-        EEH_Event_Query::$_event_query_orderby      = EEH_Event_Query::_orderby($orderby);
112
-        EEH_Event_Query::$_event_query_sort         = EEH_Event_Query::_sort($sort);
113
-    }
114
-
115
-
116
-    /**
117
-     * what month should the event list display events for?
118
-     *
119
-     * @param string|null $month
120
-     * @return string
121
-     */
122
-    private static function _display_month(?string $month = ''): string
123
-    {
124
-        return self::getRequest()->getRequestParam('event_query_month', $month);
125
-    }
126
-
127
-
128
-    /**
129
-     * @param string|null $category
130
-     * @return string
131
-     */
132
-    private static function _event_category_slug(?string $category = ''): string
133
-    {
134
-        return self::getRequest()->getRequestParam('event_query_category', $category);
135
-    }
136
-
137
-
138
-    /**
139
-     * @param bool $show_expired
140
-     * @return bool
141
-     */
142
-    private static function _show_expired(bool $show_expired = false): bool
143
-    {
144
-        // override default expired option if set via filter
145
-        return self::getRequest()->getRequestParam('event_query_show_expired', $show_expired, 'bool');
146
-    }
147
-
148
-
149
-    /**
150
-     * @param array|string|null $orderby
151
-     * @return array
152
-     */
153
-    private static function _orderby($orderby = 'start_date'): array
154
-    {
155
-        $event_query_orderby = self::getRequest()->getRequestParam(
156
-            'event_query_orderby',
157
-            (array) $orderby,
158
-            DataType::STRING,
159
-            true
160
-        );
161
-        $event_query_orderby = is_array($event_query_orderby)
162
-            ? $event_query_orderby
163
-            : explode(',', $event_query_orderby);
164
-        $event_query_orderby = array_map('trim', $event_query_orderby);
165
-        return array_map('sanitize_text_field', $event_query_orderby);
166
-    }
167
-
168
-
169
-    /**
170
-     * @param string|null $sort
171
-     * @return string
172
-     */
173
-    private static function _sort(?string $sort = 'ASC'): string
174
-    {
175
-        $sort = self::getRequest()->getRequestParam('event_query_sort', $sort);
176
-        return in_array($sort, ['ASC', 'asc', 'DESC', 'desc'], true)
177
-            ? strtoupper($sort)
178
-            : 'ASC';
179
-    }
180
-
181
-
182
-    /**
183
-     * Filters the clauses for the WP_Query object
184
-     *
185
-     * @param array    $clauses array of clauses
186
-     * @param WP_Query $wp_query
187
-     * @return array   array of clauses
188
-     */
189
-    public static function posts_clauses(array $clauses, WP_Query $wp_query): array
190
-    {
191
-        if (EEH_Event_Query::apply_query_filters($wp_query)) {
192
-            global $wpdb;
193
-            $clauses['groupby'] = $wpdb->posts . '.ID ';
194
-        }
195
-        return $clauses;
196
-    }
197
-
198
-
199
-    /**
200
-     * @param string   $SQL
201
-     * @param WP_Query $wp_query
202
-     * @return string
203
-     * @throws EE_Error
204
-     * @throws ReflectionException
205
-     */
206
-    public static function posts_fields(string $SQL, WP_Query $wp_query): string
207
-    {
208
-        if (EEH_Event_Query::apply_query_filters($wp_query)) {
209
-            // adds something like ", wp_esp_datetime.* " to WP Query SELECT statement
210
-            $SQL .= EEH_Event_Query::posts_fields_sql_for_orderby(EEH_Event_Query::$_event_query_orderby);
211
-        }
212
-        return $SQL;
213
-    }
214
-
215
-
216
-    /**
217
-     * @param array $orderby_params
218
-     * @return string
219
-     * @throws EE_Error
220
-     * @throws ReflectionException
221
-     */
222
-    public static function posts_fields_sql_for_orderby(array $orderby_params = []): string
223
-    {
224
-        $SQL = ', MIN( ' . EEM_Datetime::instance()->table() . '.DTT_EVT_start ) as event_start_date ';
225
-        foreach ($orderby_params as $orderby) {
226
-            switch ($orderby) {
227
-                case 'ticket_start':
228
-                    $SQL .= ', ' . EEM_Ticket::instance()->table() . '.TKT_start_date';
229
-                    break;
230
-                case 'ticket_end':
231
-                    $SQL .= ', ' . EEM_Ticket::instance()->table() . '.TKT_end_date';
232
-                    break;
233
-                case 'venue_title':
234
-                    $SQL .= ', Venue.post_title AS venue_title';
235
-                    break;
236
-                case 'city':
237
-                    $SQL .= ', ' . EEM_Venue::instance()->second_table() . '.VNU_city';
238
-                    break;
239
-                case 'state':
240
-                    $SQL .= ', ' . EEM_State::instance()->table() . '.STA_name';
241
-                    break;
242
-            }
243
-        }
244
-        return $SQL;
245
-    }
246
-
247
-
248
-    /**
249
-     * @param string   $SQL
250
-     * @param WP_Query $wp_query
251
-     * @return string
252
-     * @throws EE_Error
253
-     * @throws ReflectionException
254
-     */
255
-    public static function posts_join(string $SQL, WP_Query $wp_query): string
256
-    {
257
-        if (EEH_Event_Query::apply_query_filters($wp_query)) {
258
-            // Category
259
-            $SQL = EEH_Event_Query::posts_join_sql_for_show_expired($SQL, EEH_Event_Query::$_event_query_show_expired);
260
-            $SQL = EEH_Event_Query::posts_join_sql_for_terms($SQL, EEH_Event_Query::$_event_query_category);
261
-            $SQL = EEH_Event_Query::posts_join_for_orderby($SQL, EEH_Event_Query::$_event_query_orderby);
262
-        }
263
-        return $SQL;
264
-    }
265
-
266
-
267
-    /**
268
-     * @param string  $SQL
269
-     * @param boolean $show_expired if TRUE, then displayed past events
270
-     * @return string
271
-     * @throws EE_Error
272
-     * @throws ReflectionException
273
-     */
274
-    public static function posts_join_sql_for_show_expired(string $SQL = '', bool $show_expired = false): string
275
-    {
276
-        if (! $show_expired) {
277
-            $datetime_table = EEM_Datetime::instance()->table();
278
-            // don't add if this is already in the SQL
279
-            if (strpos($SQL, "INNER JOIN $datetime_table") === false) {
280
-                $event_table = EEM_Event::instance()->table();
281
-                $event_table_pk = EEM_Event::instance()->primary_key_name();
282
-                $SQL .= " INNER JOIN $datetime_table ON ( $event_table.ID = $datetime_table.$event_table_pk ) ";
283
-            }
284
-        }
285
-        return $SQL;
286
-    }
287
-
288
-
289
-    /**
290
-     * @param string $SQL
291
-     * @param string $join_terms    pass TRUE or term string, doesn't really matter since this value doesn't really get
292
-     *                              used for anything yet
293
-     * @return string
294
-     */
295
-    public static function posts_join_sql_for_terms(string $SQL = '', string $join_terms = ''): string
296
-    {
297
-        global $wpdb;
298
-        if (! empty($join_terms) && strpos($SQL, "LEFT JOIN $wpdb->term_relationships") === false) {
299
-            $SQL .= " LEFT JOIN $wpdb->term_relationships ON ($wpdb->posts.ID = $wpdb->term_relationships.object_id)";
300
-            $SQL .= " LEFT JOIN $wpdb->term_taxonomy ON ($wpdb->term_relationships.term_taxonomy_id = $wpdb->term_taxonomy.term_taxonomy_id)";
301
-            $SQL .= " LEFT JOIN $wpdb->terms ON ($wpdb->terms.term_id = $wpdb->term_taxonomy.term_id) ";
302
-        }
303
-        return $SQL;
304
-    }
305
-
306
-
307
-    /**
308
-     * usage:  $SQL .= EEH_Event_Query::posts_join_for_orderby( $orderby_params );
309
-     *
310
-     * @param string $SQL
311
-     * @param array  $orderby_params
312
-     * @return string
313
-     * @throws EE_Error
314
-     * @throws ReflectionException
315
-     */
316
-    public static function posts_join_for_orderby(string $SQL = '', array $orderby_params = []): string
317
-    {
318
-        foreach ($orderby_params as $orderby) {
319
-            switch ($orderby) {
320
-                case 'ticket_start':
321
-                case 'ticket_end':
322
-                    $SQL .= EEH_Event_Query::_posts_join_for_datetime(
323
-                        $SQL,
324
-                        EEM_Datetime_Ticket::instance()->table() . '.' . EEM_Datetime::instance()->primary_key_name()
325
-                    );
326
-                    $SQL .= EEH_Event_Query::postsJoinForTicket($SQL);
327
-                    break;
328
-                case 'venue_title':
329
-                case 'city':
330
-                    $SQL .= EEH_Event_Query::_posts_join_for_event_venue($SQL);
331
-                    break;
332
-                case 'state':
333
-                    $SQL .= EEH_Event_Query::_posts_join_for_event_venue($SQL);
334
-                    $SQL .= EEH_Event_Query::_posts_join_for_venue_state($SQL);
335
-                    break;
336
-                case 'start_date':
337
-                default:
338
-                    $SQL .= EEH_Event_Query::_posts_join_for_datetime($SQL, EEM_Event::instance()->table() . '.ID');
339
-                    break;
340
-            }
341
-        }
342
-        return $SQL;
343
-    }
344
-
345
-
346
-    /**
347
-     * @param string $SQL
348
-     * @param string $join
349
-     * @return string
350
-     * @throws EE_Error
351
-     * @throws ReflectionException
352
-     */
353
-    protected static function _posts_join_for_datetime(string $SQL = '', string $join = ''): string
354
-    {
355
-        if (! empty($join)) {
356
-            $datetime_table = EEM_Datetime::instance()->table();
357
-            // don't add if this is already in the SQL
358
-            if (strpos($SQL, "INNER JOIN $datetime_table") === false) {
359
-                $event_table_pk = EEM_Event::instance()->primary_key_name();
360
-                return " INNER JOIN $datetime_table ON ( $join = $datetime_table.$event_table_pk )";
361
-            }
362
-        }
363
-        return '';
364
-    }
365
-
366
-
367
-    /**
368
-     * @param string $SQL
369
-     * @return string
370
-     * @throws EE_Error
371
-     * @throws ReflectionException
372
-     */
373
-    protected static function _posts_join_for_event_venue(string $SQL = ''): string
374
-    {
375
-        $venue_table = EEM_Venue::instance()->table();
376
-        // don't add joins if they have already been added
377
-        if (strpos($SQL, "LEFT JOIN $venue_table") === false) {
378
-            global $wpdb;
379
-            // grab venue table PK name & event_meta table name
380
-            $VNU_ID     = EEM_Venue::instance()->primary_key_name();
381
-            $event_meta = EEM_Event::instance()->second_table();
382
-            // generate conditions for:  Event <=> Venue  JOIN clause
383
-            $event_venue_join = "Venue.ID = $event_meta.$VNU_ID";
384
-            // grab wp_posts (event), venue, and venue_meta table names
385
-            $wp_posts   = $wpdb->posts;
386
-            $venue_meta = EEM_Venue::instance()->second_table();
387
-            // generate JOIN clause for: Event <=> Event Meta
388
-            $venue_SQL = " LEFT JOIN $event_meta ON ( $wp_posts.ID = $event_meta.EVT_ID )";
389
-            // generate JOIN clause for: Event Meta <=> Venue
390
-            $venue_SQL .= " LEFT JOIN $venue_table AS Venue ON ( $event_venue_join )";
391
-            // generate JOIN clause for: Venue <=> Venue Meta
392
-            $venue_SQL .= " LEFT JOIN $venue_meta ON ( Venue.ID = $venue_meta.$VNU_ID )";
393
-            unset($venue_table, $VNU_ID, $event_meta, $venue_meta, $event_venue_join);
394
-            return $venue_SQL;
395
-        }
396
-        unset($VNU_ID, $event_meta, $event_venue_join);
397
-        return '';
398
-    }
399
-
400
-
401
-    /**
402
-     * @param string $SQL
403
-     * @return string
404
-     * @throws EE_Error
405
-     * @throws ReflectionException
406
-     * @since 5.0.20.p
407
-     */
408
-    protected static function postsJoinForTicket(string $SQL = ''): string
409
-    {
410
-        $ticket_table = EEM_Ticket::instance()->table();
411
-        // don't add if this is already in the SQL
412
-        if (strpos($SQL, "LEFT JOIN $ticket_table") === false) {
413
-            $datetime_table = EEM_Datetime::instance()->table();
414
-            $ticket_table_pk = EEM_Ticket::instance()->primary_key_name();
415
-            return " LEFT JOIN $ticket_table ON ( $datetime_table.$ticket_table_pk = $ticket_table.$ticket_table_pk )";
416
-        }
417
-        return '';
418
-    }
419
-
420
-
421
-
422
-    /**
423
-     * @param string $SQL
424
-     * @return string
425
-     * @throws EE_Error
426
-     * @throws ReflectionException
427
-     */
428
-    protected static function _posts_join_for_venue_state(string $SQL = ''): string
429
-    {
430
-        $state_table = EEM_State::instance()->table();
431
-        // don't add join if it has already been added
432
-        if (strpos($SQL, "LEFT JOIN $state_table") === false) {
433
-            $state_table_pk = EEM_State::instance()->primary_key_name();
434
-            $venue_meta_table = EEM_Venue::instance()->second_table();
435
-            // like: wp_esp_venue_meta.STA_ID = wp_esp_state.STA_ID
436
-            return " LEFT JOIN $state_table ON ( $venue_meta_table.$state_table_pk = $state_table.$state_table_pk )";
437
-        }
438
-        return '';
439
-    }
440
-
441
-
442
-    /**
443
-     * @param string   $SQL
444
-     * @param WP_Query $wp_query
445
-     * @return string
446
-     * @throws EE_Error
447
-     * @throws ReflectionException
448
-     */
449
-    public static function posts_where(string $SQL, WP_Query $wp_query): string
450
-    {
451
-        if (EEH_Event_Query::apply_query_filters($wp_query)) {
452
-            // Show Expired ?
453
-            $SQL .= EEH_Event_Query::posts_where_sql_for_show_expired(EEH_Event_Query::$_event_query_show_expired);
454
-            // Category
455
-            $SQL .= EEH_Event_Query::posts_where_sql_for_event_category_slug(EEH_Event_Query::$_event_query_category);
456
-            // Start Date
457
-            $SQL .= EEH_Event_Query::posts_where_sql_for_event_list_month(EEH_Event_Query::$_event_query_month);
458
-            // Trashed DateTimes
459
-            $SQL .= EEH_Event_Query::posts_where_sql_for_non_trashed_datetimes();
460
-        }
461
-        return $SQL;
462
-    }
463
-
464
-
465
-    /**
466
-     * @param boolean $show_expired if TRUE, then displayed past events
467
-     * @return string
468
-     * @throws EE_Error
469
-     * @throws ReflectionException
470
-     */
471
-    public static function posts_where_sql_for_show_expired(bool $show_expired = false): string
472
-    {
473
-        return ! $show_expired
474
-            ? ' AND ' . EEM_Datetime::instance()->table() . '.DTT_EVT_end > \'' . current_time('mysql', true) . '\' '
475
-            : '';
476
-    }
477
-
478
-
479
-    /**
480
-     * @param string|null $event_category_slug
481
-     * @return string
482
-     */
483
-    public static function posts_where_sql_for_event_category_slug(?string $event_category_slug = null): string
484
-    {
485
-        global $wpdb;
486
-        if (! empty($event_category_slug)) {
487
-            $event_category_slugs_array   = array_map('trim', explode(',', $event_category_slug));
488
-            $event_category_slugs_prepare = implode(', ', array_fill(0, count($event_category_slugs_array), '%s'));
489
-            return $wpdb->prepare(
490
-                " AND $wpdb->terms.slug IN ($event_category_slugs_prepare) ",
491
-                $event_category_slugs_array
492
-            );
493
-        }
494
-        return '';
495
-    }
496
-
497
-
498
-    /**
499
-     * @param string|null $month
500
-     * @return string
501
-     * @throws EE_Error
502
-     * @throws ReflectionException
503
-     */
504
-    public static function posts_where_sql_for_event_list_month(?string $month = null): string
505
-    {
506
-        $SQL = '';
507
-        if (! empty($month)) {
508
-            $datetime_table = EEM_Datetime::instance()->table();
509
-            // event start date is LESS than the end of the month ( so nothing that doesn't start until next month )
510
-            $SQL = " AND $datetime_table.DTT_EVT_start <= '";
511
-            $SQL .= date('Y-m-t 23:59:59', EEH_DTT_Helper::first_of_month_timestamp($month)) . "'";
512
-            // event end date is GREATER than the start of the month ( so nothing that ended before this month )
513
-            $SQL .= " AND $datetime_table.DTT_EVT_end >= '";
514
-            $SQL .= date('Y-m-01 0:0:00', EEH_DTT_Helper::first_of_month_timestamp($month)) . "' ";
515
-        }
516
-        return $SQL;
517
-    }
518
-
519
-
520
-    /**
521
-     * @return string
522
-     * @throws EE_Error
523
-     * @throws ReflectionException
524
-     */
525
-    public static function posts_where_sql_for_non_trashed_datetimes(): string
526
-    {
527
-        return ' AND ' . EEM_Datetime::instance()->table() . '.DTT_deleted = 0';
528
-    }
529
-
530
-
531
-    /**
532
-     * @param string   $SQL
533
-     * @param WP_Query $wp_query
534
-     * @return string
535
-     * @throws EE_Error
536
-     * @throws ReflectionException
537
-     */
538
-    public static function posts_orderby(string $SQL, WP_Query $wp_query): string
539
-    {
540
-        if (EEH_Event_Query::apply_query_filters($wp_query)) {
541
-            $SQL = EEH_Event_Query::posts_orderby_sql(
542
-                EEH_Event_Query::$_event_query_orderby,
543
-                EEH_Event_Query::$_event_query_sort
544
-            );
545
-        }
546
-        return $SQL;
547
-    }
548
-
549
-
550
-    /**
551
-     *    posts_orderby_sql
552
-     *    possible parameters:
553
-     *    ID
554
-     *    start_date
555
-     *    end_date
556
-     *    event_name
557
-     *    category_slug
558
-     *    ticket_start
559
-     *    ticket_end
560
-     *    venue_title
561
-     *    city
562
-     *    state
563
-     *    **IMPORTANT**
564
-     *    make sure to also send the $orderby_params array to the posts_join_for_orderby() method
565
-     *    or else some of the table references below will result in MySQL errors
566
-     *
567
-     * @param array  $orderby_params
568
-     * @param string $sort
569
-     * @return string
570
-     * @throws EE_Error
571
-     * @throws ReflectionException
572
-     */
573
-    public static function posts_orderby_sql(array $orderby_params = [], string $sort = 'ASC'): string
574
-    {
575
-        global $wpdb;
576
-        $SQL     = '';
577
-        $counter = 0;
578
-        $sort    = in_array($sort, ['ASC', 'asc', 'DESC', 'desc'], true)
579
-            ? strtoupper($sort)
580
-            : 'ASC';
581
-        // make sure 'orderby' is set in query params
582
-        if (! isset(self::$_query_params['orderby'])) {
583
-            self::$_query_params['orderby'] = [];
584
-        }
585
-        // loop thru $orderby_params (type cast as array)
586
-        foreach ($orderby_params as $orderby) {
587
-            // check if we have already added this param
588
-            if (isset(self::$_query_params['orderby'][ $orderby ])) {
589
-                // if so then remove from the $orderby_params so that the count() method below is accurate
590
-                unset($orderby_params[ $orderby ]);
591
-                // then bump ahead to the next param
592
-                continue;
593
-            }
594
-            // this will add a comma depending on whether this is the first or last param
595
-            $glue = $counter === 0 || $counter === count($orderby_params) ? ' ' : ', ';
596
-            // ok what's we dealing with?
597
-            switch ($orderby) {
598
-                case 'id':
599
-                case 'ID':
600
-                    $SQL .= $glue . $wpdb->posts . '.ID ' . $sort;
601
-                    break;
602
-                case 'end_date':
603
-                    $SQL .= $glue . EEM_Datetime::instance()->table() . '.DTT_EVT_end ' . $sort;
604
-                    break;
605
-                case 'event_name':
606
-                    $SQL .= $glue . $wpdb->posts . '.post_title ' . $sort;
607
-                    break;
608
-                case 'category_slug':
609
-                    $SQL .= $glue . $wpdb->terms . '.slug ' . $sort;
610
-                    break;
611
-                case 'ticket_start':
612
-                    $SQL .= $glue . EEM_Ticket::instance()->table() . '.TKT_start_date ' . $sort;
613
-                    break;
614
-                case 'ticket_end':
615
-                    $SQL .= $glue . EEM_Ticket::instance()->table() . '.TKT_end_date ' . $sort;
616
-                    break;
617
-                case 'venue_title':
618
-                    $SQL .= $glue . 'venue_title ' . $sort;
619
-                    break;
620
-                case 'city':
621
-                    $SQL .= $glue . EEM_Venue::instance()->second_table() . '.VNU_city ' . $sort;
622
-                    break;
623
-                case 'state':
624
-                    $SQL .= $glue . EEM_State::instance()->table() . '.STA_name ' . $sort;
625
-                    break;
626
-                case 'start_date':
627
-                default:
628
-                    $SQL .= $glue . ' event_start_date ' . $sort;
629
-                    break;
630
-            }
631
-            // add to array of orderby params that have been added
632
-            self::$_query_params['orderby'][ $orderby ] = true;
633
-            $counter++;
634
-        }
635
-        return $SQL;
636
-    }
637
-
638
-
639
-    /**
640
-     * @return RequestInterface
641
-     * @since   4.10.14.p
642
-     */
643
-    private static function getRequest(): RequestInterface
644
-    {
645
-        return LoaderFactory::getLoader()->getShared(RequestInterface::class);
646
-    }
18
+	/**
19
+	 * Start Date
20
+	 */
21
+	protected static string $_event_query_month;
22
+
23
+	/**
24
+	 * Category
25
+	 */
26
+	protected static string $_event_query_category;
27
+
28
+	/**
29
+	 * whether to display expired events in the event list
30
+	 */
31
+	protected static bool $_event_query_show_expired = false;
32
+
33
+	/**
34
+	 * list of params for controlling how the query results are ordered
35
+	 */
36
+	protected static array $_event_query_orderby = [];
37
+
38
+	/**
39
+	 * direction list is sorted
40
+	 */
41
+	protected static string $_event_query_sort;
42
+
43
+	/**
44
+	 * list of params used to build the query's various clauses
45
+	 */
46
+	protected static array $_query_params = [];
47
+
48
+
49
+	/**
50
+	 * @return void
51
+	 */
52
+	public static function add_query_filters()
53
+	{
54
+		// add query filters
55
+		add_action('pre_get_posts', ['EEH_Event_Query', 'filter_query_parts']);
56
+	}
57
+
58
+
59
+	/**
60
+	 * @param WP_Query $WP_Query
61
+	 * @return bool
62
+	 * @noinspection PhpUnnecessaryBoolCastInspection
63
+	 */
64
+	public static function apply_query_filters(WP_Query $WP_Query): bool
65
+	{
66
+		return (
67
+				isset($WP_Query->query['post_type'])
68
+				&& $WP_Query->query['post_type'] === 'espresso_events'
69
+			)
70
+			|| (bool) apply_filters('FHEE__EEH_Event_Query__apply_query_filters', false);
71
+	}
72
+
73
+
74
+	/**
75
+	 * @param WP_Query $WP_Query
76
+	 */
77
+	public static function filter_query_parts(WP_Query $WP_Query)
78
+	{
79
+		// ONLY add our filters if this isn't the main wp_query,
80
+		// because if this is the main wp_query we already have
81
+		// our cpt strategies take care of adding things in.
82
+		if (! $WP_Query->is_main_query()) {
83
+			// build event list query
84
+			add_filter('posts_fields', ['EEH_Event_Query', 'posts_fields'], 10, 2);
85
+			add_filter('posts_join', ['EEH_Event_Query', 'posts_join'], 10, 2);
86
+			add_filter('posts_where', ['EEH_Event_Query', 'posts_where'], 10, 2);
87
+			add_filter('posts_orderby', ['EEH_Event_Query', 'posts_orderby'], 10, 2);
88
+			add_filter('posts_clauses_request', ['EEH_Event_Query', 'posts_clauses'], 10, 2);
89
+		}
90
+	}
91
+
92
+
93
+	/**
94
+	 * @param string|null  $month
95
+	 * @param string|null  $category
96
+	 * @param bool         $show_expired
97
+	 * @param array|string $orderby
98
+	 * @param string|null  $sort
99
+	 */
100
+	public static function set_query_params(
101
+		?string $month = '',
102
+		?string $category = '',
103
+		bool $show_expired = false,
104
+		$orderby = 'start_date',
105
+		?string $sort = 'ASC'
106
+	) {
107
+		self::$_query_params                        = [];
108
+		EEH_Event_Query::$_event_query_month        = EEH_Event_Query::_display_month($month);
109
+		EEH_Event_Query::$_event_query_category     = EEH_Event_Query::_event_category_slug($category);
110
+		EEH_Event_Query::$_event_query_show_expired = EEH_Event_Query::_show_expired($show_expired);
111
+		EEH_Event_Query::$_event_query_orderby      = EEH_Event_Query::_orderby($orderby);
112
+		EEH_Event_Query::$_event_query_sort         = EEH_Event_Query::_sort($sort);
113
+	}
114
+
115
+
116
+	/**
117
+	 * what month should the event list display events for?
118
+	 *
119
+	 * @param string|null $month
120
+	 * @return string
121
+	 */
122
+	private static function _display_month(?string $month = ''): string
123
+	{
124
+		return self::getRequest()->getRequestParam('event_query_month', $month);
125
+	}
126
+
127
+
128
+	/**
129
+	 * @param string|null $category
130
+	 * @return string
131
+	 */
132
+	private static function _event_category_slug(?string $category = ''): string
133
+	{
134
+		return self::getRequest()->getRequestParam('event_query_category', $category);
135
+	}
136
+
137
+
138
+	/**
139
+	 * @param bool $show_expired
140
+	 * @return bool
141
+	 */
142
+	private static function _show_expired(bool $show_expired = false): bool
143
+	{
144
+		// override default expired option if set via filter
145
+		return self::getRequest()->getRequestParam('event_query_show_expired', $show_expired, 'bool');
146
+	}
147
+
148
+
149
+	/**
150
+	 * @param array|string|null $orderby
151
+	 * @return array
152
+	 */
153
+	private static function _orderby($orderby = 'start_date'): array
154
+	{
155
+		$event_query_orderby = self::getRequest()->getRequestParam(
156
+			'event_query_orderby',
157
+			(array) $orderby,
158
+			DataType::STRING,
159
+			true
160
+		);
161
+		$event_query_orderby = is_array($event_query_orderby)
162
+			? $event_query_orderby
163
+			: explode(',', $event_query_orderby);
164
+		$event_query_orderby = array_map('trim', $event_query_orderby);
165
+		return array_map('sanitize_text_field', $event_query_orderby);
166
+	}
167
+
168
+
169
+	/**
170
+	 * @param string|null $sort
171
+	 * @return string
172
+	 */
173
+	private static function _sort(?string $sort = 'ASC'): string
174
+	{
175
+		$sort = self::getRequest()->getRequestParam('event_query_sort', $sort);
176
+		return in_array($sort, ['ASC', 'asc', 'DESC', 'desc'], true)
177
+			? strtoupper($sort)
178
+			: 'ASC';
179
+	}
180
+
181
+
182
+	/**
183
+	 * Filters the clauses for the WP_Query object
184
+	 *
185
+	 * @param array    $clauses array of clauses
186
+	 * @param WP_Query $wp_query
187
+	 * @return array   array of clauses
188
+	 */
189
+	public static function posts_clauses(array $clauses, WP_Query $wp_query): array
190
+	{
191
+		if (EEH_Event_Query::apply_query_filters($wp_query)) {
192
+			global $wpdb;
193
+			$clauses['groupby'] = $wpdb->posts . '.ID ';
194
+		}
195
+		return $clauses;
196
+	}
197
+
198
+
199
+	/**
200
+	 * @param string   $SQL
201
+	 * @param WP_Query $wp_query
202
+	 * @return string
203
+	 * @throws EE_Error
204
+	 * @throws ReflectionException
205
+	 */
206
+	public static function posts_fields(string $SQL, WP_Query $wp_query): string
207
+	{
208
+		if (EEH_Event_Query::apply_query_filters($wp_query)) {
209
+			// adds something like ", wp_esp_datetime.* " to WP Query SELECT statement
210
+			$SQL .= EEH_Event_Query::posts_fields_sql_for_orderby(EEH_Event_Query::$_event_query_orderby);
211
+		}
212
+		return $SQL;
213
+	}
214
+
215
+
216
+	/**
217
+	 * @param array $orderby_params
218
+	 * @return string
219
+	 * @throws EE_Error
220
+	 * @throws ReflectionException
221
+	 */
222
+	public static function posts_fields_sql_for_orderby(array $orderby_params = []): string
223
+	{
224
+		$SQL = ', MIN( ' . EEM_Datetime::instance()->table() . '.DTT_EVT_start ) as event_start_date ';
225
+		foreach ($orderby_params as $orderby) {
226
+			switch ($orderby) {
227
+				case 'ticket_start':
228
+					$SQL .= ', ' . EEM_Ticket::instance()->table() . '.TKT_start_date';
229
+					break;
230
+				case 'ticket_end':
231
+					$SQL .= ', ' . EEM_Ticket::instance()->table() . '.TKT_end_date';
232
+					break;
233
+				case 'venue_title':
234
+					$SQL .= ', Venue.post_title AS venue_title';
235
+					break;
236
+				case 'city':
237
+					$SQL .= ', ' . EEM_Venue::instance()->second_table() . '.VNU_city';
238
+					break;
239
+				case 'state':
240
+					$SQL .= ', ' . EEM_State::instance()->table() . '.STA_name';
241
+					break;
242
+			}
243
+		}
244
+		return $SQL;
245
+	}
246
+
247
+
248
+	/**
249
+	 * @param string   $SQL
250
+	 * @param WP_Query $wp_query
251
+	 * @return string
252
+	 * @throws EE_Error
253
+	 * @throws ReflectionException
254
+	 */
255
+	public static function posts_join(string $SQL, WP_Query $wp_query): string
256
+	{
257
+		if (EEH_Event_Query::apply_query_filters($wp_query)) {
258
+			// Category
259
+			$SQL = EEH_Event_Query::posts_join_sql_for_show_expired($SQL, EEH_Event_Query::$_event_query_show_expired);
260
+			$SQL = EEH_Event_Query::posts_join_sql_for_terms($SQL, EEH_Event_Query::$_event_query_category);
261
+			$SQL = EEH_Event_Query::posts_join_for_orderby($SQL, EEH_Event_Query::$_event_query_orderby);
262
+		}
263
+		return $SQL;
264
+	}
265
+
266
+
267
+	/**
268
+	 * @param string  $SQL
269
+	 * @param boolean $show_expired if TRUE, then displayed past events
270
+	 * @return string
271
+	 * @throws EE_Error
272
+	 * @throws ReflectionException
273
+	 */
274
+	public static function posts_join_sql_for_show_expired(string $SQL = '', bool $show_expired = false): string
275
+	{
276
+		if (! $show_expired) {
277
+			$datetime_table = EEM_Datetime::instance()->table();
278
+			// don't add if this is already in the SQL
279
+			if (strpos($SQL, "INNER JOIN $datetime_table") === false) {
280
+				$event_table = EEM_Event::instance()->table();
281
+				$event_table_pk = EEM_Event::instance()->primary_key_name();
282
+				$SQL .= " INNER JOIN $datetime_table ON ( $event_table.ID = $datetime_table.$event_table_pk ) ";
283
+			}
284
+		}
285
+		return $SQL;
286
+	}
287
+
288
+
289
+	/**
290
+	 * @param string $SQL
291
+	 * @param string $join_terms    pass TRUE or term string, doesn't really matter since this value doesn't really get
292
+	 *                              used for anything yet
293
+	 * @return string
294
+	 */
295
+	public static function posts_join_sql_for_terms(string $SQL = '', string $join_terms = ''): string
296
+	{
297
+		global $wpdb;
298
+		if (! empty($join_terms) && strpos($SQL, "LEFT JOIN $wpdb->term_relationships") === false) {
299
+			$SQL .= " LEFT JOIN $wpdb->term_relationships ON ($wpdb->posts.ID = $wpdb->term_relationships.object_id)";
300
+			$SQL .= " LEFT JOIN $wpdb->term_taxonomy ON ($wpdb->term_relationships.term_taxonomy_id = $wpdb->term_taxonomy.term_taxonomy_id)";
301
+			$SQL .= " LEFT JOIN $wpdb->terms ON ($wpdb->terms.term_id = $wpdb->term_taxonomy.term_id) ";
302
+		}
303
+		return $SQL;
304
+	}
305
+
306
+
307
+	/**
308
+	 * usage:  $SQL .= EEH_Event_Query::posts_join_for_orderby( $orderby_params );
309
+	 *
310
+	 * @param string $SQL
311
+	 * @param array  $orderby_params
312
+	 * @return string
313
+	 * @throws EE_Error
314
+	 * @throws ReflectionException
315
+	 */
316
+	public static function posts_join_for_orderby(string $SQL = '', array $orderby_params = []): string
317
+	{
318
+		foreach ($orderby_params as $orderby) {
319
+			switch ($orderby) {
320
+				case 'ticket_start':
321
+				case 'ticket_end':
322
+					$SQL .= EEH_Event_Query::_posts_join_for_datetime(
323
+						$SQL,
324
+						EEM_Datetime_Ticket::instance()->table() . '.' . EEM_Datetime::instance()->primary_key_name()
325
+					);
326
+					$SQL .= EEH_Event_Query::postsJoinForTicket($SQL);
327
+					break;
328
+				case 'venue_title':
329
+				case 'city':
330
+					$SQL .= EEH_Event_Query::_posts_join_for_event_venue($SQL);
331
+					break;
332
+				case 'state':
333
+					$SQL .= EEH_Event_Query::_posts_join_for_event_venue($SQL);
334
+					$SQL .= EEH_Event_Query::_posts_join_for_venue_state($SQL);
335
+					break;
336
+				case 'start_date':
337
+				default:
338
+					$SQL .= EEH_Event_Query::_posts_join_for_datetime($SQL, EEM_Event::instance()->table() . '.ID');
339
+					break;
340
+			}
341
+		}
342
+		return $SQL;
343
+	}
344
+
345
+
346
+	/**
347
+	 * @param string $SQL
348
+	 * @param string $join
349
+	 * @return string
350
+	 * @throws EE_Error
351
+	 * @throws ReflectionException
352
+	 */
353
+	protected static function _posts_join_for_datetime(string $SQL = '', string $join = ''): string
354
+	{
355
+		if (! empty($join)) {
356
+			$datetime_table = EEM_Datetime::instance()->table();
357
+			// don't add if this is already in the SQL
358
+			if (strpos($SQL, "INNER JOIN $datetime_table") === false) {
359
+				$event_table_pk = EEM_Event::instance()->primary_key_name();
360
+				return " INNER JOIN $datetime_table ON ( $join = $datetime_table.$event_table_pk )";
361
+			}
362
+		}
363
+		return '';
364
+	}
365
+
366
+
367
+	/**
368
+	 * @param string $SQL
369
+	 * @return string
370
+	 * @throws EE_Error
371
+	 * @throws ReflectionException
372
+	 */
373
+	protected static function _posts_join_for_event_venue(string $SQL = ''): string
374
+	{
375
+		$venue_table = EEM_Venue::instance()->table();
376
+		// don't add joins if they have already been added
377
+		if (strpos($SQL, "LEFT JOIN $venue_table") === false) {
378
+			global $wpdb;
379
+			// grab venue table PK name & event_meta table name
380
+			$VNU_ID     = EEM_Venue::instance()->primary_key_name();
381
+			$event_meta = EEM_Event::instance()->second_table();
382
+			// generate conditions for:  Event <=> Venue  JOIN clause
383
+			$event_venue_join = "Venue.ID = $event_meta.$VNU_ID";
384
+			// grab wp_posts (event), venue, and venue_meta table names
385
+			$wp_posts   = $wpdb->posts;
386
+			$venue_meta = EEM_Venue::instance()->second_table();
387
+			// generate JOIN clause for: Event <=> Event Meta
388
+			$venue_SQL = " LEFT JOIN $event_meta ON ( $wp_posts.ID = $event_meta.EVT_ID )";
389
+			// generate JOIN clause for: Event Meta <=> Venue
390
+			$venue_SQL .= " LEFT JOIN $venue_table AS Venue ON ( $event_venue_join )";
391
+			// generate JOIN clause for: Venue <=> Venue Meta
392
+			$venue_SQL .= " LEFT JOIN $venue_meta ON ( Venue.ID = $venue_meta.$VNU_ID )";
393
+			unset($venue_table, $VNU_ID, $event_meta, $venue_meta, $event_venue_join);
394
+			return $venue_SQL;
395
+		}
396
+		unset($VNU_ID, $event_meta, $event_venue_join);
397
+		return '';
398
+	}
399
+
400
+
401
+	/**
402
+	 * @param string $SQL
403
+	 * @return string
404
+	 * @throws EE_Error
405
+	 * @throws ReflectionException
406
+	 * @since 5.0.20.p
407
+	 */
408
+	protected static function postsJoinForTicket(string $SQL = ''): string
409
+	{
410
+		$ticket_table = EEM_Ticket::instance()->table();
411
+		// don't add if this is already in the SQL
412
+		if (strpos($SQL, "LEFT JOIN $ticket_table") === false) {
413
+			$datetime_table = EEM_Datetime::instance()->table();
414
+			$ticket_table_pk = EEM_Ticket::instance()->primary_key_name();
415
+			return " LEFT JOIN $ticket_table ON ( $datetime_table.$ticket_table_pk = $ticket_table.$ticket_table_pk )";
416
+		}
417
+		return '';
418
+	}
419
+
420
+
421
+
422
+	/**
423
+	 * @param string $SQL
424
+	 * @return string
425
+	 * @throws EE_Error
426
+	 * @throws ReflectionException
427
+	 */
428
+	protected static function _posts_join_for_venue_state(string $SQL = ''): string
429
+	{
430
+		$state_table = EEM_State::instance()->table();
431
+		// don't add join if it has already been added
432
+		if (strpos($SQL, "LEFT JOIN $state_table") === false) {
433
+			$state_table_pk = EEM_State::instance()->primary_key_name();
434
+			$venue_meta_table = EEM_Venue::instance()->second_table();
435
+			// like: wp_esp_venue_meta.STA_ID = wp_esp_state.STA_ID
436
+			return " LEFT JOIN $state_table ON ( $venue_meta_table.$state_table_pk = $state_table.$state_table_pk )";
437
+		}
438
+		return '';
439
+	}
440
+
441
+
442
+	/**
443
+	 * @param string   $SQL
444
+	 * @param WP_Query $wp_query
445
+	 * @return string
446
+	 * @throws EE_Error
447
+	 * @throws ReflectionException
448
+	 */
449
+	public static function posts_where(string $SQL, WP_Query $wp_query): string
450
+	{
451
+		if (EEH_Event_Query::apply_query_filters($wp_query)) {
452
+			// Show Expired ?
453
+			$SQL .= EEH_Event_Query::posts_where_sql_for_show_expired(EEH_Event_Query::$_event_query_show_expired);
454
+			// Category
455
+			$SQL .= EEH_Event_Query::posts_where_sql_for_event_category_slug(EEH_Event_Query::$_event_query_category);
456
+			// Start Date
457
+			$SQL .= EEH_Event_Query::posts_where_sql_for_event_list_month(EEH_Event_Query::$_event_query_month);
458
+			// Trashed DateTimes
459
+			$SQL .= EEH_Event_Query::posts_where_sql_for_non_trashed_datetimes();
460
+		}
461
+		return $SQL;
462
+	}
463
+
464
+
465
+	/**
466
+	 * @param boolean $show_expired if TRUE, then displayed past events
467
+	 * @return string
468
+	 * @throws EE_Error
469
+	 * @throws ReflectionException
470
+	 */
471
+	public static function posts_where_sql_for_show_expired(bool $show_expired = false): string
472
+	{
473
+		return ! $show_expired
474
+			? ' AND ' . EEM_Datetime::instance()->table() . '.DTT_EVT_end > \'' . current_time('mysql', true) . '\' '
475
+			: '';
476
+	}
477
+
478
+
479
+	/**
480
+	 * @param string|null $event_category_slug
481
+	 * @return string
482
+	 */
483
+	public static function posts_where_sql_for_event_category_slug(?string $event_category_slug = null): string
484
+	{
485
+		global $wpdb;
486
+		if (! empty($event_category_slug)) {
487
+			$event_category_slugs_array   = array_map('trim', explode(',', $event_category_slug));
488
+			$event_category_slugs_prepare = implode(', ', array_fill(0, count($event_category_slugs_array), '%s'));
489
+			return $wpdb->prepare(
490
+				" AND $wpdb->terms.slug IN ($event_category_slugs_prepare) ",
491
+				$event_category_slugs_array
492
+			);
493
+		}
494
+		return '';
495
+	}
496
+
497
+
498
+	/**
499
+	 * @param string|null $month
500
+	 * @return string
501
+	 * @throws EE_Error
502
+	 * @throws ReflectionException
503
+	 */
504
+	public static function posts_where_sql_for_event_list_month(?string $month = null): string
505
+	{
506
+		$SQL = '';
507
+		if (! empty($month)) {
508
+			$datetime_table = EEM_Datetime::instance()->table();
509
+			// event start date is LESS than the end of the month ( so nothing that doesn't start until next month )
510
+			$SQL = " AND $datetime_table.DTT_EVT_start <= '";
511
+			$SQL .= date('Y-m-t 23:59:59', EEH_DTT_Helper::first_of_month_timestamp($month)) . "'";
512
+			// event end date is GREATER than the start of the month ( so nothing that ended before this month )
513
+			$SQL .= " AND $datetime_table.DTT_EVT_end >= '";
514
+			$SQL .= date('Y-m-01 0:0:00', EEH_DTT_Helper::first_of_month_timestamp($month)) . "' ";
515
+		}
516
+		return $SQL;
517
+	}
518
+
519
+
520
+	/**
521
+	 * @return string
522
+	 * @throws EE_Error
523
+	 * @throws ReflectionException
524
+	 */
525
+	public static function posts_where_sql_for_non_trashed_datetimes(): string
526
+	{
527
+		return ' AND ' . EEM_Datetime::instance()->table() . '.DTT_deleted = 0';
528
+	}
529
+
530
+
531
+	/**
532
+	 * @param string   $SQL
533
+	 * @param WP_Query $wp_query
534
+	 * @return string
535
+	 * @throws EE_Error
536
+	 * @throws ReflectionException
537
+	 */
538
+	public static function posts_orderby(string $SQL, WP_Query $wp_query): string
539
+	{
540
+		if (EEH_Event_Query::apply_query_filters($wp_query)) {
541
+			$SQL = EEH_Event_Query::posts_orderby_sql(
542
+				EEH_Event_Query::$_event_query_orderby,
543
+				EEH_Event_Query::$_event_query_sort
544
+			);
545
+		}
546
+		return $SQL;
547
+	}
548
+
549
+
550
+	/**
551
+	 *    posts_orderby_sql
552
+	 *    possible parameters:
553
+	 *    ID
554
+	 *    start_date
555
+	 *    end_date
556
+	 *    event_name
557
+	 *    category_slug
558
+	 *    ticket_start
559
+	 *    ticket_end
560
+	 *    venue_title
561
+	 *    city
562
+	 *    state
563
+	 *    **IMPORTANT**
564
+	 *    make sure to also send the $orderby_params array to the posts_join_for_orderby() method
565
+	 *    or else some of the table references below will result in MySQL errors
566
+	 *
567
+	 * @param array  $orderby_params
568
+	 * @param string $sort
569
+	 * @return string
570
+	 * @throws EE_Error
571
+	 * @throws ReflectionException
572
+	 */
573
+	public static function posts_orderby_sql(array $orderby_params = [], string $sort = 'ASC'): string
574
+	{
575
+		global $wpdb;
576
+		$SQL     = '';
577
+		$counter = 0;
578
+		$sort    = in_array($sort, ['ASC', 'asc', 'DESC', 'desc'], true)
579
+			? strtoupper($sort)
580
+			: 'ASC';
581
+		// make sure 'orderby' is set in query params
582
+		if (! isset(self::$_query_params['orderby'])) {
583
+			self::$_query_params['orderby'] = [];
584
+		}
585
+		// loop thru $orderby_params (type cast as array)
586
+		foreach ($orderby_params as $orderby) {
587
+			// check if we have already added this param
588
+			if (isset(self::$_query_params['orderby'][ $orderby ])) {
589
+				// if so then remove from the $orderby_params so that the count() method below is accurate
590
+				unset($orderby_params[ $orderby ]);
591
+				// then bump ahead to the next param
592
+				continue;
593
+			}
594
+			// this will add a comma depending on whether this is the first or last param
595
+			$glue = $counter === 0 || $counter === count($orderby_params) ? ' ' : ', ';
596
+			// ok what's we dealing with?
597
+			switch ($orderby) {
598
+				case 'id':
599
+				case 'ID':
600
+					$SQL .= $glue . $wpdb->posts . '.ID ' . $sort;
601
+					break;
602
+				case 'end_date':
603
+					$SQL .= $glue . EEM_Datetime::instance()->table() . '.DTT_EVT_end ' . $sort;
604
+					break;
605
+				case 'event_name':
606
+					$SQL .= $glue . $wpdb->posts . '.post_title ' . $sort;
607
+					break;
608
+				case 'category_slug':
609
+					$SQL .= $glue . $wpdb->terms . '.slug ' . $sort;
610
+					break;
611
+				case 'ticket_start':
612
+					$SQL .= $glue . EEM_Ticket::instance()->table() . '.TKT_start_date ' . $sort;
613
+					break;
614
+				case 'ticket_end':
615
+					$SQL .= $glue . EEM_Ticket::instance()->table() . '.TKT_end_date ' . $sort;
616
+					break;
617
+				case 'venue_title':
618
+					$SQL .= $glue . 'venue_title ' . $sort;
619
+					break;
620
+				case 'city':
621
+					$SQL .= $glue . EEM_Venue::instance()->second_table() . '.VNU_city ' . $sort;
622
+					break;
623
+				case 'state':
624
+					$SQL .= $glue . EEM_State::instance()->table() . '.STA_name ' . $sort;
625
+					break;
626
+				case 'start_date':
627
+				default:
628
+					$SQL .= $glue . ' event_start_date ' . $sort;
629
+					break;
630
+			}
631
+			// add to array of orderby params that have been added
632
+			self::$_query_params['orderby'][ $orderby ] = true;
633
+			$counter++;
634
+		}
635
+		return $SQL;
636
+	}
637
+
638
+
639
+	/**
640
+	 * @return RequestInterface
641
+	 * @since   4.10.14.p
642
+	 */
643
+	private static function getRequest(): RequestInterface
644
+	{
645
+		return LoaderFactory::getLoader()->getShared(RequestInterface::class);
646
+	}
647 647
 }
Please login to merge, or discard this patch.
Spacing   +32 added lines, -32 removed lines patch added patch discarded remove patch
@@ -79,7 +79,7 @@  discard block
 block discarded – undo
79 79
         // ONLY add our filters if this isn't the main wp_query,
80 80
         // because if this is the main wp_query we already have
81 81
         // our cpt strategies take care of adding things in.
82
-        if (! $WP_Query->is_main_query()) {
82
+        if ( ! $WP_Query->is_main_query()) {
83 83
             // build event list query
84 84
             add_filter('posts_fields', ['EEH_Event_Query', 'posts_fields'], 10, 2);
85 85
             add_filter('posts_join', ['EEH_Event_Query', 'posts_join'], 10, 2);
@@ -190,7 +190,7 @@  discard block
 block discarded – undo
190 190
     {
191 191
         if (EEH_Event_Query::apply_query_filters($wp_query)) {
192 192
             global $wpdb;
193
-            $clauses['groupby'] = $wpdb->posts . '.ID ';
193
+            $clauses['groupby'] = $wpdb->posts.'.ID ';
194 194
         }
195 195
         return $clauses;
196 196
     }
@@ -221,23 +221,23 @@  discard block
 block discarded – undo
221 221
      */
222 222
     public static function posts_fields_sql_for_orderby(array $orderby_params = []): string
223 223
     {
224
-        $SQL = ', MIN( ' . EEM_Datetime::instance()->table() . '.DTT_EVT_start ) as event_start_date ';
224
+        $SQL = ', MIN( '.EEM_Datetime::instance()->table().'.DTT_EVT_start ) as event_start_date ';
225 225
         foreach ($orderby_params as $orderby) {
226 226
             switch ($orderby) {
227 227
                 case 'ticket_start':
228
-                    $SQL .= ', ' . EEM_Ticket::instance()->table() . '.TKT_start_date';
228
+                    $SQL .= ', '.EEM_Ticket::instance()->table().'.TKT_start_date';
229 229
                     break;
230 230
                 case 'ticket_end':
231
-                    $SQL .= ', ' . EEM_Ticket::instance()->table() . '.TKT_end_date';
231
+                    $SQL .= ', '.EEM_Ticket::instance()->table().'.TKT_end_date';
232 232
                     break;
233 233
                 case 'venue_title':
234 234
                     $SQL .= ', Venue.post_title AS venue_title';
235 235
                     break;
236 236
                 case 'city':
237
-                    $SQL .= ', ' . EEM_Venue::instance()->second_table() . '.VNU_city';
237
+                    $SQL .= ', '.EEM_Venue::instance()->second_table().'.VNU_city';
238 238
                     break;
239 239
                 case 'state':
240
-                    $SQL .= ', ' . EEM_State::instance()->table() . '.STA_name';
240
+                    $SQL .= ', '.EEM_State::instance()->table().'.STA_name';
241 241
                     break;
242 242
             }
243 243
         }
@@ -273,7 +273,7 @@  discard block
 block discarded – undo
273 273
      */
274 274
     public static function posts_join_sql_for_show_expired(string $SQL = '', bool $show_expired = false): string
275 275
     {
276
-        if (! $show_expired) {
276
+        if ( ! $show_expired) {
277 277
             $datetime_table = EEM_Datetime::instance()->table();
278 278
             // don't add if this is already in the SQL
279 279
             if (strpos($SQL, "INNER JOIN $datetime_table") === false) {
@@ -295,7 +295,7 @@  discard block
 block discarded – undo
295 295
     public static function posts_join_sql_for_terms(string $SQL = '', string $join_terms = ''): string
296 296
     {
297 297
         global $wpdb;
298
-        if (! empty($join_terms) && strpos($SQL, "LEFT JOIN $wpdb->term_relationships") === false) {
298
+        if ( ! empty($join_terms) && strpos($SQL, "LEFT JOIN $wpdb->term_relationships") === false) {
299 299
             $SQL .= " LEFT JOIN $wpdb->term_relationships ON ($wpdb->posts.ID = $wpdb->term_relationships.object_id)";
300 300
             $SQL .= " LEFT JOIN $wpdb->term_taxonomy ON ($wpdb->term_relationships.term_taxonomy_id = $wpdb->term_taxonomy.term_taxonomy_id)";
301 301
             $SQL .= " LEFT JOIN $wpdb->terms ON ($wpdb->terms.term_id = $wpdb->term_taxonomy.term_id) ";
@@ -321,7 +321,7 @@  discard block
 block discarded – undo
321 321
                 case 'ticket_end':
322 322
                     $SQL .= EEH_Event_Query::_posts_join_for_datetime(
323 323
                         $SQL,
324
-                        EEM_Datetime_Ticket::instance()->table() . '.' . EEM_Datetime::instance()->primary_key_name()
324
+                        EEM_Datetime_Ticket::instance()->table().'.'.EEM_Datetime::instance()->primary_key_name()
325 325
                     );
326 326
                     $SQL .= EEH_Event_Query::postsJoinForTicket($SQL);
327 327
                     break;
@@ -335,7 +335,7 @@  discard block
 block discarded – undo
335 335
                     break;
336 336
                 case 'start_date':
337 337
                 default:
338
-                    $SQL .= EEH_Event_Query::_posts_join_for_datetime($SQL, EEM_Event::instance()->table() . '.ID');
338
+                    $SQL .= EEH_Event_Query::_posts_join_for_datetime($SQL, EEM_Event::instance()->table().'.ID');
339 339
                     break;
340 340
             }
341 341
         }
@@ -352,7 +352,7 @@  discard block
 block discarded – undo
352 352
      */
353 353
     protected static function _posts_join_for_datetime(string $SQL = '', string $join = ''): string
354 354
     {
355
-        if (! empty($join)) {
355
+        if ( ! empty($join)) {
356 356
             $datetime_table = EEM_Datetime::instance()->table();
357 357
             // don't add if this is already in the SQL
358 358
             if (strpos($SQL, "INNER JOIN $datetime_table") === false) {
@@ -471,7 +471,7 @@  discard block
 block discarded – undo
471 471
     public static function posts_where_sql_for_show_expired(bool $show_expired = false): string
472 472
     {
473 473
         return ! $show_expired
474
-            ? ' AND ' . EEM_Datetime::instance()->table() . '.DTT_EVT_end > \'' . current_time('mysql', true) . '\' '
474
+            ? ' AND '.EEM_Datetime::instance()->table().'.DTT_EVT_end > \''.current_time('mysql', true).'\' '
475 475
             : '';
476 476
     }
477 477
 
@@ -483,7 +483,7 @@  discard block
 block discarded – undo
483 483
     public static function posts_where_sql_for_event_category_slug(?string $event_category_slug = null): string
484 484
     {
485 485
         global $wpdb;
486
-        if (! empty($event_category_slug)) {
486
+        if ( ! empty($event_category_slug)) {
487 487
             $event_category_slugs_array   = array_map('trim', explode(',', $event_category_slug));
488 488
             $event_category_slugs_prepare = implode(', ', array_fill(0, count($event_category_slugs_array), '%s'));
489 489
             return $wpdb->prepare(
@@ -504,14 +504,14 @@  discard block
 block discarded – undo
504 504
     public static function posts_where_sql_for_event_list_month(?string $month = null): string
505 505
     {
506 506
         $SQL = '';
507
-        if (! empty($month)) {
507
+        if ( ! empty($month)) {
508 508
             $datetime_table = EEM_Datetime::instance()->table();
509 509
             // event start date is LESS than the end of the month ( so nothing that doesn't start until next month )
510 510
             $SQL = " AND $datetime_table.DTT_EVT_start <= '";
511
-            $SQL .= date('Y-m-t 23:59:59', EEH_DTT_Helper::first_of_month_timestamp($month)) . "'";
511
+            $SQL .= date('Y-m-t 23:59:59', EEH_DTT_Helper::first_of_month_timestamp($month))."'";
512 512
             // event end date is GREATER than the start of the month ( so nothing that ended before this month )
513 513
             $SQL .= " AND $datetime_table.DTT_EVT_end >= '";
514
-            $SQL .= date('Y-m-01 0:0:00', EEH_DTT_Helper::first_of_month_timestamp($month)) . "' ";
514
+            $SQL .= date('Y-m-01 0:0:00', EEH_DTT_Helper::first_of_month_timestamp($month))."' ";
515 515
         }
516 516
         return $SQL;
517 517
     }
@@ -524,7 +524,7 @@  discard block
 block discarded – undo
524 524
      */
525 525
     public static function posts_where_sql_for_non_trashed_datetimes(): string
526 526
     {
527
-        return ' AND ' . EEM_Datetime::instance()->table() . '.DTT_deleted = 0';
527
+        return ' AND '.EEM_Datetime::instance()->table().'.DTT_deleted = 0';
528 528
     }
529 529
 
530 530
 
@@ -579,15 +579,15 @@  discard block
 block discarded – undo
579 579
             ? strtoupper($sort)
580 580
             : 'ASC';
581 581
         // make sure 'orderby' is set in query params
582
-        if (! isset(self::$_query_params['orderby'])) {
582
+        if ( ! isset(self::$_query_params['orderby'])) {
583 583
             self::$_query_params['orderby'] = [];
584 584
         }
585 585
         // loop thru $orderby_params (type cast as array)
586 586
         foreach ($orderby_params as $orderby) {
587 587
             // check if we have already added this param
588
-            if (isset(self::$_query_params['orderby'][ $orderby ])) {
588
+            if (isset(self::$_query_params['orderby'][$orderby])) {
589 589
                 // if so then remove from the $orderby_params so that the count() method below is accurate
590
-                unset($orderby_params[ $orderby ]);
590
+                unset($orderby_params[$orderby]);
591 591
                 // then bump ahead to the next param
592 592
                 continue;
593 593
             }
@@ -597,39 +597,39 @@  discard block
 block discarded – undo
597 597
             switch ($orderby) {
598 598
                 case 'id':
599 599
                 case 'ID':
600
-                    $SQL .= $glue . $wpdb->posts . '.ID ' . $sort;
600
+                    $SQL .= $glue.$wpdb->posts.'.ID '.$sort;
601 601
                     break;
602 602
                 case 'end_date':
603
-                    $SQL .= $glue . EEM_Datetime::instance()->table() . '.DTT_EVT_end ' . $sort;
603
+                    $SQL .= $glue.EEM_Datetime::instance()->table().'.DTT_EVT_end '.$sort;
604 604
                     break;
605 605
                 case 'event_name':
606
-                    $SQL .= $glue . $wpdb->posts . '.post_title ' . $sort;
606
+                    $SQL .= $glue.$wpdb->posts.'.post_title '.$sort;
607 607
                     break;
608 608
                 case 'category_slug':
609
-                    $SQL .= $glue . $wpdb->terms . '.slug ' . $sort;
609
+                    $SQL .= $glue.$wpdb->terms.'.slug '.$sort;
610 610
                     break;
611 611
                 case 'ticket_start':
612
-                    $SQL .= $glue . EEM_Ticket::instance()->table() . '.TKT_start_date ' . $sort;
612
+                    $SQL .= $glue.EEM_Ticket::instance()->table().'.TKT_start_date '.$sort;
613 613
                     break;
614 614
                 case 'ticket_end':
615
-                    $SQL .= $glue . EEM_Ticket::instance()->table() . '.TKT_end_date ' . $sort;
615
+                    $SQL .= $glue.EEM_Ticket::instance()->table().'.TKT_end_date '.$sort;
616 616
                     break;
617 617
                 case 'venue_title':
618
-                    $SQL .= $glue . 'venue_title ' . $sort;
618
+                    $SQL .= $glue.'venue_title '.$sort;
619 619
                     break;
620 620
                 case 'city':
621
-                    $SQL .= $glue . EEM_Venue::instance()->second_table() . '.VNU_city ' . $sort;
621
+                    $SQL .= $glue.EEM_Venue::instance()->second_table().'.VNU_city '.$sort;
622 622
                     break;
623 623
                 case 'state':
624
-                    $SQL .= $glue . EEM_State::instance()->table() . '.STA_name ' . $sort;
624
+                    $SQL .= $glue.EEM_State::instance()->table().'.STA_name '.$sort;
625 625
                     break;
626 626
                 case 'start_date':
627 627
                 default:
628
-                    $SQL .= $glue . ' event_start_date ' . $sort;
628
+                    $SQL .= $glue.' event_start_date '.$sort;
629 629
                     break;
630 630
             }
631 631
             // add to array of orderby params that have been added
632
-            self::$_query_params['orderby'][ $orderby ] = true;
632
+            self::$_query_params['orderby'][$orderby] = true;
633 633
             $counter++;
634 634
         }
635 635
         return $SQL;
Please login to merge, or discard this patch.