Completed
Branch dev (64e3a7)
by
unknown
13:10 queued 05:44
created
core/services/assets/AssetManager.php 2 patches
Spacing   +2 added lines, -2 removed lines patch added patch discarded remove patch
@@ -176,10 +176,10 @@
 block discarded – undo
176 176
         $version = ''
177 177
     ) {
178 178
         $dev_suffix = wp_scripts_get_suffix('dev');
179
-        $vendor_path = $this->domain->pluginUrl() . 'assets/vendor/';
179
+        $vendor_path = $this->domain->pluginUrl().'assets/vendor/';
180 180
         return $this->addJavascript(
181 181
             $handle,
182
-            "{$vendor_path}{$handle}{$dev_suffix}". Asset::EXT_JS,
182
+            "{$vendor_path}{$handle}{$dev_suffix}".Asset::EXT_JS,
183 183
             $dependencies,
184 184
             $load_in_footer,
185 185
             $version
Please login to merge, or discard this patch.
Indentation   +323 added lines, -323 removed lines patch added patch discarded remove patch
@@ -23,332 +23,332 @@
 block discarded – undo
23 23
 abstract class AssetManager implements AssetManagerInterface
24 24
 {
25 25
 
26
-    /**
27
-     * @var AssetCollection|Asset[] $assets
28
-     */
29
-    protected $assets;
30
-
31
-    /**
32
-     * @var DomainInterface
33
-     */
34
-    protected $domain;
35
-
36
-    /**
37
-     * @var Registry $registry
38
-     */
39
-    protected $registry;
40
-
41
-
42
-    /**
43
-     * AssetRegister constructor.
44
-     *
45
-     * @param DomainInterface $domain
46
-     * @param AssetCollection $assets
47
-     * @param Registry        $registry
48
-     */
49
-    public function __construct(DomainInterface $domain, AssetCollection $assets, Registry $registry)
50
-    {
51
-        $this->domain = $domain;
52
-        $this->assets = $assets;
53
-        $this->registry = $registry;
54
-        $this->registry->addAssetCollection($assets);
55
-        add_action('wp_enqueue_scripts', array($this, 'addAssets'), 2);
56
-        add_action('admin_enqueue_scripts', array($this, 'addAssets'), 2);
57
-    }
58
-
59
-
60
-    /**
61
-     * @return AssetCollection
62
-     */
63
-    public function getAssets()
64
-    {
65
-        return $this->assets;
66
-    }
67
-
68
-
69
-    /**
70
-     * @since 4.9.71.p
71
-     * @return string
72
-     */
73
-    public function assetNamespace()
74
-    {
75
-        return $this->domain->assetNamespace();
76
-    }
77
-
78
-
79
-    /**
80
-     * @param string $handle
81
-     * @param string $source
82
-     * @param array  $dependencies
83
-     * @param bool   $load_in_footer
84
-     * @param string $version
85
-     * @return JavascriptAsset
86
-     * @throws DuplicateCollectionIdentifierException
87
-     * @throws InvalidDataTypeException
88
-     * @throws InvalidEntityException
89
-     * @throws DomainException
90
-     * @since 4.9.62.p
91
-     */
92
-    public function addJavascript(
93
-        $handle,
94
-        $source,
95
-        array $dependencies = array(),
96
-        $load_in_footer = true,
97
-        $version = ''
98
-    ) {
99
-        $asset = new JavascriptAsset(
100
-            $handle,
101
-            $source,
102
-            array_unique($dependencies),
103
-            $load_in_footer,
104
-            $this->domain,
105
-            $version
106
-        );
107
-        $this->assets->add($asset, $handle);
108
-        return $asset;
109
-    }
110
-
111
-
112
-    /**
113
-     * Used to register a javascript asset where everything is dynamically derived from the given handle.
114
-     *
115
-     * @param string       $handle
116
-     * @param string|array $extra_dependencies
117
-     * @return JavascriptAsset
118
-     * @throws DuplicateCollectionIdentifierException
119
-     * @throws InvalidDataTypeException
120
-     * @throws InvalidEntityException
121
-     * @throws DomainException
122
-     */
123
-    public function addJs($handle, $extra_dependencies = [])
124
-    {
125
-        $details = $this->getAssetDetails(
126
-            Asset::TYPE_JS,
127
-            $handle,
128
-            $extra_dependencies
129
-        );
130
-        $source = $this->registry->getJsUrl($this->domain->assetNamespace(), $handle);
131
-        return $this->addJavascript(
132
-            $handle,
133
-            $source,
134
-            $details['dependencies'],
135
-            true,
136
-            $details['version']
137
-        );
138
-    }
139
-
140
-
141
-    /**
142
-     * @param string $handle
143
-     * @param array  $dependencies
144
-     * @param bool   $load_in_footer
145
-     * @param string $version
146
-     * @return JavascriptAsset
147
-     * @throws DomainException
148
-     * @throws DuplicateCollectionIdentifierException
149
-     * @throws InvalidDataTypeException
150
-     * @throws InvalidEntityException
151
-     * @since 4.9.71.p
152
-     */
153
-    public function addVendorJavascript(
154
-        $handle,
155
-        array $dependencies = array(),
156
-        $load_in_footer = true,
157
-        $version = ''
158
-    ) {
159
-        $dev_suffix = wp_scripts_get_suffix('dev');
160
-        $vendor_path = $this->domain->pluginUrl() . 'assets/vendor/';
161
-        return $this->addJavascript(
162
-            $handle,
163
-            "{$vendor_path}{$handle}{$dev_suffix}". Asset::EXT_JS,
164
-            $dependencies,
165
-            $load_in_footer,
166
-            $version
167
-        );
168
-    }
169
-
170
-
171
-    /**
172
-     * @param string $handle
173
-     * @param string $source
174
-     * @param array  $dependencies
175
-     * @param string $media
176
-     * @param string $version
177
-     * @return StylesheetAsset
178
-     * @throws DomainException
179
-     * @throws DuplicateCollectionIdentifierException
180
-     * @throws InvalidDataTypeException
181
-     * @throws InvalidEntityException
182
-     * @since 4.9.62.p
183
-     */
184
-    public function addStylesheet(
185
-        $handle,
186
-        $source,
187
-        array $dependencies = array(),
188
-        $media = 'all',
189
-        $version = ''
190
-    ) {
191
-        $asset = new StylesheetAsset(
192
-            $handle,
193
-            $source,
194
-            array_unique($dependencies),
195
-            $this->domain,
196
-            $media,
197
-            $version
198
-        );
199
-        $this->assets->add($asset, $handle);
200
-        return $asset;
201
-    }
202
-
203
-
204
-    /**
205
-     * Used to register a css asset where everything is dynamically derived from the given handle.
206
-     *
207
-     * @param string       $handle
208
-     * @param string|array $extra_dependencies
209
-     * @return StylesheetAsset
210
-     * @throws DuplicateCollectionIdentifierException
211
-     * @throws InvalidDataTypeException
212
-     * @throws InvalidEntityException
213
-     * @throws DomainException
214
-     */
215
-    public function addCss($handle, $extra_dependencies = [])
216
-    {
217
-        $details = $this->getAssetDetails(
218
-            Asset::TYPE_CSS,
219
-            $handle,
220
-            $extra_dependencies
221
-        );
222
-        return $this->addStylesheet(
223
-            $handle,
224
-            $this->registry->getCssUrl($this->domain->assetNamespace(), $handle),
225
-            $details['dependencies'],
226
-            'all',
227
-            $details['version']
228
-        );
229
-    }
230
-
231
-
232
-    /**
233
-     * @param string $handle
234
-     * @return bool
235
-     * @since 4.9.62.p
236
-     */
237
-    public function enqueueAsset($handle)
238
-    {
239
-        if ($this->assets->has($handle)) {
240
-            /** @var Asset $asset */
241
-            $asset = $this->assets->get($handle);
242
-            if ($asset instanceof BrowserAsset && $asset->isRegistered()) {
243
-                $asset->enqueueAsset();
244
-                return true;
245
-            }
246
-        }
247
-        return false;
248
-    }
249
-
250
-
251
-    /**
252
-     * @return  void
253
-     * @since   $VID:$
254
-     */
255
-    public function enqueueBrowserAssets()
256
-    {
257
-        foreach ($this->assets as $asset) {
258
-            if ($asset instanceof BrowserAsset && $asset->isRegistered()) {
259
-                $asset->enqueueAsset();
260
-            }
261
-        }
262
-    }
263
-
264
-
265
-    /**
266
-     * @param string $asset_type
267
-     * @param string $handle
268
-     * @param array  $extra_dependencies
269
-     * @return array
270
-     * @since 4.10.2.p
271
-     */
272
-    private function getAssetDetails($asset_type, $handle, $extra_dependencies = [])
273
-    {
274
-        $getAssetDetails = '';
275
-        switch ($asset_type) {
276
-            case Asset::TYPE_JS :
277
-                $getAssetDetails = 'getJsAssetDetails';
278
-                break;
279
-            case Asset::TYPE_CSS :
280
-                $getAssetDetails = 'getCssAssetDetails';
281
-                break;
282
-        }
283
-        if ($getAssetDetails === '') {
284
-            return ['dependencies' => [], 'version' => ''];
285
-        }
286
-        $details = $this->registry->$getAssetDetails(
287
-            $this->domain->assetNamespace(),
288
-            $handle
289
-        );
290
-        $details['dependencies'] = isset($details['dependencies'])
291
-            ? $details['dependencies']
292
-            : [];
293
-        $details['version'] = isset($details['version'])
294
-            ? $details['version']
295
-            : '';
296
-        $details['dependencies'] = ! empty($extra_dependencies)
297
-            ? array_merge($details['dependencies'], (array) $extra_dependencies)
298
-            : $details['dependencies'];
299
-        return $details;
300
-
301
-    }
302
-
303
-
304
-    /**
305
-     * @param string $handle
306
-     * @return bool
307
-     * @throws DomainException
308
-     */
309
-    public function verifyAssetIsRegistered($handle)
310
-    {
311
-        if (wp_script_is($handle, 'registered')) {
312
-            return true;
313
-        }
314
-        if (WP_DEBUG) {
315
-            throw new DomainException(
316
-                sprintf(
317
-                    esc_html__(
318
-                        'The "%1$s" script is not registered when it should be!%2$s
26
+	/**
27
+	 * @var AssetCollection|Asset[] $assets
28
+	 */
29
+	protected $assets;
30
+
31
+	/**
32
+	 * @var DomainInterface
33
+	 */
34
+	protected $domain;
35
+
36
+	/**
37
+	 * @var Registry $registry
38
+	 */
39
+	protected $registry;
40
+
41
+
42
+	/**
43
+	 * AssetRegister constructor.
44
+	 *
45
+	 * @param DomainInterface $domain
46
+	 * @param AssetCollection $assets
47
+	 * @param Registry        $registry
48
+	 */
49
+	public function __construct(DomainInterface $domain, AssetCollection $assets, Registry $registry)
50
+	{
51
+		$this->domain = $domain;
52
+		$this->assets = $assets;
53
+		$this->registry = $registry;
54
+		$this->registry->addAssetCollection($assets);
55
+		add_action('wp_enqueue_scripts', array($this, 'addAssets'), 2);
56
+		add_action('admin_enqueue_scripts', array($this, 'addAssets'), 2);
57
+	}
58
+
59
+
60
+	/**
61
+	 * @return AssetCollection
62
+	 */
63
+	public function getAssets()
64
+	{
65
+		return $this->assets;
66
+	}
67
+
68
+
69
+	/**
70
+	 * @since 4.9.71.p
71
+	 * @return string
72
+	 */
73
+	public function assetNamespace()
74
+	{
75
+		return $this->domain->assetNamespace();
76
+	}
77
+
78
+
79
+	/**
80
+	 * @param string $handle
81
+	 * @param string $source
82
+	 * @param array  $dependencies
83
+	 * @param bool   $load_in_footer
84
+	 * @param string $version
85
+	 * @return JavascriptAsset
86
+	 * @throws DuplicateCollectionIdentifierException
87
+	 * @throws InvalidDataTypeException
88
+	 * @throws InvalidEntityException
89
+	 * @throws DomainException
90
+	 * @since 4.9.62.p
91
+	 */
92
+	public function addJavascript(
93
+		$handle,
94
+		$source,
95
+		array $dependencies = array(),
96
+		$load_in_footer = true,
97
+		$version = ''
98
+	) {
99
+		$asset = new JavascriptAsset(
100
+			$handle,
101
+			$source,
102
+			array_unique($dependencies),
103
+			$load_in_footer,
104
+			$this->domain,
105
+			$version
106
+		);
107
+		$this->assets->add($asset, $handle);
108
+		return $asset;
109
+	}
110
+
111
+
112
+	/**
113
+	 * Used to register a javascript asset where everything is dynamically derived from the given handle.
114
+	 *
115
+	 * @param string       $handle
116
+	 * @param string|array $extra_dependencies
117
+	 * @return JavascriptAsset
118
+	 * @throws DuplicateCollectionIdentifierException
119
+	 * @throws InvalidDataTypeException
120
+	 * @throws InvalidEntityException
121
+	 * @throws DomainException
122
+	 */
123
+	public function addJs($handle, $extra_dependencies = [])
124
+	{
125
+		$details = $this->getAssetDetails(
126
+			Asset::TYPE_JS,
127
+			$handle,
128
+			$extra_dependencies
129
+		);
130
+		$source = $this->registry->getJsUrl($this->domain->assetNamespace(), $handle);
131
+		return $this->addJavascript(
132
+			$handle,
133
+			$source,
134
+			$details['dependencies'],
135
+			true,
136
+			$details['version']
137
+		);
138
+	}
139
+
140
+
141
+	/**
142
+	 * @param string $handle
143
+	 * @param array  $dependencies
144
+	 * @param bool   $load_in_footer
145
+	 * @param string $version
146
+	 * @return JavascriptAsset
147
+	 * @throws DomainException
148
+	 * @throws DuplicateCollectionIdentifierException
149
+	 * @throws InvalidDataTypeException
150
+	 * @throws InvalidEntityException
151
+	 * @since 4.9.71.p
152
+	 */
153
+	public function addVendorJavascript(
154
+		$handle,
155
+		array $dependencies = array(),
156
+		$load_in_footer = true,
157
+		$version = ''
158
+	) {
159
+		$dev_suffix = wp_scripts_get_suffix('dev');
160
+		$vendor_path = $this->domain->pluginUrl() . 'assets/vendor/';
161
+		return $this->addJavascript(
162
+			$handle,
163
+			"{$vendor_path}{$handle}{$dev_suffix}". Asset::EXT_JS,
164
+			$dependencies,
165
+			$load_in_footer,
166
+			$version
167
+		);
168
+	}
169
+
170
+
171
+	/**
172
+	 * @param string $handle
173
+	 * @param string $source
174
+	 * @param array  $dependencies
175
+	 * @param string $media
176
+	 * @param string $version
177
+	 * @return StylesheetAsset
178
+	 * @throws DomainException
179
+	 * @throws DuplicateCollectionIdentifierException
180
+	 * @throws InvalidDataTypeException
181
+	 * @throws InvalidEntityException
182
+	 * @since 4.9.62.p
183
+	 */
184
+	public function addStylesheet(
185
+		$handle,
186
+		$source,
187
+		array $dependencies = array(),
188
+		$media = 'all',
189
+		$version = ''
190
+	) {
191
+		$asset = new StylesheetAsset(
192
+			$handle,
193
+			$source,
194
+			array_unique($dependencies),
195
+			$this->domain,
196
+			$media,
197
+			$version
198
+		);
199
+		$this->assets->add($asset, $handle);
200
+		return $asset;
201
+	}
202
+
203
+
204
+	/**
205
+	 * Used to register a css asset where everything is dynamically derived from the given handle.
206
+	 *
207
+	 * @param string       $handle
208
+	 * @param string|array $extra_dependencies
209
+	 * @return StylesheetAsset
210
+	 * @throws DuplicateCollectionIdentifierException
211
+	 * @throws InvalidDataTypeException
212
+	 * @throws InvalidEntityException
213
+	 * @throws DomainException
214
+	 */
215
+	public function addCss($handle, $extra_dependencies = [])
216
+	{
217
+		$details = $this->getAssetDetails(
218
+			Asset::TYPE_CSS,
219
+			$handle,
220
+			$extra_dependencies
221
+		);
222
+		return $this->addStylesheet(
223
+			$handle,
224
+			$this->registry->getCssUrl($this->domain->assetNamespace(), $handle),
225
+			$details['dependencies'],
226
+			'all',
227
+			$details['version']
228
+		);
229
+	}
230
+
231
+
232
+	/**
233
+	 * @param string $handle
234
+	 * @return bool
235
+	 * @since 4.9.62.p
236
+	 */
237
+	public function enqueueAsset($handle)
238
+	{
239
+		if ($this->assets->has($handle)) {
240
+			/** @var Asset $asset */
241
+			$asset = $this->assets->get($handle);
242
+			if ($asset instanceof BrowserAsset && $asset->isRegistered()) {
243
+				$asset->enqueueAsset();
244
+				return true;
245
+			}
246
+		}
247
+		return false;
248
+	}
249
+
250
+
251
+	/**
252
+	 * @return  void
253
+	 * @since   $VID:$
254
+	 */
255
+	public function enqueueBrowserAssets()
256
+	{
257
+		foreach ($this->assets as $asset) {
258
+			if ($asset instanceof BrowserAsset && $asset->isRegistered()) {
259
+				$asset->enqueueAsset();
260
+			}
261
+		}
262
+	}
263
+
264
+
265
+	/**
266
+	 * @param string $asset_type
267
+	 * @param string $handle
268
+	 * @param array  $extra_dependencies
269
+	 * @return array
270
+	 * @since 4.10.2.p
271
+	 */
272
+	private function getAssetDetails($asset_type, $handle, $extra_dependencies = [])
273
+	{
274
+		$getAssetDetails = '';
275
+		switch ($asset_type) {
276
+			case Asset::TYPE_JS :
277
+				$getAssetDetails = 'getJsAssetDetails';
278
+				break;
279
+			case Asset::TYPE_CSS :
280
+				$getAssetDetails = 'getCssAssetDetails';
281
+				break;
282
+		}
283
+		if ($getAssetDetails === '') {
284
+			return ['dependencies' => [], 'version' => ''];
285
+		}
286
+		$details = $this->registry->$getAssetDetails(
287
+			$this->domain->assetNamespace(),
288
+			$handle
289
+		);
290
+		$details['dependencies'] = isset($details['dependencies'])
291
+			? $details['dependencies']
292
+			: [];
293
+		$details['version'] = isset($details['version'])
294
+			? $details['version']
295
+			: '';
296
+		$details['dependencies'] = ! empty($extra_dependencies)
297
+			? array_merge($details['dependencies'], (array) $extra_dependencies)
298
+			: $details['dependencies'];
299
+		return $details;
300
+
301
+	}
302
+
303
+
304
+	/**
305
+	 * @param string $handle
306
+	 * @return bool
307
+	 * @throws DomainException
308
+	 */
309
+	public function verifyAssetIsRegistered($handle)
310
+	{
311
+		if (wp_script_is($handle, 'registered')) {
312
+			return true;
313
+		}
314
+		if (WP_DEBUG) {
315
+			throw new DomainException(
316
+				sprintf(
317
+					esc_html__(
318
+						'The "%1$s" script is not registered when it should be!%2$s
319 319
                         Are you running the Barista plugin for development purposes? 
320 320
                         If so, then you need to build the appropriate assets for this domain.%2$s
321 321
                         If you are seeing this error on a live website, then you should not have 
322 322
                         the WP_DEBUG constant in your wp-config.php file set to "true". 
323 323
                         Please contact Event Espresso support for more information.',
324
-                        'event_espresso'
325
-                    ),
326
-                    $handle,
327
-                    '<br />'
328
-                )
329
-            );
330
-        }
331
-        return false;
332
-    }
333
-
334
-
335
-    /**************** deprecated ****************/
336
-
337
-
338
-    /**
339
-     * @return void
340
-     * @deprecated $VID:$
341
-     */
342
-    public function addManifestFile()
343
-    {
344
-    }
345
-
346
-
347
-    /**
348
-     * @return void
349
-     * @deprecated $VID:$
350
-     */
351
-    public function getManifestFile()
352
-    {
353
-    }
324
+						'event_espresso'
325
+					),
326
+					$handle,
327
+					'<br />'
328
+				)
329
+			);
330
+		}
331
+		return false;
332
+	}
333
+
334
+
335
+	/**************** deprecated ****************/
336
+
337
+
338
+	/**
339
+	 * @return void
340
+	 * @deprecated $VID:$
341
+	 */
342
+	public function addManifestFile()
343
+	{
344
+	}
345
+
346
+
347
+	/**
348
+	 * @return void
349
+	 * @deprecated $VID:$
350
+	 */
351
+	public function getManifestFile()
352
+	{
353
+	}
354 354
 }
Please login to merge, or discard this patch.
core/services/shortcodes/ShortcodesManager.php 1 patch
Indentation   +206 added lines, -206 removed lines patch added patch discarded remove patch
@@ -29,210 +29,210 @@
 block discarded – undo
29 29
  */
30 30
 class ShortcodesManager
31 31
 {
32
-    /**
33
-     * @type CurrentPage
34
-     */
35
-    protected $current_page;
36
-
37
-    /**
38
-     * @var LegacyShortcodesManager $legacy_shortcodes_manager
39
-     */
40
-    private $legacy_shortcodes_manager;
41
-
42
-    /**
43
-     * @var ShortcodeInterface[] $shortcodes
44
-     */
45
-    private $shortcodes;
46
-
47
-
48
-    /**
49
-     * ShortcodesManager constructor
50
-     *
51
-     * @param LegacyShortcodesManager $legacy_shortcodes_manager
52
-     * @param CurrentPage             $current_page
53
-     */
54
-    public function __construct(LegacyShortcodesManager $legacy_shortcodes_manager, CurrentPage $current_page)
55
-    {
56
-        $this->legacy_shortcodes_manager = $legacy_shortcodes_manager;
57
-        $this->current_page              = $current_page;
58
-        // assemble a list of installed and active shortcodes
59
-        add_action(
60
-            'AHEE__EE_System__register_shortcodes_modules_and_widgets',
61
-            [$this, 'registerShortcodes'],
62
-            999
63
-        );
64
-        //  call add_shortcode() for all installed shortcodes
65
-        add_action('AHEE__EE_System__core_loaded_and_ready', [$this, 'addShortcodes']);
66
-        // check content for shortcodes the old way
67
-        add_action('parse_query', [$this->legacy_shortcodes_manager, 'initializeShortcodes'], 5);
68
-        // check content for shortcodes the NEW more efficient way
69
-        add_action('template_redirect', [$this, 'templateRedirect'], 999);
70
-    }
71
-
72
-
73
-    /**
74
-     * @return CollectionInterface|ShortcodeInterface[]
75
-     * @throws InvalidIdentifierException
76
-     * @throws InvalidInterfaceException
77
-     * @throws InvalidFilePathException
78
-     * @throws InvalidEntityException
79
-     * @throws InvalidDataTypeException
80
-     * @throws InvalidClassException
81
-     */
82
-    public function getShortcodes()
83
-    {
84
-        if (! $this->shortcodes instanceof CollectionInterface) {
85
-            $this->shortcodes = $this->loadShortcodesCollection();
86
-        }
87
-        return $this->shortcodes;
88
-    }
89
-
90
-
91
-    /**
92
-     * @return CollectionInterface|ShortcodeInterface[]
93
-     * @throws InvalidIdentifierException
94
-     * @throws InvalidInterfaceException
95
-     * @throws InvalidFilePathException
96
-     * @throws InvalidEntityException
97
-     * @throws InvalidDataTypeException
98
-     * @throws InvalidClassException
99
-     */
100
-    protected function loadShortcodesCollection()
101
-    {
102
-        $loader = new CollectionLoader(
103
-            new CollectionDetails(
104
-            // collection name
105
-                'shortcodes',
106
-                // collection interface
107
-                'EventEspresso\core\services\shortcodes\ShortcodeInterface',
108
-                // FQCNs for classes to add (all classes within that namespace will be loaded)
109
-                ['EventEspresso\core\domain\entities\shortcodes'],
110
-                // filepaths to classes to add
111
-                [],
112
-                // file mask to use if parsing folder for files to add
113
-                '',
114
-                // what to use as identifier for collection entities
115
-                // using CLASS NAME prevents duplicates (works like a singleton)
116
-                CollectionDetails::ID_CLASS_NAME
117
-            )
118
-        );
119
-        return $loader->getCollection();
120
-    }
121
-
122
-
123
-    /**
124
-     * @return void
125
-     * @throws DomainException
126
-     * @throws InvalidInterfaceException
127
-     * @throws InvalidIdentifierException
128
-     * @throws InvalidFilePathException
129
-     * @throws InvalidEntityException
130
-     * @throws InvalidDataTypeException
131
-     * @throws InvalidClassException
132
-     * @throws Exception
133
-     */
134
-    public function registerShortcodes()
135
-    {
136
-        try {
137
-            $this->shortcodes = apply_filters(
138
-                'FHEE__EventEspresso_core_services_shortcodes_ShortcodesManager__registerShortcodes__shortcode_collection',
139
-                $this->getShortcodes()
140
-            );
141
-            if (! $this->shortcodes instanceof CollectionInterface) {
142
-                throw new InvalidEntityException(
143
-                    $this->shortcodes,
144
-                    'CollectionInterface',
145
-                    sprintf(
146
-                        esc_html__(
147
-                            'The "FHEE__EventEspresso_core_services_shortcodes_ShortcodesManager__registerShortcodes__shortcode_collection" filter must return a Collection of EspressoShortcode objects. "%1$s" was received instead.',
148
-                            'event_espresso'
149
-                        ),
150
-                        is_object($this->shortcodes) ? get_class($this->shortcodes) : gettype($this->shortcodes)
151
-                    )
152
-                );
153
-            }
154
-            $this->legacy_shortcodes_manager->registerShortcodes();
155
-        } catch (Exception $exception) {
156
-            new ExceptionStackTraceDisplay($exception);
157
-        }
158
-    }
159
-
160
-
161
-    /**
162
-     * @return void
163
-     * @throws Exception
164
-     */
165
-    public function addShortcodes()
166
-    {
167
-        try {
168
-            // cycle thru shortcode folders
169
-            foreach ($this->shortcodes as $shortcode) {
170
-                if ($shortcode instanceof EnqueueAssetsInterface) {
171
-                    add_action('wp_enqueue_scripts', [$shortcode, 'registerScriptsAndStylesheets'], 10);
172
-                    add_action('wp_enqueue_scripts', [$shortcode, 'enqueueStylesheets'], 11);
173
-                }
174
-                // add_shortcode() if it has not already been added
175
-                if (! shortcode_exists($shortcode->getTag())) {
176
-                    add_shortcode($shortcode->getTag(), [$shortcode, 'processShortcodeCallback']);
177
-                }
178
-            }
179
-            $this->legacy_shortcodes_manager->addShortcodes();
180
-        } catch (Exception $exception) {
181
-            new ExceptionStackTraceDisplay($exception);
182
-        }
183
-    }
184
-
185
-
186
-    /**
187
-     * callback for the "template_redirect" hook point
188
-     * checks posts for EE shortcodes, and initializes them,
189
-     * then toggles filter switch that loads core default assets
190
-     *
191
-     * @return void
192
-     */
193
-    public function templateRedirect()
194
-    {
195
-        global $wp_query;
196
-        if (empty($wp_query->posts)) {
197
-            return;
198
-        }
199
-        $load_assets = false;
200
-        // array of posts displayed in current request
201
-        $posts = is_array($wp_query->posts) ? $wp_query->posts : [$wp_query->posts];
202
-        foreach ($posts as $post) {
203
-            // now check post content and excerpt for EE shortcodes
204
-            $load_assets = $this->parseContentForShortcodes($post->post_content)
205
-                ? true
206
-                : $load_assets;
207
-        }
208
-        if ($load_assets) {
209
-            $this->current_page->setEspressoPage(true);
210
-            add_filter('FHEE_load_css', '__return_true');
211
-            add_filter('FHEE_load_js', '__return_true');
212
-        }
213
-    }
214
-
215
-
216
-    /**
217
-     * checks supplied content against list of shortcodes,
218
-     * then initializes any found shortcodes, and returns true.
219
-     * returns false if no shortcodes found.
220
-     *
221
-     * @param string $content
222
-     * @return bool
223
-     */
224
-    public function parseContentForShortcodes($content)
225
-    {
226
-        if (empty($this->shortcodes)) {
227
-            return false;
228
-        }
229
-        $has_shortcode = false;
230
-        foreach ($this->shortcodes as $shortcode) {
231
-            if (has_shortcode($content, $shortcode->getTag())) {
232
-                $shortcode->initializeShortcode();
233
-                $has_shortcode = true;
234
-            }
235
-        }
236
-        return $has_shortcode;
237
-    }
32
+	/**
33
+	 * @type CurrentPage
34
+	 */
35
+	protected $current_page;
36
+
37
+	/**
38
+	 * @var LegacyShortcodesManager $legacy_shortcodes_manager
39
+	 */
40
+	private $legacy_shortcodes_manager;
41
+
42
+	/**
43
+	 * @var ShortcodeInterface[] $shortcodes
44
+	 */
45
+	private $shortcodes;
46
+
47
+
48
+	/**
49
+	 * ShortcodesManager constructor
50
+	 *
51
+	 * @param LegacyShortcodesManager $legacy_shortcodes_manager
52
+	 * @param CurrentPage             $current_page
53
+	 */
54
+	public function __construct(LegacyShortcodesManager $legacy_shortcodes_manager, CurrentPage $current_page)
55
+	{
56
+		$this->legacy_shortcodes_manager = $legacy_shortcodes_manager;
57
+		$this->current_page              = $current_page;
58
+		// assemble a list of installed and active shortcodes
59
+		add_action(
60
+			'AHEE__EE_System__register_shortcodes_modules_and_widgets',
61
+			[$this, 'registerShortcodes'],
62
+			999
63
+		);
64
+		//  call add_shortcode() for all installed shortcodes
65
+		add_action('AHEE__EE_System__core_loaded_and_ready', [$this, 'addShortcodes']);
66
+		// check content for shortcodes the old way
67
+		add_action('parse_query', [$this->legacy_shortcodes_manager, 'initializeShortcodes'], 5);
68
+		// check content for shortcodes the NEW more efficient way
69
+		add_action('template_redirect', [$this, 'templateRedirect'], 999);
70
+	}
71
+
72
+
73
+	/**
74
+	 * @return CollectionInterface|ShortcodeInterface[]
75
+	 * @throws InvalidIdentifierException
76
+	 * @throws InvalidInterfaceException
77
+	 * @throws InvalidFilePathException
78
+	 * @throws InvalidEntityException
79
+	 * @throws InvalidDataTypeException
80
+	 * @throws InvalidClassException
81
+	 */
82
+	public function getShortcodes()
83
+	{
84
+		if (! $this->shortcodes instanceof CollectionInterface) {
85
+			$this->shortcodes = $this->loadShortcodesCollection();
86
+		}
87
+		return $this->shortcodes;
88
+	}
89
+
90
+
91
+	/**
92
+	 * @return CollectionInterface|ShortcodeInterface[]
93
+	 * @throws InvalidIdentifierException
94
+	 * @throws InvalidInterfaceException
95
+	 * @throws InvalidFilePathException
96
+	 * @throws InvalidEntityException
97
+	 * @throws InvalidDataTypeException
98
+	 * @throws InvalidClassException
99
+	 */
100
+	protected function loadShortcodesCollection()
101
+	{
102
+		$loader = new CollectionLoader(
103
+			new CollectionDetails(
104
+			// collection name
105
+				'shortcodes',
106
+				// collection interface
107
+				'EventEspresso\core\services\shortcodes\ShortcodeInterface',
108
+				// FQCNs for classes to add (all classes within that namespace will be loaded)
109
+				['EventEspresso\core\domain\entities\shortcodes'],
110
+				// filepaths to classes to add
111
+				[],
112
+				// file mask to use if parsing folder for files to add
113
+				'',
114
+				// what to use as identifier for collection entities
115
+				// using CLASS NAME prevents duplicates (works like a singleton)
116
+				CollectionDetails::ID_CLASS_NAME
117
+			)
118
+		);
119
+		return $loader->getCollection();
120
+	}
121
+
122
+
123
+	/**
124
+	 * @return void
125
+	 * @throws DomainException
126
+	 * @throws InvalidInterfaceException
127
+	 * @throws InvalidIdentifierException
128
+	 * @throws InvalidFilePathException
129
+	 * @throws InvalidEntityException
130
+	 * @throws InvalidDataTypeException
131
+	 * @throws InvalidClassException
132
+	 * @throws Exception
133
+	 */
134
+	public function registerShortcodes()
135
+	{
136
+		try {
137
+			$this->shortcodes = apply_filters(
138
+				'FHEE__EventEspresso_core_services_shortcodes_ShortcodesManager__registerShortcodes__shortcode_collection',
139
+				$this->getShortcodes()
140
+			);
141
+			if (! $this->shortcodes instanceof CollectionInterface) {
142
+				throw new InvalidEntityException(
143
+					$this->shortcodes,
144
+					'CollectionInterface',
145
+					sprintf(
146
+						esc_html__(
147
+							'The "FHEE__EventEspresso_core_services_shortcodes_ShortcodesManager__registerShortcodes__shortcode_collection" filter must return a Collection of EspressoShortcode objects. "%1$s" was received instead.',
148
+							'event_espresso'
149
+						),
150
+						is_object($this->shortcodes) ? get_class($this->shortcodes) : gettype($this->shortcodes)
151
+					)
152
+				);
153
+			}
154
+			$this->legacy_shortcodes_manager->registerShortcodes();
155
+		} catch (Exception $exception) {
156
+			new ExceptionStackTraceDisplay($exception);
157
+		}
158
+	}
159
+
160
+
161
+	/**
162
+	 * @return void
163
+	 * @throws Exception
164
+	 */
165
+	public function addShortcodes()
166
+	{
167
+		try {
168
+			// cycle thru shortcode folders
169
+			foreach ($this->shortcodes as $shortcode) {
170
+				if ($shortcode instanceof EnqueueAssetsInterface) {
171
+					add_action('wp_enqueue_scripts', [$shortcode, 'registerScriptsAndStylesheets'], 10);
172
+					add_action('wp_enqueue_scripts', [$shortcode, 'enqueueStylesheets'], 11);
173
+				}
174
+				// add_shortcode() if it has not already been added
175
+				if (! shortcode_exists($shortcode->getTag())) {
176
+					add_shortcode($shortcode->getTag(), [$shortcode, 'processShortcodeCallback']);
177
+				}
178
+			}
179
+			$this->legacy_shortcodes_manager->addShortcodes();
180
+		} catch (Exception $exception) {
181
+			new ExceptionStackTraceDisplay($exception);
182
+		}
183
+	}
184
+
185
+
186
+	/**
187
+	 * callback for the "template_redirect" hook point
188
+	 * checks posts for EE shortcodes, and initializes them,
189
+	 * then toggles filter switch that loads core default assets
190
+	 *
191
+	 * @return void
192
+	 */
193
+	public function templateRedirect()
194
+	{
195
+		global $wp_query;
196
+		if (empty($wp_query->posts)) {
197
+			return;
198
+		}
199
+		$load_assets = false;
200
+		// array of posts displayed in current request
201
+		$posts = is_array($wp_query->posts) ? $wp_query->posts : [$wp_query->posts];
202
+		foreach ($posts as $post) {
203
+			// now check post content and excerpt for EE shortcodes
204
+			$load_assets = $this->parseContentForShortcodes($post->post_content)
205
+				? true
206
+				: $load_assets;
207
+		}
208
+		if ($load_assets) {
209
+			$this->current_page->setEspressoPage(true);
210
+			add_filter('FHEE_load_css', '__return_true');
211
+			add_filter('FHEE_load_js', '__return_true');
212
+		}
213
+	}
214
+
215
+
216
+	/**
217
+	 * checks supplied content against list of shortcodes,
218
+	 * then initializes any found shortcodes, and returns true.
219
+	 * returns false if no shortcodes found.
220
+	 *
221
+	 * @param string $content
222
+	 * @return bool
223
+	 */
224
+	public function parseContentForShortcodes($content)
225
+	{
226
+		if (empty($this->shortcodes)) {
227
+			return false;
228
+		}
229
+		$has_shortcode = false;
230
+		foreach ($this->shortcodes as $shortcode) {
231
+			if (has_shortcode($content, $shortcode->getTag())) {
232
+				$shortcode->initializeShortcode();
233
+				$has_shortcode = true;
234
+			}
235
+		}
236
+		return $has_shortcode;
237
+	}
238 238
 }
Please login to merge, or discard this patch.
core/EE_Front_Controller.core.php 2 patches
Spacing   +5 added lines, -5 removed lines patch added patch discarded remove patch
@@ -98,7 +98,7 @@  discard block
 block discarded – undo
98 98
      */
99 99
     public function Request_Handler()
100 100
     {
101
-        if (! $this->Request_Handler instanceof EE_Request_Handler) {
101
+        if ( ! $this->Request_Handler instanceof EE_Request_Handler) {
102 102
             $this->Request_Handler = LoaderFactory::getLoader()->getShared('EE_Request_Handler');
103 103
         }
104 104
         return $this->Request_Handler;
@@ -333,7 +333,7 @@  discard block
 block discarded – undo
333 333
         print(
334 334
         apply_filters(
335 335
             'FHEE__EE_Front_Controller__header_meta_tag',
336
-            '<meta name="generator" content="Event Espresso Version ' . EVENT_ESPRESSO_VERSION . "\" />\n"
336
+            '<meta name="generator" content="Event Espresso Version '.EVENT_ESPRESSO_VERSION."\" />\n"
337 337
         )
338 338
         );
339 339
 
@@ -350,7 +350,7 @@  discard block
 block discarded – undo
350 350
             print(
351 351
             apply_filters(
352 352
                 'FHEE__EE_Front_Controller__header_meta_tag__noindex_for_event_type',
353
-                '<meta name="robots" content="noindex,follow" />' . "\n"
353
+                '<meta name="robots" content="noindex,follow" />'."\n"
354 354
             )
355 355
             );
356 356
         }
@@ -434,7 +434,7 @@  discard block
 block discarded – undo
434 434
     public function prependNotices($the_content)
435 435
     {
436 436
         $notices = $this->printNotices();
437
-        return $notices ? $notices . $the_content : $the_content;
437
+        return $notices ? $notices.$the_content : $the_content;
438 438
     }
439 439
 
440 440
 
@@ -446,7 +446,7 @@  discard block
 block discarded – undo
446 446
     {
447 447
         ob_start();
448 448
         echo wp_kses(EE_Error::get_notices(), AllowedTags::getWithFormTags());
449
-        EEH_Template::display_template(EE_TEMPLATES . 'espresso-ajax-notices.template.php');
449
+        EEH_Template::display_template(EE_TEMPLATES.'espresso-ajax-notices.template.php');
450 450
         return ob_get_clean();
451 451
     }
452 452
 
Please login to merge, or discard this patch.
Indentation   +509 added lines, -509 removed lines patch added patch discarded remove patch
@@ -17,513 +17,513 @@
 block discarded – undo
17 17
  */
18 18
 final class EE_Front_Controller
19 19
 {
20
-    /**
21
-     * @var string
22
-     */
23
-    private $_template_path;
24
-
25
-    /**
26
-     * @var string
27
-     */
28
-    private $_template;
29
-
30
-    /**
31
-     * @type EE_Registry
32
-     */
33
-    protected $Registry;
34
-
35
-    /**
36
-     * @type EE_Request_Handler
37
-     */
38
-    protected $Request_Handler;
39
-
40
-    /**
41
-     * @type EE_Module_Request_Router
42
-     */
43
-    protected $Module_Request_Router;
44
-
45
-    /**
46
-     * @type CurrentPage
47
-     */
48
-    protected $current_page;
49
-
50
-
51
-    /**
52
-     *    class constructor
53
-     *    should fire after shortcode, module, addon, or other plugin's default priority init phases have run
54
-     *
55
-     * @access    public
56
-     * @param EE_Registry              $Registry
57
-     * @param CurrentPage              $EspressoPage
58
-     * @param EE_Module_Request_Router $Module_Request_Router
59
-     */
60
-    public function __construct(
61
-        EE_Registry $Registry,
62
-        CurrentPage $EspressoPage,
63
-        EE_Module_Request_Router $Module_Request_Router
64
-    ) {
65
-        $this->Registry              = $Registry;
66
-        $this->current_page          = $EspressoPage;
67
-        $this->Module_Request_Router = $Module_Request_Router;
68
-        // load other resources and begin to actually run shortcodes and modules
69
-        // analyse the incoming WP request
70
-        add_action('parse_request', array($this, 'get_request'), 1, 1);
71
-        // process request with module factory
72
-        add_action('pre_get_posts', array($this, 'pre_get_posts'), 10, 1);
73
-        // before headers sent
74
-        add_action('wp', array($this, 'wp'), 5);
75
-        // primarily used to process any content shortcodes
76
-        add_action('template_redirect', array($this, 'templateRedirect'), 999);
77
-        // header
78
-        add_action('wp_head', array($this, 'header_meta_tag'), 5);
79
-        add_action('wp_print_scripts', array($this, 'wp_print_scripts'), 10);
80
-        add_filter('template_include', array($this, 'template_include'), 1);
81
-        // display errors
82
-        add_action('loop_start', array($this, 'display_errors'), 2);
83
-        // the content
84
-        // add_filter( 'the_content', array( $this, 'the_content' ), 5, 1 );
85
-        // exclude our private cpt comments
86
-        add_filter('comments_clauses', array($this, 'filter_wp_comments'), 10, 1);
87
-        // make sure any ajax requests will respect the url schema when requests are made against admin-ajax.php (http:// or https://)
88
-        add_filter('admin_url', array($this, 'maybe_force_admin_ajax_ssl'), 200, 1);
89
-        // action hook EE
90
-        do_action('AHEE__EE_Front_Controller__construct__done', $this);
91
-    }
92
-
93
-
94
-    /**
95
-     * @return EE_Request_Handler
96
-     * @deprecated 4.10.14.p
97
-     */
98
-    public function Request_Handler()
99
-    {
100
-        if (! $this->Request_Handler instanceof EE_Request_Handler) {
101
-            $this->Request_Handler = LoaderFactory::getLoader()->getShared('EE_Request_Handler');
102
-        }
103
-        return $this->Request_Handler;
104
-    }
105
-
106
-
107
-    /**
108
-     * @return EE_Module_Request_Router
109
-     */
110
-    public function Module_Request_Router()
111
-    {
112
-        return $this->Module_Request_Router;
113
-    }
114
-
115
-
116
-    /**
117
-     * @return LegacyShortcodesManager
118
-     * @deprecated 4.10.14.p
119
-     */
120
-    public function getLegacyShortcodesManager()
121
-    {
122
-        return EE_Config::getLegacyShortcodesManager();
123
-    }
124
-
125
-
126
-
127
-
128
-
129
-    /***********************************************        INIT ACTION HOOK         ***********************************************/
130
-    /**
131
-     * filter_wp_comments
132
-     * This simply makes sure that any "private" EE CPTs do not have their comments show up in any wp comment
133
-     * widgets/queries done on frontend
134
-     *
135
-     * @param  array $clauses array of comment clauses setup by WP_Comment_Query
136
-     * @return array array of comment clauses with modifications.
137
-     * @throws InvalidArgumentException
138
-     * @throws InvalidDataTypeException
139
-     * @throws InvalidInterfaceException
140
-     */
141
-    public function filter_wp_comments($clauses)
142
-    {
143
-        global $wpdb;
144
-        if (strpos($clauses['join'], $wpdb->posts) !== false) {
145
-            /** @var EventEspresso\core\domain\entities\custom_post_types\CustomPostTypeDefinitions $custom_post_types */
146
-            $custom_post_types = LoaderFactory::getLoader()->getShared(
147
-                'EventEspresso\core\domain\entities\custom_post_types\CustomPostTypeDefinitions'
148
-            );
149
-            $cpts = $custom_post_types->getPrivateCustomPostTypes();
150
-            foreach ($cpts as $cpt => $details) {
151
-                $clauses['where'] .= $wpdb->prepare(" AND $wpdb->posts.post_type != %s", $cpt);
152
-            }
153
-        }
154
-        return $clauses;
155
-    }
156
-
157
-
158
-    /**
159
-     * this just makes sure that if the site is using ssl that we force that for any admin ajax calls from frontend
160
-     *
161
-     * @param  string $url incoming url
162
-     * @return string         final assembled url
163
-     */
164
-    public function maybe_force_admin_ajax_ssl($url)
165
-    {
166
-        if (is_ssl() && preg_match('/admin-ajax.php/', $url)) {
167
-            $url = str_replace('http://', 'https://', $url);
168
-        }
169
-        return $url;
170
-    }
171
-
172
-
173
-
174
-
175
-
176
-
177
-    /***********************************************        WP_LOADED ACTION HOOK         ***********************************************/
178
-
179
-
180
-    /**
181
-     *    wp_loaded - should fire after shortcode, module, addon, or other plugin's have been registered and their
182
-     *    default priority init phases have run
183
-     *
184
-     * @access    public
185
-     * @return    void
186
-     */
187
-    public function wp_loaded()
188
-    {
189
-    }
190
-
191
-
192
-
193
-
194
-
195
-    /***********************************************        PARSE_REQUEST HOOK         ***********************************************/
196
-    /**
197
-     *    _get_request
198
-     *
199
-     * @access public
200
-     * @param WP $WP
201
-     * @return void
202
-     */
203
-    public function get_request(WP $WP)
204
-    {
205
-        do_action('AHEE__EE_Front_Controller__get_request__start');
206
-        $this->current_page->parseQueryVars($WP);
207
-        do_action('AHEE__EE_Front_Controller__get_request__complete');
208
-        remove_action('parse_request', [$this, 'get_request'], 1);
209
-    }
210
-
211
-
212
-    /**
213
-     *    pre_get_posts - basically a module factory for instantiating modules and selecting the final view template
214
-     *
215
-     * @access    public
216
-     * @param WP_Query $WP_Query
217
-     * @return    void
218
-     * @throws EE_Error
219
-     * @throws ReflectionException
220
-     */
221
-    public function pre_get_posts($WP_Query)
222
-    {
223
-        // only load Module_Request_Router if this is the main query
224
-        if (
225
-            $this->Module_Request_Router instanceof EE_Module_Request_Router
226
-            && $WP_Query->is_main_query()
227
-        ) {
228
-            // cycle thru module routes
229
-            while ($route = $this->Module_Request_Router->get_route($WP_Query)) {
230
-                // determine module and method for route
231
-                $module = $this->Module_Request_Router->resolve_route($route[0], $route[1]);
232
-                if ($module instanceof EED_Module) {
233
-                    // get registered view for route
234
-                    $this->_template_path = $this->Module_Request_Router->get_view($route);
235
-                    // grab module name
236
-                    $module_name = $module->module_name();
237
-                    // map the module to the module objects
238
-                    $this->Registry->modules->{$module_name} = $module;
239
-                }
240
-            }
241
-        }
242
-    }
243
-
244
-
245
-
246
-
247
-
248
-    /***********************************************        WP HOOK         ***********************************************/
249
-
250
-
251
-    /**
252
-     *    wp - basically last chance to do stuff before headers sent
253
-     *
254
-     * @access    public
255
-     * @return    void
256
-     */
257
-    public function wp()
258
-    {
259
-    }
260
-
261
-
262
-
263
-    /***********************     GET_HEADER && WP_HEAD HOOK     ***********************/
264
-
265
-
266
-    /**
267
-     * callback for the "template_redirect" hook point
268
-     * checks sidebars for EE widgets
269
-     * loads resources and assets accordingly
270
-     *
271
-     * @return void
272
-     */
273
-    public function templateRedirect()
274
-    {
275
-        global $wp_query;
276
-        if (empty($wp_query->posts)) {
277
-            return;
278
-        }
279
-        // if we already know this is an espresso page, then load assets
280
-        $load_assets = $this->current_page->isEspressoPage();
281
-        // if we are already loading assets then just move along, otherwise check for widgets
282
-        $load_assets = $load_assets || $this->espresso_widgets_in_active_sidebars();
283
-        if ($load_assets) {
284
-            add_action('wp_enqueue_scripts', array($this, 'enqueueStyle'), 10);
285
-            add_action('wp_enqueue_scripts', array($this, 'enqueueScripts'), 10);
286
-        }
287
-    }
288
-
289
-
290
-    /**
291
-     * builds list of active widgets then scans active sidebars looking for them
292
-     * returns true is an EE widget is found in an active sidebar
293
-     * Please Note: this does NOT mean that the sidebar or widget
294
-     * is actually in use in a given template, as that is unfortunately not known
295
-     * until a sidebar and it's widgets are actually loaded
296
-     *
297
-     * @return boolean
298
-     */
299
-    private function espresso_widgets_in_active_sidebars()
300
-    {
301
-        $espresso_widgets = array();
302
-        foreach ($this->Registry->widgets as $widget_class => $widget) {
303
-            $id_base = EspressoWidget::getIdBase($widget_class);
304
-            if (is_active_widget(false, false, $id_base)) {
305
-                $espresso_widgets[] = $id_base;
306
-            }
307
-        }
308
-        $all_sidebar_widgets = wp_get_sidebars_widgets();
309
-        foreach ($all_sidebar_widgets as $sidebar_widgets) {
310
-            if (is_array($sidebar_widgets) && ! empty($sidebar_widgets)) {
311
-                foreach ($sidebar_widgets as $sidebar_widget) {
312
-                    foreach ($espresso_widgets as $espresso_widget) {
313
-                        if (strpos($sidebar_widget, $espresso_widget) !== false) {
314
-                            return true;
315
-                        }
316
-                    }
317
-                }
318
-            }
319
-        }
320
-        return false;
321
-    }
322
-
323
-
324
-    /**
325
-     *    header_meta_tag
326
-     *
327
-     * @access    public
328
-     * @return    void
329
-     */
330
-    public function header_meta_tag()
331
-    {
332
-        print(
333
-        apply_filters(
334
-            'FHEE__EE_Front_Controller__header_meta_tag',
335
-            '<meta name="generator" content="Event Espresso Version ' . EVENT_ESPRESSO_VERSION . "\" />\n"
336
-        )
337
-        );
338
-
339
-        // let's exclude all event type taxonomy term archive pages from search engine indexing
340
-        // @see https://events.codebasehq.com/projects/event-espresso/tickets/10249
341
-        // also exclude all critical pages from indexing
342
-        if (
343
-            (
344
-                is_tax('espresso_event_type')
345
-                && get_option('blog_public') !== '0'
346
-            )
347
-            || is_page(EE_Registry::instance()->CFG->core->get_critical_pages_array())
348
-        ) {
349
-            print(
350
-            apply_filters(
351
-                'FHEE__EE_Front_Controller__header_meta_tag__noindex_for_event_type',
352
-                '<meta name="robots" content="noindex,follow" />' . "\n"
353
-            )
354
-            );
355
-        }
356
-    }
357
-
358
-
359
-    /**
360
-     * wp_print_scripts
361
-     *
362
-     * @return void
363
-     * @throws EE_Error
364
-     */
365
-    public function wp_print_scripts()
366
-    {
367
-        global $post;
368
-        if (
369
-            isset($post->EE_Event)
370
-            && $post->EE_Event instanceof EE_Event
371
-            && get_post_type() === 'espresso_events'
372
-            && is_singular()
373
-        ) {
374
-            EEH_Schema::add_json_linked_data_for_event($post->EE_Event);
375
-        }
376
-    }
377
-
378
-
379
-    public function enqueueStyle()
380
-    {
381
-        wp_enqueue_style('espresso_default');
382
-        wp_enqueue_style('espresso_custom_css');
383
-    }
384
-
385
-
386
-
387
-    /***********************************************        WP_FOOTER         ***********************************************/
388
-
389
-
390
-    public function enqueueScripts()
391
-    {
392
-        wp_enqueue_script('espresso_core');
393
-    }
394
-
395
-
396
-    /**
397
-     * display_errors
398
-     *
399
-     * @access public
400
-     * @return void
401
-     * @throws DomainException
402
-     */
403
-    public function display_errors()
404
-    {
405
-        static $shown_already = false;
406
-        do_action('AHEE__EE_Front_Controller__display_errors__begin');
407
-        if (
408
-            ! $shown_already
409
-            && apply_filters('FHEE__EE_Front_Controller__display_errors', true)
410
-            && is_main_query()
411
-            && ! is_feed()
412
-            && in_the_loop()
413
-            && $this->current_page->isEspressoPage()
414
-        ) {
415
-            $shown_already = true;
416
-            if (did_action('wp_head')) {
417
-                echo $this->printNotices();
418
-            } else {
419
-                // block enabled themes run their query loop before headers are sent
420
-                // so we need to add our notices onto the beginning of the content
421
-                add_filter('the_content', [$this, 'prependNotices'], 1, 1);
422
-            }
423
-        }
424
-        do_action('AHEE__EE_Front_Controller__display_errors__end');
425
-    }
426
-
427
-
428
-    /**
429
-     * @param string $the_content
430
-     * @return string
431
-     * @since 4.10.30.p
432
-     */
433
-    public function prependNotices($the_content)
434
-    {
435
-        $notices = $this->printNotices();
436
-        return $notices ? $notices . $the_content : $the_content;
437
-    }
438
-
439
-
440
-    /**
441
-     * @return false|string
442
-     * @since 4.10.30.p
443
-     */
444
-    public function printNotices()
445
-    {
446
-        ob_start();
447
-        echo wp_kses(EE_Error::get_notices(), AllowedTags::getWithFormTags());
448
-        EEH_Template::display_template(EE_TEMPLATES . 'espresso-ajax-notices.template.php');
449
-        return ob_get_clean();
450
-    }
451
-
452
-
453
-
454
-    /***********************************************        UTILITIES         ***********************************************/
455
-
456
-
457
-    /**
458
-     * @param string $template_include_path
459
-     * @return string
460
-     * @throws EE_Error
461
-     * @throws ReflectionException
462
-     */
463
-    public function template_include($template_include_path = null)
464
-    {
465
-        if ($this->current_page->isEspressoPage()) {
466
-            // despite all helpers having autoloaders set, we need to manually load the template loader
467
-            // because there are some side effects in that class for triggering template tag functions
468
-            $this->Registry->load_helper('EEH_Template');
469
-            $this->_template_path = ! empty($this->_template_path)
470
-                ? basename($this->_template_path)
471
-                : basename(
472
-                    $template_include_path
473
-                );
474
-            $template_path = EEH_Template::locate_template($this->_template_path, array(), false);
475
-            $this->_template_path = ! empty($template_path) ? $template_path : $template_include_path;
476
-            $this->_template = basename($this->_template_path);
477
-            return $this->_template_path;
478
-        }
479
-        return $template_include_path;
480
-    }
481
-
482
-
483
-    /**
484
-     * @param bool $with_path
485
-     * @return    string
486
-     */
487
-    public function get_selected_template($with_path = false)
488
-    {
489
-        return $with_path ? $this->_template_path : $this->_template;
490
-    }
491
-
492
-
493
-    /**
494
-     * @param string $shortcode_class
495
-     * @param WP     $wp
496
-     * @throws ReflectionException
497
-     * @deprecated 4.9.26
498
-     */
499
-    public function initialize_shortcode($shortcode_class = '', WP $wp = null)
500
-    {
501
-        EE_Error::doing_it_wrong(
502
-            __METHOD__,
503
-            esc_html__(
504
-                'Usage is deprecated. Please use \EventEspresso\core\services\shortcodes\LegacyShortcodesManager::initializeShortcode() instead.',
505
-                'event_espresso'
506
-            ),
507
-            '4.9.26'
508
-        );
509
-        $this->getLegacyShortcodesManager()->initializeShortcode($shortcode_class, $wp);
510
-    }
511
-
512
-
513
-    /**
514
-     * @return void
515
-     * @deprecated 4.9.57.p
516
-     */
517
-    public function loadPersistentAdminNoticeManager()
518
-    {
519
-    }
520
-
521
-
522
-    /**
523
-     * @return void
524
-     * @deprecated 4.9.64.p
525
-     */
526
-    public function employ_CPT_Strategy()
527
-    {
528
-    }
20
+	/**
21
+	 * @var string
22
+	 */
23
+	private $_template_path;
24
+
25
+	/**
26
+	 * @var string
27
+	 */
28
+	private $_template;
29
+
30
+	/**
31
+	 * @type EE_Registry
32
+	 */
33
+	protected $Registry;
34
+
35
+	/**
36
+	 * @type EE_Request_Handler
37
+	 */
38
+	protected $Request_Handler;
39
+
40
+	/**
41
+	 * @type EE_Module_Request_Router
42
+	 */
43
+	protected $Module_Request_Router;
44
+
45
+	/**
46
+	 * @type CurrentPage
47
+	 */
48
+	protected $current_page;
49
+
50
+
51
+	/**
52
+	 *    class constructor
53
+	 *    should fire after shortcode, module, addon, or other plugin's default priority init phases have run
54
+	 *
55
+	 * @access    public
56
+	 * @param EE_Registry              $Registry
57
+	 * @param CurrentPage              $EspressoPage
58
+	 * @param EE_Module_Request_Router $Module_Request_Router
59
+	 */
60
+	public function __construct(
61
+		EE_Registry $Registry,
62
+		CurrentPage $EspressoPage,
63
+		EE_Module_Request_Router $Module_Request_Router
64
+	) {
65
+		$this->Registry              = $Registry;
66
+		$this->current_page          = $EspressoPage;
67
+		$this->Module_Request_Router = $Module_Request_Router;
68
+		// load other resources and begin to actually run shortcodes and modules
69
+		// analyse the incoming WP request
70
+		add_action('parse_request', array($this, 'get_request'), 1, 1);
71
+		// process request with module factory
72
+		add_action('pre_get_posts', array($this, 'pre_get_posts'), 10, 1);
73
+		// before headers sent
74
+		add_action('wp', array($this, 'wp'), 5);
75
+		// primarily used to process any content shortcodes
76
+		add_action('template_redirect', array($this, 'templateRedirect'), 999);
77
+		// header
78
+		add_action('wp_head', array($this, 'header_meta_tag'), 5);
79
+		add_action('wp_print_scripts', array($this, 'wp_print_scripts'), 10);
80
+		add_filter('template_include', array($this, 'template_include'), 1);
81
+		// display errors
82
+		add_action('loop_start', array($this, 'display_errors'), 2);
83
+		// the content
84
+		// add_filter( 'the_content', array( $this, 'the_content' ), 5, 1 );
85
+		// exclude our private cpt comments
86
+		add_filter('comments_clauses', array($this, 'filter_wp_comments'), 10, 1);
87
+		// make sure any ajax requests will respect the url schema when requests are made against admin-ajax.php (http:// or https://)
88
+		add_filter('admin_url', array($this, 'maybe_force_admin_ajax_ssl'), 200, 1);
89
+		// action hook EE
90
+		do_action('AHEE__EE_Front_Controller__construct__done', $this);
91
+	}
92
+
93
+
94
+	/**
95
+	 * @return EE_Request_Handler
96
+	 * @deprecated 4.10.14.p
97
+	 */
98
+	public function Request_Handler()
99
+	{
100
+		if (! $this->Request_Handler instanceof EE_Request_Handler) {
101
+			$this->Request_Handler = LoaderFactory::getLoader()->getShared('EE_Request_Handler');
102
+		}
103
+		return $this->Request_Handler;
104
+	}
105
+
106
+
107
+	/**
108
+	 * @return EE_Module_Request_Router
109
+	 */
110
+	public function Module_Request_Router()
111
+	{
112
+		return $this->Module_Request_Router;
113
+	}
114
+
115
+
116
+	/**
117
+	 * @return LegacyShortcodesManager
118
+	 * @deprecated 4.10.14.p
119
+	 */
120
+	public function getLegacyShortcodesManager()
121
+	{
122
+		return EE_Config::getLegacyShortcodesManager();
123
+	}
124
+
125
+
126
+
127
+
128
+
129
+	/***********************************************        INIT ACTION HOOK         ***********************************************/
130
+	/**
131
+	 * filter_wp_comments
132
+	 * This simply makes sure that any "private" EE CPTs do not have their comments show up in any wp comment
133
+	 * widgets/queries done on frontend
134
+	 *
135
+	 * @param  array $clauses array of comment clauses setup by WP_Comment_Query
136
+	 * @return array array of comment clauses with modifications.
137
+	 * @throws InvalidArgumentException
138
+	 * @throws InvalidDataTypeException
139
+	 * @throws InvalidInterfaceException
140
+	 */
141
+	public function filter_wp_comments($clauses)
142
+	{
143
+		global $wpdb;
144
+		if (strpos($clauses['join'], $wpdb->posts) !== false) {
145
+			/** @var EventEspresso\core\domain\entities\custom_post_types\CustomPostTypeDefinitions $custom_post_types */
146
+			$custom_post_types = LoaderFactory::getLoader()->getShared(
147
+				'EventEspresso\core\domain\entities\custom_post_types\CustomPostTypeDefinitions'
148
+			);
149
+			$cpts = $custom_post_types->getPrivateCustomPostTypes();
150
+			foreach ($cpts as $cpt => $details) {
151
+				$clauses['where'] .= $wpdb->prepare(" AND $wpdb->posts.post_type != %s", $cpt);
152
+			}
153
+		}
154
+		return $clauses;
155
+	}
156
+
157
+
158
+	/**
159
+	 * this just makes sure that if the site is using ssl that we force that for any admin ajax calls from frontend
160
+	 *
161
+	 * @param  string $url incoming url
162
+	 * @return string         final assembled url
163
+	 */
164
+	public function maybe_force_admin_ajax_ssl($url)
165
+	{
166
+		if (is_ssl() && preg_match('/admin-ajax.php/', $url)) {
167
+			$url = str_replace('http://', 'https://', $url);
168
+		}
169
+		return $url;
170
+	}
171
+
172
+
173
+
174
+
175
+
176
+
177
+	/***********************************************        WP_LOADED ACTION HOOK         ***********************************************/
178
+
179
+
180
+	/**
181
+	 *    wp_loaded - should fire after shortcode, module, addon, or other plugin's have been registered and their
182
+	 *    default priority init phases have run
183
+	 *
184
+	 * @access    public
185
+	 * @return    void
186
+	 */
187
+	public function wp_loaded()
188
+	{
189
+	}
190
+
191
+
192
+
193
+
194
+
195
+	/***********************************************        PARSE_REQUEST HOOK         ***********************************************/
196
+	/**
197
+	 *    _get_request
198
+	 *
199
+	 * @access public
200
+	 * @param WP $WP
201
+	 * @return void
202
+	 */
203
+	public function get_request(WP $WP)
204
+	{
205
+		do_action('AHEE__EE_Front_Controller__get_request__start');
206
+		$this->current_page->parseQueryVars($WP);
207
+		do_action('AHEE__EE_Front_Controller__get_request__complete');
208
+		remove_action('parse_request', [$this, 'get_request'], 1);
209
+	}
210
+
211
+
212
+	/**
213
+	 *    pre_get_posts - basically a module factory for instantiating modules and selecting the final view template
214
+	 *
215
+	 * @access    public
216
+	 * @param WP_Query $WP_Query
217
+	 * @return    void
218
+	 * @throws EE_Error
219
+	 * @throws ReflectionException
220
+	 */
221
+	public function pre_get_posts($WP_Query)
222
+	{
223
+		// only load Module_Request_Router if this is the main query
224
+		if (
225
+			$this->Module_Request_Router instanceof EE_Module_Request_Router
226
+			&& $WP_Query->is_main_query()
227
+		) {
228
+			// cycle thru module routes
229
+			while ($route = $this->Module_Request_Router->get_route($WP_Query)) {
230
+				// determine module and method for route
231
+				$module = $this->Module_Request_Router->resolve_route($route[0], $route[1]);
232
+				if ($module instanceof EED_Module) {
233
+					// get registered view for route
234
+					$this->_template_path = $this->Module_Request_Router->get_view($route);
235
+					// grab module name
236
+					$module_name = $module->module_name();
237
+					// map the module to the module objects
238
+					$this->Registry->modules->{$module_name} = $module;
239
+				}
240
+			}
241
+		}
242
+	}
243
+
244
+
245
+
246
+
247
+
248
+	/***********************************************        WP HOOK         ***********************************************/
249
+
250
+
251
+	/**
252
+	 *    wp - basically last chance to do stuff before headers sent
253
+	 *
254
+	 * @access    public
255
+	 * @return    void
256
+	 */
257
+	public function wp()
258
+	{
259
+	}
260
+
261
+
262
+
263
+	/***********************     GET_HEADER && WP_HEAD HOOK     ***********************/
264
+
265
+
266
+	/**
267
+	 * callback for the "template_redirect" hook point
268
+	 * checks sidebars for EE widgets
269
+	 * loads resources and assets accordingly
270
+	 *
271
+	 * @return void
272
+	 */
273
+	public function templateRedirect()
274
+	{
275
+		global $wp_query;
276
+		if (empty($wp_query->posts)) {
277
+			return;
278
+		}
279
+		// if we already know this is an espresso page, then load assets
280
+		$load_assets = $this->current_page->isEspressoPage();
281
+		// if we are already loading assets then just move along, otherwise check for widgets
282
+		$load_assets = $load_assets || $this->espresso_widgets_in_active_sidebars();
283
+		if ($load_assets) {
284
+			add_action('wp_enqueue_scripts', array($this, 'enqueueStyle'), 10);
285
+			add_action('wp_enqueue_scripts', array($this, 'enqueueScripts'), 10);
286
+		}
287
+	}
288
+
289
+
290
+	/**
291
+	 * builds list of active widgets then scans active sidebars looking for them
292
+	 * returns true is an EE widget is found in an active sidebar
293
+	 * Please Note: this does NOT mean that the sidebar or widget
294
+	 * is actually in use in a given template, as that is unfortunately not known
295
+	 * until a sidebar and it's widgets are actually loaded
296
+	 *
297
+	 * @return boolean
298
+	 */
299
+	private function espresso_widgets_in_active_sidebars()
300
+	{
301
+		$espresso_widgets = array();
302
+		foreach ($this->Registry->widgets as $widget_class => $widget) {
303
+			$id_base = EspressoWidget::getIdBase($widget_class);
304
+			if (is_active_widget(false, false, $id_base)) {
305
+				$espresso_widgets[] = $id_base;
306
+			}
307
+		}
308
+		$all_sidebar_widgets = wp_get_sidebars_widgets();
309
+		foreach ($all_sidebar_widgets as $sidebar_widgets) {
310
+			if (is_array($sidebar_widgets) && ! empty($sidebar_widgets)) {
311
+				foreach ($sidebar_widgets as $sidebar_widget) {
312
+					foreach ($espresso_widgets as $espresso_widget) {
313
+						if (strpos($sidebar_widget, $espresso_widget) !== false) {
314
+							return true;
315
+						}
316
+					}
317
+				}
318
+			}
319
+		}
320
+		return false;
321
+	}
322
+
323
+
324
+	/**
325
+	 *    header_meta_tag
326
+	 *
327
+	 * @access    public
328
+	 * @return    void
329
+	 */
330
+	public function header_meta_tag()
331
+	{
332
+		print(
333
+		apply_filters(
334
+			'FHEE__EE_Front_Controller__header_meta_tag',
335
+			'<meta name="generator" content="Event Espresso Version ' . EVENT_ESPRESSO_VERSION . "\" />\n"
336
+		)
337
+		);
338
+
339
+		// let's exclude all event type taxonomy term archive pages from search engine indexing
340
+		// @see https://events.codebasehq.com/projects/event-espresso/tickets/10249
341
+		// also exclude all critical pages from indexing
342
+		if (
343
+			(
344
+				is_tax('espresso_event_type')
345
+				&& get_option('blog_public') !== '0'
346
+			)
347
+			|| is_page(EE_Registry::instance()->CFG->core->get_critical_pages_array())
348
+		) {
349
+			print(
350
+			apply_filters(
351
+				'FHEE__EE_Front_Controller__header_meta_tag__noindex_for_event_type',
352
+				'<meta name="robots" content="noindex,follow" />' . "\n"
353
+			)
354
+			);
355
+		}
356
+	}
357
+
358
+
359
+	/**
360
+	 * wp_print_scripts
361
+	 *
362
+	 * @return void
363
+	 * @throws EE_Error
364
+	 */
365
+	public function wp_print_scripts()
366
+	{
367
+		global $post;
368
+		if (
369
+			isset($post->EE_Event)
370
+			&& $post->EE_Event instanceof EE_Event
371
+			&& get_post_type() === 'espresso_events'
372
+			&& is_singular()
373
+		) {
374
+			EEH_Schema::add_json_linked_data_for_event($post->EE_Event);
375
+		}
376
+	}
377
+
378
+
379
+	public function enqueueStyle()
380
+	{
381
+		wp_enqueue_style('espresso_default');
382
+		wp_enqueue_style('espresso_custom_css');
383
+	}
384
+
385
+
386
+
387
+	/***********************************************        WP_FOOTER         ***********************************************/
388
+
389
+
390
+	public function enqueueScripts()
391
+	{
392
+		wp_enqueue_script('espresso_core');
393
+	}
394
+
395
+
396
+	/**
397
+	 * display_errors
398
+	 *
399
+	 * @access public
400
+	 * @return void
401
+	 * @throws DomainException
402
+	 */
403
+	public function display_errors()
404
+	{
405
+		static $shown_already = false;
406
+		do_action('AHEE__EE_Front_Controller__display_errors__begin');
407
+		if (
408
+			! $shown_already
409
+			&& apply_filters('FHEE__EE_Front_Controller__display_errors', true)
410
+			&& is_main_query()
411
+			&& ! is_feed()
412
+			&& in_the_loop()
413
+			&& $this->current_page->isEspressoPage()
414
+		) {
415
+			$shown_already = true;
416
+			if (did_action('wp_head')) {
417
+				echo $this->printNotices();
418
+			} else {
419
+				// block enabled themes run their query loop before headers are sent
420
+				// so we need to add our notices onto the beginning of the content
421
+				add_filter('the_content', [$this, 'prependNotices'], 1, 1);
422
+			}
423
+		}
424
+		do_action('AHEE__EE_Front_Controller__display_errors__end');
425
+	}
426
+
427
+
428
+	/**
429
+	 * @param string $the_content
430
+	 * @return string
431
+	 * @since 4.10.30.p
432
+	 */
433
+	public function prependNotices($the_content)
434
+	{
435
+		$notices = $this->printNotices();
436
+		return $notices ? $notices . $the_content : $the_content;
437
+	}
438
+
439
+
440
+	/**
441
+	 * @return false|string
442
+	 * @since 4.10.30.p
443
+	 */
444
+	public function printNotices()
445
+	{
446
+		ob_start();
447
+		echo wp_kses(EE_Error::get_notices(), AllowedTags::getWithFormTags());
448
+		EEH_Template::display_template(EE_TEMPLATES . 'espresso-ajax-notices.template.php');
449
+		return ob_get_clean();
450
+	}
451
+
452
+
453
+
454
+	/***********************************************        UTILITIES         ***********************************************/
455
+
456
+
457
+	/**
458
+	 * @param string $template_include_path
459
+	 * @return string
460
+	 * @throws EE_Error
461
+	 * @throws ReflectionException
462
+	 */
463
+	public function template_include($template_include_path = null)
464
+	{
465
+		if ($this->current_page->isEspressoPage()) {
466
+			// despite all helpers having autoloaders set, we need to manually load the template loader
467
+			// because there are some side effects in that class for triggering template tag functions
468
+			$this->Registry->load_helper('EEH_Template');
469
+			$this->_template_path = ! empty($this->_template_path)
470
+				? basename($this->_template_path)
471
+				: basename(
472
+					$template_include_path
473
+				);
474
+			$template_path = EEH_Template::locate_template($this->_template_path, array(), false);
475
+			$this->_template_path = ! empty($template_path) ? $template_path : $template_include_path;
476
+			$this->_template = basename($this->_template_path);
477
+			return $this->_template_path;
478
+		}
479
+		return $template_include_path;
480
+	}
481
+
482
+
483
+	/**
484
+	 * @param bool $with_path
485
+	 * @return    string
486
+	 */
487
+	public function get_selected_template($with_path = false)
488
+	{
489
+		return $with_path ? $this->_template_path : $this->_template;
490
+	}
491
+
492
+
493
+	/**
494
+	 * @param string $shortcode_class
495
+	 * @param WP     $wp
496
+	 * @throws ReflectionException
497
+	 * @deprecated 4.9.26
498
+	 */
499
+	public function initialize_shortcode($shortcode_class = '', WP $wp = null)
500
+	{
501
+		EE_Error::doing_it_wrong(
502
+			__METHOD__,
503
+			esc_html__(
504
+				'Usage is deprecated. Please use \EventEspresso\core\services\shortcodes\LegacyShortcodesManager::initializeShortcode() instead.',
505
+				'event_espresso'
506
+			),
507
+			'4.9.26'
508
+		);
509
+		$this->getLegacyShortcodesManager()->initializeShortcode($shortcode_class, $wp);
510
+	}
511
+
512
+
513
+	/**
514
+	 * @return void
515
+	 * @deprecated 4.9.57.p
516
+	 */
517
+	public function loadPersistentAdminNoticeManager()
518
+	{
519
+	}
520
+
521
+
522
+	/**
523
+	 * @return void
524
+	 * @deprecated 4.9.64.p
525
+	 */
526
+	public function employ_CPT_Strategy()
527
+	{
528
+	}
529 529
 }
Please login to merge, or discard this patch.
core/bootstrap_espresso.php 2 patches
Indentation   +77 added lines, -77 removed lines patch added patch discarded remove patch
@@ -14,22 +14,22 @@  discard block
 block discarded – undo
14 14
  */
15 15
 function espresso_load_error_handling()
16 16
 {
17
-    static $error_handling_loaded = false;
18
-    if ($error_handling_loaded) {
19
-        return;
20
-    }
21
-    // load debugging tools
22
-    if (WP_DEBUG === true && is_readable(EE_HELPERS . 'EEH_Debug_Tools.helper.php')) {
23
-        require_once EE_HELPERS . 'EEH_Debug_Tools.helper.php';
24
-        EEH_Debug_Tools::instance();
25
-    }
26
-    // load error handling
27
-    if (is_readable(EE_CORE . 'EE_Error.core.php')) {
28
-        require_once EE_CORE . 'EE_Error.core.php';
29
-    } else {
30
-        wp_die(esc_html__('The EE_Error core class could not be loaded.', 'event_espresso'));
31
-    }
32
-    $error_handling_loaded = true;
17
+	static $error_handling_loaded = false;
18
+	if ($error_handling_loaded) {
19
+		return;
20
+	}
21
+	// load debugging tools
22
+	if (WP_DEBUG === true && is_readable(EE_HELPERS . 'EEH_Debug_Tools.helper.php')) {
23
+		require_once EE_HELPERS . 'EEH_Debug_Tools.helper.php';
24
+		EEH_Debug_Tools::instance();
25
+	}
26
+	// load error handling
27
+	if (is_readable(EE_CORE . 'EE_Error.core.php')) {
28
+		require_once EE_CORE . 'EE_Error.core.php';
29
+	} else {
30
+		wp_die(esc_html__('The EE_Error core class could not be loaded.', 'event_espresso'));
31
+	}
32
+	$error_handling_loaded = true;
33 33
 }
34 34
 
35 35
 
@@ -43,19 +43,19 @@  discard block
 block discarded – undo
43 43
  */
44 44
 function espresso_load_required($classname, $full_path_to_file)
45 45
 {
46
-    if (is_readable($full_path_to_file)) {
47
-        require_once $full_path_to_file;
48
-    } else {
49
-        throw new EE_Error(
50
-            sprintf(
51
-                esc_html__(
52
-                    'The %s class file could not be located or is not readable due to file permissions.',
53
-                    'event_espresso'
54
-                ),
55
-                $classname
56
-            )
57
-        );
58
-    }
46
+	if (is_readable($full_path_to_file)) {
47
+		require_once $full_path_to_file;
48
+	} else {
49
+		throw new EE_Error(
50
+			sprintf(
51
+				esc_html__(
52
+					'The %s class file could not be located or is not readable due to file permissions.',
53
+					'event_espresso'
54
+				),
55
+				$classname
56
+			)
57
+		);
58
+	}
59 59
 }
60 60
 
61 61
 
@@ -73,52 +73,52 @@  discard block
 block discarded – undo
73 73
  */
74 74
 function bootstrap_espresso()
75 75
 {
76
-    require_once __DIR__ . '/espresso_definitions.php';
77
-    try {
78
-        espresso_load_error_handling();
79
-        // include WordPress shims for functions introduced in later versions of WordPress
80
-        espresso_load_required(
81
-            '',
82
-            EE_CORE . 'wordpress-shims.php'
83
-        );
84
-        espresso_load_required(
85
-            '',
86
-            EE_CORE . 'third-party-compatibility.php'
87
-        );
88
-        espresso_load_required(
89
-            'EEH_Base',
90
-            EE_CORE . 'helpers/EEH_Base.helper.php'
91
-        );
92
-        espresso_load_required(
93
-            'EEH_File',
94
-            EE_CORE . 'interfaces/EEHI_File.interface.php'
95
-        );
96
-        espresso_load_required(
97
-            'EEH_File',
98
-            EE_CORE . 'helpers/EEH_File.helper.php'
99
-        );
100
-        espresso_load_required(
101
-            'EEH_Array',
102
-            EE_CORE . 'helpers/EEH_Array.helper.php'
103
-        );
104
-        espresso_load_required(
105
-            'EE_Base',
106
-            EE_CORE . 'EE_Base.core.php'
107
-        );
108
-        // instantiate and configure PSR4 autoloader
109
-        espresso_load_required(
110
-            'Psr4Autoloader',
111
-            EE_CORE . 'Psr4Autoloader.php'
112
-        );
113
-        espresso_load_required(
114
-            'EE_Psr4AutoloaderInit',
115
-            EE_CORE . 'EE_Psr4AutoloaderInit.core.php'
116
-        );
117
-        $AutoloaderInit = new EE_Psr4AutoloaderInit();
118
-        $AutoloaderInit->initializeAutoloader();
119
-        new EventEspresso\core\services\bootstrap\BootstrapCore();
120
-    } catch (Exception $e) {
121
-        require_once EE_CORE . 'exceptions/ExceptionStackTraceDisplay.php';
122
-        new EventEspresso\core\exceptions\ExceptionStackTraceDisplay($e);
123
-    }
76
+	require_once __DIR__ . '/espresso_definitions.php';
77
+	try {
78
+		espresso_load_error_handling();
79
+		// include WordPress shims for functions introduced in later versions of WordPress
80
+		espresso_load_required(
81
+			'',
82
+			EE_CORE . 'wordpress-shims.php'
83
+		);
84
+		espresso_load_required(
85
+			'',
86
+			EE_CORE . 'third-party-compatibility.php'
87
+		);
88
+		espresso_load_required(
89
+			'EEH_Base',
90
+			EE_CORE . 'helpers/EEH_Base.helper.php'
91
+		);
92
+		espresso_load_required(
93
+			'EEH_File',
94
+			EE_CORE . 'interfaces/EEHI_File.interface.php'
95
+		);
96
+		espresso_load_required(
97
+			'EEH_File',
98
+			EE_CORE . 'helpers/EEH_File.helper.php'
99
+		);
100
+		espresso_load_required(
101
+			'EEH_Array',
102
+			EE_CORE . 'helpers/EEH_Array.helper.php'
103
+		);
104
+		espresso_load_required(
105
+			'EE_Base',
106
+			EE_CORE . 'EE_Base.core.php'
107
+		);
108
+		// instantiate and configure PSR4 autoloader
109
+		espresso_load_required(
110
+			'Psr4Autoloader',
111
+			EE_CORE . 'Psr4Autoloader.php'
112
+		);
113
+		espresso_load_required(
114
+			'EE_Psr4AutoloaderInit',
115
+			EE_CORE . 'EE_Psr4AutoloaderInit.core.php'
116
+		);
117
+		$AutoloaderInit = new EE_Psr4AutoloaderInit();
118
+		$AutoloaderInit->initializeAutoloader();
119
+		new EventEspresso\core\services\bootstrap\BootstrapCore();
120
+	} catch (Exception $e) {
121
+		require_once EE_CORE . 'exceptions/ExceptionStackTraceDisplay.php';
122
+		new EventEspresso\core\exceptions\ExceptionStackTraceDisplay($e);
123
+	}
124 124
 }
Please login to merge, or discard this patch.
Spacing   +15 added lines, -15 removed lines patch added patch discarded remove patch
@@ -19,13 +19,13 @@  discard block
 block discarded – undo
19 19
         return;
20 20
     }
21 21
     // load debugging tools
22
-    if (WP_DEBUG === true && is_readable(EE_HELPERS . 'EEH_Debug_Tools.helper.php')) {
23
-        require_once EE_HELPERS . 'EEH_Debug_Tools.helper.php';
22
+    if (WP_DEBUG === true && is_readable(EE_HELPERS.'EEH_Debug_Tools.helper.php')) {
23
+        require_once EE_HELPERS.'EEH_Debug_Tools.helper.php';
24 24
         EEH_Debug_Tools::instance();
25 25
     }
26 26
     // load error handling
27
-    if (is_readable(EE_CORE . 'EE_Error.core.php')) {
28
-        require_once EE_CORE . 'EE_Error.core.php';
27
+    if (is_readable(EE_CORE.'EE_Error.core.php')) {
28
+        require_once EE_CORE.'EE_Error.core.php';
29 29
     } else {
30 30
         wp_die(esc_html__('The EE_Error core class could not be loaded.', 'event_espresso'));
31 31
     }
@@ -73,52 +73,52 @@  discard block
 block discarded – undo
73 73
  */
74 74
 function bootstrap_espresso()
75 75
 {
76
-    require_once __DIR__ . '/espresso_definitions.php';
76
+    require_once __DIR__.'/espresso_definitions.php';
77 77
     try {
78 78
         espresso_load_error_handling();
79 79
         // include WordPress shims for functions introduced in later versions of WordPress
80 80
         espresso_load_required(
81 81
             '',
82
-            EE_CORE . 'wordpress-shims.php'
82
+            EE_CORE.'wordpress-shims.php'
83 83
         );
84 84
         espresso_load_required(
85 85
             '',
86
-            EE_CORE . 'third-party-compatibility.php'
86
+            EE_CORE.'third-party-compatibility.php'
87 87
         );
88 88
         espresso_load_required(
89 89
             'EEH_Base',
90
-            EE_CORE . 'helpers/EEH_Base.helper.php'
90
+            EE_CORE.'helpers/EEH_Base.helper.php'
91 91
         );
92 92
         espresso_load_required(
93 93
             'EEH_File',
94
-            EE_CORE . 'interfaces/EEHI_File.interface.php'
94
+            EE_CORE.'interfaces/EEHI_File.interface.php'
95 95
         );
96 96
         espresso_load_required(
97 97
             'EEH_File',
98
-            EE_CORE . 'helpers/EEH_File.helper.php'
98
+            EE_CORE.'helpers/EEH_File.helper.php'
99 99
         );
100 100
         espresso_load_required(
101 101
             'EEH_Array',
102
-            EE_CORE . 'helpers/EEH_Array.helper.php'
102
+            EE_CORE.'helpers/EEH_Array.helper.php'
103 103
         );
104 104
         espresso_load_required(
105 105
             'EE_Base',
106
-            EE_CORE . 'EE_Base.core.php'
106
+            EE_CORE.'EE_Base.core.php'
107 107
         );
108 108
         // instantiate and configure PSR4 autoloader
109 109
         espresso_load_required(
110 110
             'Psr4Autoloader',
111
-            EE_CORE . 'Psr4Autoloader.php'
111
+            EE_CORE.'Psr4Autoloader.php'
112 112
         );
113 113
         espresso_load_required(
114 114
             'EE_Psr4AutoloaderInit',
115
-            EE_CORE . 'EE_Psr4AutoloaderInit.core.php'
115
+            EE_CORE.'EE_Psr4AutoloaderInit.core.php'
116 116
         );
117 117
         $AutoloaderInit = new EE_Psr4AutoloaderInit();
118 118
         $AutoloaderInit->initializeAutoloader();
119 119
         new EventEspresso\core\services\bootstrap\BootstrapCore();
120 120
     } catch (Exception $e) {
121
-        require_once EE_CORE . 'exceptions/ExceptionStackTraceDisplay.php';
121
+        require_once EE_CORE.'exceptions/ExceptionStackTraceDisplay.php';
122 122
         new EventEspresso\core\exceptions\ExceptionStackTraceDisplay($e);
123 123
     }
124 124
 }
Please login to merge, or discard this patch.
core/exceptions/ExceptionStackTraceDisplay.php 2 patches
Spacing   +34 added lines, -34 removed lines patch added patch discarded remove patch
@@ -70,14 +70,14 @@  discard block
 block discarded – undo
70 70
         // start gathering output
71 71
         $output = '
72 72
         <div id="ee-error-message" class="error">
73
-            ' . $error_message . '
73
+            ' . $error_message.'
74 74
         </div>';
75 75
         $scripts = $this->printScripts(true);
76 76
         if (defined('DOING_AJAX')) {
77
-            echo wp_json_encode(array('error' => $output . $scripts));
77
+            echo wp_json_encode(array('error' => $output.$scripts));
78 78
             exit();
79 79
         }
80
-        echo wp_kses($output . $scripts, AllowedTags::getWithScriptAndStyleTags());
80
+        echo wp_kses($output.$scripts, AllowedTags::getWithScriptAndStyleTags());
81 81
     }
82 82
 
83 83
 
@@ -85,7 +85,7 @@  discard block
 block discarded – undo
85 85
     {
86 86
         return '
87 87
         <p>
88
-            <span class="ee-error-user-msg-spn">' . trim($msg) . '</span> &nbsp; <sup>' . $code . '</sup>
88
+            <span class="ee-error-user-msg-spn">' . trim($msg).'</span> &nbsp; <sup>'.$code.'</sup>
89 89
         </p>';
90 90
     }
91 91
 
@@ -110,16 +110,16 @@  discard block
 block discarded – undo
110 110
                     '<strong class="ee-error-dev-msg-str">',
111 111
                     get_class($exception),
112 112
                     '</strong>  &nbsp; <span>',
113
-                    $code . '</span>'
113
+                    $code.'</span>'
114 114
                 )
115 115
                 . '<br />
116
-                <span class="big-text">"' . trim($msg) . '"</span><br/>
116
+                <span class="big-text">"' . trim($msg).'"</span><br/>
117 117
                 <a id="display-ee-error-trace-1'
118 118
                    . $time
119 119
                    . '" class="display-ee-error-trace-lnk small-text" rel="ee-error-trace-1'
120 120
                    . $time
121 121
                    . '">
122
-                    ' . esc_html__('click to view backtrace and class/method details', 'event_espresso') . '
122
+                    ' . esc_html__('click to view backtrace and class/method details', 'event_espresso').'
123 123
                 </a><br />
124 124
                 '
125 125
                 . $exception->getFile()
@@ -136,7 +136,7 @@  discard block
 block discarded – undo
136 136
                    . '-dv" class="ee-error-trace-dv ee-error-trace-dv--hidden">
137 137
                 '
138 138
                    . $trace_details
139
-                   . $this->classDetails() . '
139
+                   . $this->classDetails().'
140 140
             </div>
141 141
         </div>';
142 142
     }
@@ -154,8 +154,8 @@  discard block
 block discarded – undo
154 154
         return '
155 155
             <div style="padding:3px; margin:0 0 1em; border:1px solid #999; background:#fff; border-radius:3px;">
156 156
                 <div style="padding:1em 2em; border:1px solid #999; background:#fcfcfc;">
157
-                    <h3>' . esc_html__('Class Details', 'event_espresso') . '</h3>
158
-                    <pre>' . $a . '</pre>
157
+                    <h3>' . esc_html__('Class Details', 'event_espresso').'</h3>
158
+                    <pre>' . $a.'</pre>
159 159
                 </div>
160 160
             </div>';
161 161
     }
@@ -186,7 +186,7 @@  discard block
 block discarded – undo
186 186
                     <th scope="col" class="ee-align-left">
187 187
                     ' . esc_html__('Class', 'event_espresso')
188 188
                               . '->'
189
-                              . esc_html__('Method( arguments )', 'event_espresso') . '
189
+                              . esc_html__('Method( arguments )', 'event_espresso').'
190 190
                     </th>
191 191
                 </tr>';
192 192
         $last_on_stack = count($trace) - 1;
@@ -198,7 +198,7 @@  discard block
 block discarded – undo
198 198
             $type     = isset($trace['type']) ? $trace['type'] : '';
199 199
             $function = isset($trace['function']) ? $trace['function'] : '';
200 200
             $args     = isset($trace['args']) ? $this->_convert_args_to_string($trace['args']) : '';
201
-            $args     = isset($trace['args']) && count($trace['args']) > 4 ? ' <br />' . $args . '<br />' : $args;
201
+            $args     = isset($trace['args']) && count($trace['args']) > 4 ? ' <br />'.$args.'<br />' : $args;
202 202
             $line     = isset($trace['line']) ? $trace['line'] : '';
203 203
             if (empty($file) && ! empty($this->class_name)) {
204 204
                 $a    = new ReflectionClass($this->class_name);
@@ -224,13 +224,13 @@  discard block
 block discarded – undo
224 224
             $file          = ! empty($file) ? $file : '&nbsp;';
225 225
             $type          = ! empty($type) ? $type : '';
226 226
             $function      = ! empty($function) ? $function : '';
227
-            $args          = ! empty($args) ? '( ' . $args . ' )' : '()';
227
+            $args          = ! empty($args) ? '( '.$args.' )' : '()';
228 228
             $trace_details .= '
229 229
                 <tr>
230
-                    <td class="ee-align-right">' . $nmbr . '</td>
231
-                    <td class="ee-align-right">' . $line . '</td>
232
-                    <td class="ee-align-left">' . $file . '</td>
233
-                    <td class="ee-align-left">' . $this->class_name . $type . $function . $args . '</td>
230
+                    <td class="ee-align-right">' . $nmbr.'</td>
231
+                    <td class="ee-align-right">' . $line.'</td>
232
+                    <td class="ee-align-left">' . $file.'</td>
233
+                    <td class="ee-align-left">' . $this->class_name.$type.$function.$args.'</td>
234 234
                 </tr>';
235 235
         }
236 236
         $trace_details .= '
@@ -266,25 +266,25 @@  discard block
 block discarded – undo
266 266
                 $args[] = ' &nbsp;&nbsp; ';
267 267
             }
268 268
             if (is_string($arg)) {
269
-                if (! $array && strlen($arg) > 75) {
269
+                if ( ! $array && strlen($arg) > 75) {
270 270
                     $args[] = '<br />';
271 271
                     for ($i = 0; $i <= $indent; $i++) {
272 272
                         $args[] = ' &nbsp;&nbsp; ';
273 273
                     }
274
-                    $args[] = "'" . $arg . "'<br />";
274
+                    $args[] = "'".$arg."'<br />";
275 275
                 } else {
276
-                    $args[] = " '" . $arg . "'";
276
+                    $args[] = " '".$arg."'";
277 277
                 }
278 278
             } elseif (is_array($arg)) {
279 279
                 $arg_count = count($arg);
280 280
                 if ($arg_count > 2) {
281 281
                     $indent++;
282
-                    $args[] = ' array(' . $this->_convert_args_to_string($arg, $indent, true) . ')';
282
+                    $args[] = ' array('.$this->_convert_args_to_string($arg, $indent, true).')';
283 283
                     $indent--;
284 284
                 } elseif ($arg_count === 0) {
285 285
                     $args[] = ' array()';
286 286
                 } else {
287
-                    $args[] = ' array( ' . $this->_convert_args_to_string($arg) . ' )';
287
+                    $args[] = ' array( '.$this->_convert_args_to_string($arg).' )';
288 288
                 }
289 289
             } elseif ($arg === null) {
290 290
                 $args[] = ' null';
@@ -327,8 +327,8 @@  discard block
 block discarded – undo
327 327
     {
328 328
         $file_bits = explode('.', basename($file));
329 329
         $error_code = ! empty($file_bits[0]) ? $file_bits[0] : '';
330
-        $error_code .= ! empty($func) ? ' - ' . $func : '';
331
-        $error_code .= ! empty($line) ? ' - ' . $line : '';
330
+        $error_code .= ! empty($func) ? ' - '.$func : '';
331
+        $error_code .= ! empty($line) ? ' - '.$line : '';
332 332
         return $error_code;
333 333
     }
334 334
 
@@ -341,7 +341,7 @@  discard block
 block discarded – undo
341 341
      */
342 342
     private function printScripts($force_print = false)
343 343
     {
344
-        if (! $force_print && (did_action('admin_enqueue_scripts') || did_action('wp_enqueue_scripts'))) {
344
+        if ( ! $force_print && (did_action('admin_enqueue_scripts') || did_action('wp_enqueue_scripts'))) {
345 345
             //  if script is already enqueued then we can just get out
346 346
             if (wp_script_is('ee_error_js')) {
347 347
                 return '';
@@ -354,18 +354,18 @@  discard block
 block discarded – undo
354 354
                 return '';
355 355
             }
356 356
         }
357
-        $jquery = includes_url() . 'js/jquery/jquery.js';
358
-        $core = EE_GLOBAL_ASSETS_URL . 'scripts/espresso_core.js?ver=' . espresso_version();
359
-        $ee_error = EE_GLOBAL_ASSETS_URL . 'scripts/EE_Error.js?ver=' . espresso_version();
360
-        $style = EE_GLOBAL_ASSETS_URL . 'css/ee-exception-stack-display.css';
357
+        $jquery = includes_url().'js/jquery/jquery.js';
358
+        $core = EE_GLOBAL_ASSETS_URL.'scripts/espresso_core.js?ver='.espresso_version();
359
+        $ee_error = EE_GLOBAL_ASSETS_URL.'scripts/EE_Error.js?ver='.espresso_version();
360
+        $style = EE_GLOBAL_ASSETS_URL.'css/ee-exception-stack-display.css';
361 361
         return '
362 362
             <script>
363
-            const ee_settings = {"wp_debug":"' . WP_DEBUG . '"};
363
+            const ee_settings = {"wp_debug":"' . WP_DEBUG.'"};
364 364
             </script>
365
-            <script src="' . esc_url_raw($jquery) . '" type="text/javascript"></script>
366
-            <script src="' . esc_url_raw($core) . '" type="text/javascript"></script>
367
-            <script src="' . esc_url_raw($ee_error) . '" type="text/javascript"></script>
368
-            <link href="' . esc_url_raw($style) . '" rel="stylesheet" />
365
+            <script src="' . esc_url_raw($jquery).'" type="text/javascript"></script>
366
+            <script src="' . esc_url_raw($core).'" type="text/javascript"></script>
367
+            <script src="' . esc_url_raw($ee_error).'" type="text/javascript"></script>
368
+            <link href="' . esc_url_raw($style).'" rel="stylesheet" />
369 369
         ';
370 370
     }
371 371
 }
Please login to merge, or discard this patch.
Indentation   +277 added lines, -277 removed lines patch added patch discarded remove patch
@@ -19,163 +19,163 @@  discard block
 block discarded – undo
19 19
  */
20 20
 class ExceptionStackTraceDisplay
21 21
 {
22
-    /**
23
-     * @var   string
24
-     * @since 4.10.24.p
25
-     */
26
-    private $class_name = '';
22
+	/**
23
+	 * @var   string
24
+	 * @since 4.10.24.p
25
+	 */
26
+	private $class_name = '';
27 27
 
28
-    /**
29
-     * @var   string
30
-     * @since 4.10.24.p
31
-     */
32
-    private $error_code = '';
28
+	/**
29
+	 * @var   string
30
+	 * @since 4.10.24.p
31
+	 */
32
+	private $error_code = '';
33 33
 
34 34
 
35
-    /**
36
-     * @param Exception $exception
37
-     * @throws Exception
38
-     */
39
-    public function __construct(Exception $exception)
40
-    {
41
-        if (WP_DEBUG && ! defined('EE_TESTS_DIR')) {
42
-            $this->displayException($exception);
43
-        } else {
44
-            throw $exception;
45
-        }
46
-    }
35
+	/**
36
+	 * @param Exception $exception
37
+	 * @throws Exception
38
+	 */
39
+	public function __construct(Exception $exception)
40
+	{
41
+		if (WP_DEBUG && ! defined('EE_TESTS_DIR')) {
42
+			$this->displayException($exception);
43
+		} else {
44
+			throw $exception;
45
+		}
46
+	}
47 47
 
48 48
 
49
-    /**
50
-     * @access protected
51
-     * @param Exception $exception
52
-     * @throws ReflectionException
53
-     */
54
-    protected function displayException(Exception $exception)
55
-    {
56
-        // get separate user and developer messages if they exist
57
-        $msg = explode('||', $exception->getMessage());
58
-        $user_msg = $msg[0];
59
-        $dev_msg = isset($msg[1]) ? $msg[1] : $msg[0];
60
-        $msg = WP_DEBUG ? $dev_msg : $user_msg;
61
-        // process trace info
62
-        $trace_details = $this->traceDetails($exception);
63
-        $code          = $exception->getCode() ?: $this->error_code;
64
-        // add helpful developer messages if debugging is on
65
-        // or generic non-identifying messages for non-privileged users
66
-        $error_message = WP_DEBUG
67
-            ? $this->developerError($exception, $msg, $code, $trace_details)
68
-            : $this->genericError($msg, $code);
69
-        // start gathering output
70
-        $output = '
49
+	/**
50
+	 * @access protected
51
+	 * @param Exception $exception
52
+	 * @throws ReflectionException
53
+	 */
54
+	protected function displayException(Exception $exception)
55
+	{
56
+		// get separate user and developer messages if they exist
57
+		$msg = explode('||', $exception->getMessage());
58
+		$user_msg = $msg[0];
59
+		$dev_msg = isset($msg[1]) ? $msg[1] : $msg[0];
60
+		$msg = WP_DEBUG ? $dev_msg : $user_msg;
61
+		// process trace info
62
+		$trace_details = $this->traceDetails($exception);
63
+		$code          = $exception->getCode() ?: $this->error_code;
64
+		// add helpful developer messages if debugging is on
65
+		// or generic non-identifying messages for non-privileged users
66
+		$error_message = WP_DEBUG
67
+			? $this->developerError($exception, $msg, $code, $trace_details)
68
+			: $this->genericError($msg, $code);
69
+		// start gathering output
70
+		$output = '
71 71
         <div id="ee-error-message" class="error">
72 72
             ' . $error_message . '
73 73
         </div>';
74
-        $scripts = $this->printScripts(true);
75
-        if (defined('DOING_AJAX')) {
76
-            echo wp_json_encode(array('error' => $output . $scripts));
77
-            exit();
78
-        }
79
-        echo wp_kses($output . $scripts, AllowedTags::getWithScriptAndStyleTags());
80
-    }
74
+		$scripts = $this->printScripts(true);
75
+		if (defined('DOING_AJAX')) {
76
+			echo wp_json_encode(array('error' => $output . $scripts));
77
+			exit();
78
+		}
79
+		echo wp_kses($output . $scripts, AllowedTags::getWithScriptAndStyleTags());
80
+	}
81 81
 
82 82
 
83
-    private function genericError($msg, $code)
84
-    {
85
-        return '
83
+	private function genericError($msg, $code)
84
+	{
85
+		return '
86 86
         <p>
87 87
             <span class="ee-error-user-msg-spn">' . trim($msg) . '</span> &nbsp; <sup>' . $code . '</sup>
88 88
         </p>';
89
-    }
89
+	}
90 90
 
91 91
 
92
-    /**
93
-     * @param Exception $exception
94
-     * @param $msg
95
-     * @param $code
96
-     * @param $trace_details
97
-     * @return string
98
-     * @throws ReflectionException
99
-     */
100
-    private function developerError(Exception $exception, $msg, $code, $trace_details)
101
-    {
102
-        $time = time();
103
-        return '
92
+	/**
93
+	 * @param Exception $exception
94
+	 * @param $msg
95
+	 * @param $code
96
+	 * @param $trace_details
97
+	 * @return string
98
+	 * @throws ReflectionException
99
+	 */
100
+	private function developerError(Exception $exception, $msg, $code, $trace_details)
101
+	{
102
+		$time = time();
103
+		return '
104 104
         <div class="ee-error-dev-msg-dv">
105 105
             <p class="ee-error-dev-msg-pg">
106 106
                 '
107
-                . sprintf(
108
-                    esc_html__('%1$sAn %2$s was thrown!%3$s code: %4$s', 'event_espresso'),
109
-                    '<strong class="ee-error-dev-msg-str">',
110
-                    get_class($exception),
111
-                    '</strong>  &nbsp; <span>',
112
-                    $code . '</span>'
113
-                )
114
-                . '<br />
107
+				. sprintf(
108
+					esc_html__('%1$sAn %2$s was thrown!%3$s code: %4$s', 'event_espresso'),
109
+					'<strong class="ee-error-dev-msg-str">',
110
+					get_class($exception),
111
+					'</strong>  &nbsp; <span>',
112
+					$code . '</span>'
113
+				)
114
+				. '<br />
115 115
                 <span class="big-text">"' . trim($msg) . '"</span><br/>
116 116
                 <a id="display-ee-error-trace-1'
117
-                   . $time
118
-                   . '" class="display-ee-error-trace-lnk small-text" rel="ee-error-trace-1'
119
-                   . $time
120
-                   . '">
117
+				   . $time
118
+				   . '" class="display-ee-error-trace-lnk small-text" rel="ee-error-trace-1'
119
+				   . $time
120
+				   . '">
121 121
                     ' . esc_html__('click to view backtrace and class/method details', 'event_espresso') . '
122 122
                 </a><br />
123 123
                 '
124
-                . $exception->getFile()
125
-                . sprintf(
126
-                    esc_html__('%1$s( line no: %2$s )%3$s', 'event_espresso'),
127
-                    ' &nbsp; <span class="small-text lt-grey-text">',
128
-                    $exception->getLine(),
129
-                    '</span>'
130
-                )
131
-                . '
124
+				. $exception->getFile()
125
+				. sprintf(
126
+					esc_html__('%1$s( line no: %2$s )%3$s', 'event_espresso'),
127
+					' &nbsp; <span class="small-text lt-grey-text">',
128
+					$exception->getLine(),
129
+					'</span>'
130
+				)
131
+				. '
132 132
             </p>
133 133
             <div id="ee-error-trace-1'
134
-                   . $time
135
-                   . '-dv" class="ee-error-trace-dv ee-error-trace-dv--hidden">
134
+				   . $time
135
+				   . '-dv" class="ee-error-trace-dv ee-error-trace-dv--hidden">
136 136
                 '
137
-                   . $trace_details
138
-                   . $this->classDetails() . '
137
+				   . $trace_details
138
+				   . $this->classDetails() . '
139 139
             </div>
140 140
         </div>';
141
-    }
141
+	}
142 142
 
143 143
 
144
-    /**
145
-     * @throws ReflectionException
146
-     */
147
-    private function classDetails()
148
-    {
149
-        if (empty($this->class_name)) {
150
-            return '';
151
-        }
152
-        $a = new ReflectionClass($this->class_name);
153
-        return '
144
+	/**
145
+	 * @throws ReflectionException
146
+	 */
147
+	private function classDetails()
148
+	{
149
+		if (empty($this->class_name)) {
150
+			return '';
151
+		}
152
+		$a = new ReflectionClass($this->class_name);
153
+		return '
154 154
             <div style="padding:3px; margin:0 0 1em; border:1px solid #999; background:#fff; border-radius:3px;">
155 155
                 <div style="padding:1em 2em; border:1px solid #999; background:#fcfcfc;">
156 156
                     <h3>' . esc_html__('Class Details', 'event_espresso') . '</h3>
157 157
                     <pre>' . $a . '</pre>
158 158
                 </div>
159 159
             </div>';
160
-    }
160
+	}
161 161
 
162
-    /**
163
-     * @param Exception $exception
164
-     * @return string
165
-     * @throws ReflectionException
166
-     * @since 4.10.24.p
167
-     */
168
-    private function traceDetails(Exception $exception)
169
-    {
170
-        $trace = $exception->getTrace();
171
-        if (empty($trace)) {
172
-            return esc_html__(
173
-                'Sorry, but no trace information was available for this exception.',
174
-                'event_espresso'
175
-            );
176
-        }
162
+	/**
163
+	 * @param Exception $exception
164
+	 * @return string
165
+	 * @throws ReflectionException
166
+	 * @since 4.10.24.p
167
+	 */
168
+	private function traceDetails(Exception $exception)
169
+	{
170
+		$trace = $exception->getTrace();
171
+		if (empty($trace)) {
172
+			return esc_html__(
173
+				'Sorry, but no trace information was available for this exception.',
174
+				'event_espresso'
175
+			);
176
+		}
177 177
 
178
-        $trace_details = '
178
+		$trace_details = '
179 179
         <div id="ee-trace-details">
180 180
             <table>
181 181
                 <tr>
@@ -184,180 +184,180 @@  discard block
 block discarded – undo
184 184
                     <th scope="col" class="ee-align-left" style="width:40%;">File</th>
185 185
                     <th scope="col" class="ee-align-left">
186 186
                     ' . esc_html__('Class', 'event_espresso')
187
-                              . '->'
188
-                              . esc_html__('Method( arguments )', 'event_espresso') . '
187
+							  . '->'
188
+							  . esc_html__('Method( arguments )', 'event_espresso') . '
189 189
                     </th>
190 190
                 </tr>';
191
-        $last_on_stack = count($trace) - 1;
192
-        // reverse array so that stack is in proper chronological order
193
-        $sorted_trace = array_reverse($trace);
194
-        foreach ($sorted_trace as $nmbr => $trace) {
195
-            $this->class_name = isset($trace['class']) ? $trace['class'] : '';
196
-            $file     = isset($trace['file']) ? $trace['file'] : '';
197
-            $type     = isset($trace['type']) ? $trace['type'] : '';
198
-            $function = isset($trace['function']) ? $trace['function'] : '';
199
-            $args     = isset($trace['args']) ? $this->_convert_args_to_string($trace['args']) : '';
200
-            $args     = isset($trace['args']) && count($trace['args']) > 4 ? ' <br />' . $args . '<br />' : $args;
201
-            $line     = isset($trace['line']) ? $trace['line'] : '';
202
-            if (empty($file) && ! empty($this->class_name)) {
203
-                $a    = new ReflectionClass($this->class_name);
204
-                $file = $a->getFileName();
205
-                if (empty($line) && ! empty($function)) {
206
-                    try {
207
-                        // if $function is a closure, this throws an exception
208
-                        $b    = new ReflectionMethod($this->class_name, $function);
209
-                        $line = $b->getStartLine();
210
-                    } catch (Exception $closure_exception) {
211
-                        $line = 'unknown';
212
-                    }
213
-                }
214
-            }
215
-            if ($nmbr === $last_on_stack) {
216
-                $file       = $exception->getFile() ?: $file;
217
-                $line       = $exception->getLine() ?: $line;
218
-                $this->error_code = $this->generate_error_code($file, $trace['function'], $line);
219
-            }
220
-            $file          = EEH_File::standardise_directory_separators($file);
221
-            $nmbr          = ! empty($nmbr) ? $nmbr : '&nbsp;';
222
-            $line          = ! empty($line) ? $line : '&nbsp;';
223
-            $file          = ! empty($file) ? $file : '&nbsp;';
224
-            $type          = ! empty($type) ? $type : '';
225
-            $function      = ! empty($function) ? $function : '';
226
-            $args          = ! empty($args) ? '( ' . $args . ' )' : '()';
227
-            $trace_details .= '
191
+		$last_on_stack = count($trace) - 1;
192
+		// reverse array so that stack is in proper chronological order
193
+		$sorted_trace = array_reverse($trace);
194
+		foreach ($sorted_trace as $nmbr => $trace) {
195
+			$this->class_name = isset($trace['class']) ? $trace['class'] : '';
196
+			$file     = isset($trace['file']) ? $trace['file'] : '';
197
+			$type     = isset($trace['type']) ? $trace['type'] : '';
198
+			$function = isset($trace['function']) ? $trace['function'] : '';
199
+			$args     = isset($trace['args']) ? $this->_convert_args_to_string($trace['args']) : '';
200
+			$args     = isset($trace['args']) && count($trace['args']) > 4 ? ' <br />' . $args . '<br />' : $args;
201
+			$line     = isset($trace['line']) ? $trace['line'] : '';
202
+			if (empty($file) && ! empty($this->class_name)) {
203
+				$a    = new ReflectionClass($this->class_name);
204
+				$file = $a->getFileName();
205
+				if (empty($line) && ! empty($function)) {
206
+					try {
207
+						// if $function is a closure, this throws an exception
208
+						$b    = new ReflectionMethod($this->class_name, $function);
209
+						$line = $b->getStartLine();
210
+					} catch (Exception $closure_exception) {
211
+						$line = 'unknown';
212
+					}
213
+				}
214
+			}
215
+			if ($nmbr === $last_on_stack) {
216
+				$file       = $exception->getFile() ?: $file;
217
+				$line       = $exception->getLine() ?: $line;
218
+				$this->error_code = $this->generate_error_code($file, $trace['function'], $line);
219
+			}
220
+			$file          = EEH_File::standardise_directory_separators($file);
221
+			$nmbr          = ! empty($nmbr) ? $nmbr : '&nbsp;';
222
+			$line          = ! empty($line) ? $line : '&nbsp;';
223
+			$file          = ! empty($file) ? $file : '&nbsp;';
224
+			$type          = ! empty($type) ? $type : '';
225
+			$function      = ! empty($function) ? $function : '';
226
+			$args          = ! empty($args) ? '( ' . $args . ' )' : '()';
227
+			$trace_details .= '
228 228
                 <tr>
229 229
                     <td class="ee-align-right">' . $nmbr . '</td>
230 230
                     <td class="ee-align-right">' . $line . '</td>
231 231
                     <td class="ee-align-left">' . $file . '</td>
232 232
                     <td class="ee-align-left">' . $this->class_name . $type . $function . $args . '</td>
233 233
                 </tr>';
234
-        }
235
-        $trace_details .= '
234
+		}
235
+		$trace_details .= '
236 236
             </table>
237 237
         </div>';
238
-        return $trace_details;
239
-    }
238
+		return $trace_details;
239
+	}
240 240
 
241 241
 
242
-    // phpcs:disable PSR1.Methods.CamelCapsMethodName.NotCamelCaps
243
-    // phpcs:disable PSR2.Methods.MethodDeclaration.Underscore
242
+	// phpcs:disable PSR1.Methods.CamelCapsMethodName.NotCamelCaps
243
+	// phpcs:disable PSR2.Methods.MethodDeclaration.Underscore
244 244
 
245
-    /**
246
-     * generate string from exception trace args
247
-     *
248
-     * @param array $arguments
249
-     * @param int   $indent
250
-     * @param bool  $array
251
-     * @return string
252
-     */
253
-    private function _convert_args_to_string($arguments = array(), $indent = 0, $array = false)
254
-    {
255
-        $args = array();
256
-        $args_count = count($arguments);
257
-        if ($args_count > 2) {
258
-            $indent++;
259
-            $args[] = '<br />';
260
-        }
261
-        $x = 0;
262
-        foreach ($arguments as $arg) {
263
-            $x++;
264
-            for ($i = 0; $i < $indent; $i++) {
265
-                $args[] = ' &nbsp;&nbsp; ';
266
-            }
267
-            if (is_string($arg)) {
268
-                if (! $array && strlen($arg) > 75) {
269
-                    $args[] = '<br />';
270
-                    for ($i = 0; $i <= $indent; $i++) {
271
-                        $args[] = ' &nbsp;&nbsp; ';
272
-                    }
273
-                    $args[] = "'" . $arg . "'<br />";
274
-                } else {
275
-                    $args[] = " '" . $arg . "'";
276
-                }
277
-            } elseif (is_array($arg)) {
278
-                $arg_count = count($arg);
279
-                if ($arg_count > 2) {
280
-                    $indent++;
281
-                    $args[] = ' array(' . $this->_convert_args_to_string($arg, $indent, true) . ')';
282
-                    $indent--;
283
-                } elseif ($arg_count === 0) {
284
-                    $args[] = ' array()';
285
-                } else {
286
-                    $args[] = ' array( ' . $this->_convert_args_to_string($arg) . ' )';
287
-                }
288
-            } elseif ($arg === null) {
289
-                $args[] = ' null';
290
-            } elseif (is_bool($arg)) {
291
-                $args[] = $arg ? ' true' : ' false';
292
-            } elseif (is_object($arg)) {
293
-                $args[] = get_class($arg);
294
-            } elseif (is_resource($arg)) {
295
-                $args[] = get_resource_type($arg);
296
-            } else {
297
-                $args[] = $arg;
298
-            }
299
-            if ($x === $args_count) {
300
-                if ($args_count > 2) {
301
-                    $args[] = '<br />';
302
-                    $indent--;
303
-                    for ($i = 1; $i < $indent; $i++) {
304
-                        $args[] = ' &nbsp;&nbsp; ';
305
-                    }
306
-                }
307
-            } else {
308
-                $args[] = $args_count > 2 ? ',<br />' : ', ';
309
-            }
310
-        }
311
-        return implode('', $args);
312
-    }
245
+	/**
246
+	 * generate string from exception trace args
247
+	 *
248
+	 * @param array $arguments
249
+	 * @param int   $indent
250
+	 * @param bool  $array
251
+	 * @return string
252
+	 */
253
+	private function _convert_args_to_string($arguments = array(), $indent = 0, $array = false)
254
+	{
255
+		$args = array();
256
+		$args_count = count($arguments);
257
+		if ($args_count > 2) {
258
+			$indent++;
259
+			$args[] = '<br />';
260
+		}
261
+		$x = 0;
262
+		foreach ($arguments as $arg) {
263
+			$x++;
264
+			for ($i = 0; $i < $indent; $i++) {
265
+				$args[] = ' &nbsp;&nbsp; ';
266
+			}
267
+			if (is_string($arg)) {
268
+				if (! $array && strlen($arg) > 75) {
269
+					$args[] = '<br />';
270
+					for ($i = 0; $i <= $indent; $i++) {
271
+						$args[] = ' &nbsp;&nbsp; ';
272
+					}
273
+					$args[] = "'" . $arg . "'<br />";
274
+				} else {
275
+					$args[] = " '" . $arg . "'";
276
+				}
277
+			} elseif (is_array($arg)) {
278
+				$arg_count = count($arg);
279
+				if ($arg_count > 2) {
280
+					$indent++;
281
+					$args[] = ' array(' . $this->_convert_args_to_string($arg, $indent, true) . ')';
282
+					$indent--;
283
+				} elseif ($arg_count === 0) {
284
+					$args[] = ' array()';
285
+				} else {
286
+					$args[] = ' array( ' . $this->_convert_args_to_string($arg) . ' )';
287
+				}
288
+			} elseif ($arg === null) {
289
+				$args[] = ' null';
290
+			} elseif (is_bool($arg)) {
291
+				$args[] = $arg ? ' true' : ' false';
292
+			} elseif (is_object($arg)) {
293
+				$args[] = get_class($arg);
294
+			} elseif (is_resource($arg)) {
295
+				$args[] = get_resource_type($arg);
296
+			} else {
297
+				$args[] = $arg;
298
+			}
299
+			if ($x === $args_count) {
300
+				if ($args_count > 2) {
301
+					$args[] = '<br />';
302
+					$indent--;
303
+					for ($i = 1; $i < $indent; $i++) {
304
+						$args[] = ' &nbsp;&nbsp; ';
305
+					}
306
+				}
307
+			} else {
308
+				$args[] = $args_count > 2 ? ',<br />' : ', ';
309
+			}
310
+		}
311
+		return implode('', $args);
312
+	}
313 313
 
314 314
 
315
-    /**
316
-     * create error code from filepath, function name,
317
-     * and line number where exception or error was thrown
318
-     *
319
-     * @access protected
320
-     * @param string $file
321
-     * @param string $func
322
-     * @param string $line
323
-     * @return string
324
-     */
325
-    protected function generate_error_code($file = '', $func = '', $line = '')
326
-    {
327
-        $file_bits = explode('.', basename($file));
328
-        $error_code = ! empty($file_bits[0]) ? $file_bits[0] : '';
329
-        $error_code .= ! empty($func) ? ' - ' . $func : '';
330
-        $error_code .= ! empty($line) ? ' - ' . $line : '';
331
-        return $error_code;
332
-    }
315
+	/**
316
+	 * create error code from filepath, function name,
317
+	 * and line number where exception or error was thrown
318
+	 *
319
+	 * @access protected
320
+	 * @param string $file
321
+	 * @param string $func
322
+	 * @param string $line
323
+	 * @return string
324
+	 */
325
+	protected function generate_error_code($file = '', $func = '', $line = '')
326
+	{
327
+		$file_bits = explode('.', basename($file));
328
+		$error_code = ! empty($file_bits[0]) ? $file_bits[0] : '';
329
+		$error_code .= ! empty($func) ? ' - ' . $func : '';
330
+		$error_code .= ! empty($line) ? ' - ' . $line : '';
331
+		return $error_code;
332
+	}
333 333
 
334 334
 
335
-    /**
336
-     * _print_scripts
337
-     *
338
-     * @param bool $force_print
339
-     * @return string
340
-     */
341
-    private function printScripts($force_print = false)
342
-    {
343
-        if (! $force_print && (did_action('admin_enqueue_scripts') || did_action('wp_enqueue_scripts'))) {
344
-            //  if script is already enqueued then we can just get out
345
-            if (wp_script_is('ee_error_js')) {
346
-                return '';
347
-            }
348
-            if (wp_script_is('ee_error_js', 'registered')) {
349
-                wp_enqueue_style('espresso_default');
350
-                wp_enqueue_style('espresso_custom_css');
351
-                wp_enqueue_script('ee_error_js');
352
-                wp_localize_script('ee_error_js', 'ee_settings', array('wp_debug' => WP_DEBUG));
353
-                return '';
354
-            }
355
-        }
356
-        $jquery = includes_url() . 'js/jquery/jquery.js';
357
-        $core = EE_GLOBAL_ASSETS_URL . 'scripts/espresso_core.js?ver=' . espresso_version();
358
-        $ee_error = EE_GLOBAL_ASSETS_URL . 'scripts/EE_Error.js?ver=' . espresso_version();
359
-        $style = EE_GLOBAL_ASSETS_URL . 'css/ee-exception-stack-display.css';
360
-        return '
335
+	/**
336
+	 * _print_scripts
337
+	 *
338
+	 * @param bool $force_print
339
+	 * @return string
340
+	 */
341
+	private function printScripts($force_print = false)
342
+	{
343
+		if (! $force_print && (did_action('admin_enqueue_scripts') || did_action('wp_enqueue_scripts'))) {
344
+			//  if script is already enqueued then we can just get out
345
+			if (wp_script_is('ee_error_js')) {
346
+				return '';
347
+			}
348
+			if (wp_script_is('ee_error_js', 'registered')) {
349
+				wp_enqueue_style('espresso_default');
350
+				wp_enqueue_style('espresso_custom_css');
351
+				wp_enqueue_script('ee_error_js');
352
+				wp_localize_script('ee_error_js', 'ee_settings', array('wp_debug' => WP_DEBUG));
353
+				return '';
354
+			}
355
+		}
356
+		$jquery = includes_url() . 'js/jquery/jquery.js';
357
+		$core = EE_GLOBAL_ASSETS_URL . 'scripts/espresso_core.js?ver=' . espresso_version();
358
+		$ee_error = EE_GLOBAL_ASSETS_URL . 'scripts/EE_Error.js?ver=' . espresso_version();
359
+		$style = EE_GLOBAL_ASSETS_URL . 'css/ee-exception-stack-display.css';
360
+		return '
361 361
             <script>
362 362
             const ee_settings = {"wp_debug":"' . WP_DEBUG . '"};
363 363
             </script>
@@ -366,5 +366,5 @@  discard block
 block discarded – undo
366 366
             <script src="' . esc_url_raw($ee_error) . '" type="text/javascript"></script>
367 367
             <link href="' . esc_url_raw($style) . '" rel="stylesheet" />
368 368
         ';
369
-    }
369
+	}
370 370
 }
Please login to merge, or discard this patch.
core/services/notifications/PersistentAdminNoticeManager.php 1 patch
Indentation   +388 added lines, -388 removed lines patch added patch discarded remove patch
@@ -30,392 +30,392 @@
 block discarded – undo
30 30
  */
31 31
 class PersistentAdminNoticeManager
32 32
 {
33
-    const WP_OPTION_KEY = 'ee_pers_admin_notices';
34
-
35
-    /**
36
-     * @var Collection|PersistentAdminNotice[] $notice_collection
37
-     */
38
-    private $notice_collection;
39
-
40
-    /**
41
-     * if AJAX is not enabled, then the return URL will be used for redirecting back to the admin page where the
42
-     * persistent admin notice was displayed, and ultimately dismissed from.
43
-     *
44
-     * @var string $return_url
45
-     */
46
-    private $return_url;
47
-
48
-    /**
49
-     * @var CapabilitiesChecker $capabilities_checker
50
-     */
51
-    private $capabilities_checker;
52
-
53
-    /**
54
-     * @var RequestInterface $request
55
-     */
56
-    private $request;
57
-
58
-
59
-    /**
60
-     * PersistentAdminNoticeManager constructor
61
-     *
62
-     * @param CapabilitiesChecker $capabilities_checker
63
-     * @param RequestInterface    $request
64
-     * @param string              $return_url where to  redirect to after dismissing notices
65
-     * @throws InvalidDataTypeException
66
-     */
67
-    public function __construct(
68
-        CapabilitiesChecker $capabilities_checker,
69
-        RequestInterface $request,
70
-        $return_url = ''
71
-    ) {
72
-        $this->setReturnUrl($return_url);
73
-        $this->capabilities_checker = $capabilities_checker;
74
-        $this->request = $request;
75
-        // setup up notices at priority 9 because `EE_Admin::display_admin_notices()` runs at priority 10,
76
-        // and we want to retrieve and generate any nag notices at the last possible moment
77
-        add_action('admin_notices', array($this, 'displayNotices'), 9);
78
-        add_action('network_admin_notices', array($this, 'displayNotices'), 9);
79
-        add_action('wp_ajax_dismiss_ee_nag_notice', array($this, 'dismissNotice'));
80
-        add_action('shutdown', array($this, 'registerAndSaveNotices'), 998);
81
-    }
82
-
83
-
84
-    /**
85
-     * @param string $return_url
86
-     * @throws InvalidDataTypeException
87
-     */
88
-    public function setReturnUrl($return_url)
89
-    {
90
-        if (! is_string($return_url)) {
91
-            throw new InvalidDataTypeException('$return_url', $return_url, 'string');
92
-        }
93
-        $this->return_url = $return_url;
94
-    }
95
-
96
-
97
-    /**
98
-     * @return Collection
99
-     * @throws InvalidEntityException
100
-     * @throws InvalidInterfaceException
101
-     * @throws InvalidDataTypeException
102
-     * @throws DomainException
103
-     * @throws DuplicateCollectionIdentifierException
104
-     */
105
-    protected function getPersistentAdminNoticeCollection()
106
-    {
107
-        if (! $this->notice_collection instanceof Collection) {
108
-            $this->notice_collection = new Collection(
109
-                'EventEspresso\core\domain\entities\notifications\PersistentAdminNotice'
110
-            );
111
-            $this->retrieveStoredNotices();
112
-            $this->registerNotices();
113
-        }
114
-        return $this->notice_collection;
115
-    }
116
-
117
-
118
-    /**
119
-     * generates PersistentAdminNotice objects for all non-dismissed notices saved to the db
120
-     *
121
-     * @return void
122
-     * @throws InvalidEntityException
123
-     * @throws DomainException
124
-     * @throws InvalidDataTypeException
125
-     * @throws DuplicateCollectionIdentifierException
126
-     */
127
-    protected function retrieveStoredNotices()
128
-    {
129
-        $persistent_admin_notices = get_option(PersistentAdminNoticeManager::WP_OPTION_KEY, array());
130
-        if (! empty($persistent_admin_notices)) {
131
-            foreach ($persistent_admin_notices as $name => $details) {
132
-                if (is_array($details)) {
133
-                    if (
134
-                        ! isset(
135
-                            $details['message'],
136
-                            $details['capability'],
137
-                            $details['cap_context'],
138
-                            $details['dismissed']
139
-                        )
140
-                    ) {
141
-                        throw new DomainException(
142
-                            sprintf(
143
-                                esc_html__(
144
-                                    'The "%1$s" PersistentAdminNotice could not be retrieved from the database.',
145
-                                    'event_espresso'
146
-                                ),
147
-                                $name
148
-                            )
149
-                        );
150
-                    }
151
-                    // new format for nag notices
152
-                    $this->notice_collection->add(
153
-                        new PersistentAdminNotice(
154
-                            $name,
155
-                            $details['message'],
156
-                            false,
157
-                            $details['capability'],
158
-                            $details['cap_context'],
159
-                            $details['dismissed']
160
-                        ),
161
-                        sanitize_key($name)
162
-                    );
163
-                } else {
164
-                    try {
165
-                        // old nag notices, that we want to convert to the new format
166
-                        $this->notice_collection->add(
167
-                            new PersistentAdminNotice(
168
-                                $name,
169
-                                (string) $details,
170
-                                false,
171
-                                '',
172
-                                '',
173
-                                empty($details)
174
-                            ),
175
-                            sanitize_key($name)
176
-                        );
177
-                    } catch (Exception $e) {
178
-                        EE_Error::add_error($e->getMessage(), __FILE__, __FUNCTION__, __LINE__);
179
-                    }
180
-                }
181
-                // each notice will self register when the action hook in registerNotices is triggered
182
-            }
183
-        }
184
-    }
185
-
186
-
187
-    /**
188
-     * exposes the Persistent Admin Notice Collection via an action
189
-     * so that PersistentAdminNotice objects can be added and/or removed
190
-     * without compromising the actual collection like a filter would
191
-     */
192
-    protected function registerNotices()
193
-    {
194
-        do_action(
195
-            'AHEE__EventEspresso_core_services_notifications_PersistentAdminNoticeManager__registerNotices',
196
-            $this->notice_collection
197
-        );
198
-    }
199
-
200
-
201
-    /**
202
-     * @throws DomainException
203
-     * @throws InvalidClassException
204
-     * @throws InvalidDataTypeException
205
-     * @throws InvalidInterfaceException
206
-     * @throws InvalidEntityException
207
-     * @throws DuplicateCollectionIdentifierException
208
-     */
209
-    public function displayNotices()
210
-    {
211
-        $this->notice_collection = $this->getPersistentAdminNoticeCollection();
212
-        if ($this->notice_collection->hasObjects()) {
213
-            $enqueue_assets = false;
214
-            // and display notices
215
-            foreach ($this->notice_collection as $persistent_admin_notice) {
216
-                /** @var PersistentAdminNotice $persistent_admin_notice */
217
-                // don't display notices that have already been dismissed
218
-                if ($persistent_admin_notice->getDismissed()) {
219
-                    continue;
220
-                }
221
-                try {
222
-                    $this->capabilities_checker->processCapCheck(
223
-                        $persistent_admin_notice->getCapCheck()
224
-                    );
225
-                } catch (InsufficientPermissionsException $e) {
226
-                    // user does not have required cap, so skip to next notice
227
-                    // and just eat the exception - nom nom nom nom
228
-                    continue;
229
-                }
230
-                if ($persistent_admin_notice->getMessage() === '') {
231
-                    continue;
232
-                }
233
-                $this->displayPersistentAdminNotice($persistent_admin_notice);
234
-                $enqueue_assets = true;
235
-            }
236
-            if ($enqueue_assets) {
237
-                $this->enqueueAssets();
238
-            }
239
-        }
240
-    }
241
-
242
-
243
-    /**
244
-     * does what it's named
245
-     *
246
-     * @return void
247
-     */
248
-    public function enqueueAssets()
249
-    {
250
-        wp_register_script(
251
-            'espresso_core',
252
-            EE_GLOBAL_ASSETS_URL . 'scripts/espresso_core.js',
253
-            array('jquery'),
254
-            EVENT_ESPRESSO_VERSION,
255
-            true
256
-        );
257
-        wp_register_script(
258
-            'ee_error_js',
259
-            EE_GLOBAL_ASSETS_URL . 'scripts/EE_Error.js',
260
-            array('espresso_core'),
261
-            EVENT_ESPRESSO_VERSION,
262
-            true
263
-        );
264
-        wp_localize_script(
265
-            'ee_error_js',
266
-            'ee_dismiss',
267
-            array(
268
-                'return_url'    => urlencode($this->return_url),
269
-                'ajax_url'      => WP_AJAX_URL,
270
-                'unknown_error' => wp_strip_all_tags(
271
-                    __(
272
-                        'An unknown error has occurred on the server while attempting to dismiss this notice.',
273
-                        'event_espresso'
274
-                    )
275
-                ),
276
-            )
277
-        );
278
-        wp_enqueue_script('ee_error_js');
279
-    }
280
-
281
-
282
-    /**
283
-     * displayPersistentAdminNoticeHtml
284
-     *
285
-     * @param  PersistentAdminNotice $persistent_admin_notice
286
-     */
287
-    protected function displayPersistentAdminNotice(PersistentAdminNotice $persistent_admin_notice)
288
-    {
289
-        // used in template
290
-        $persistent_admin_notice_name = $persistent_admin_notice->getName();
291
-        $persistent_admin_notice_message = $persistent_admin_notice->getMessage();
292
-        require EE_TEMPLATES . '/notifications/persistent_admin_notice.template.php';
293
-    }
294
-
295
-
296
-    /**
297
-     * dismissNotice
298
-     *
299
-     * @param string $pan_name the name, or key of the Persistent Admin Notice to be dismissed
300
-     * @param bool   $purge    if true, then delete it from the db
301
-     * @param bool   $return   forget all of this AJAX or redirect nonsense, and just return
302
-     * @return void
303
-     * @throws InvalidEntityException
304
-     * @throws InvalidInterfaceException
305
-     * @throws InvalidDataTypeException
306
-     * @throws DomainException
307
-     * @throws InvalidArgumentException
308
-     * @throws InvalidArgumentException
309
-     * @throws InvalidArgumentException
310
-     * @throws InvalidArgumentException
311
-     * @throws DuplicateCollectionIdentifierException
312
-     */
313
-    public function dismissNotice($pan_name = '', $purge = false, $return = false)
314
-    {
315
-        $pan_name = $this->request->getRequestParam('ee_nag_notice', $pan_name);
316
-        $this->notice_collection = $this->getPersistentAdminNoticeCollection();
317
-        if (! empty($pan_name) && $this->notice_collection->has($pan_name)) {
318
-            /** @var PersistentAdminNotice $persistent_admin_notice */
319
-            $persistent_admin_notice = $this->notice_collection->get($pan_name);
320
-            $persistent_admin_notice->setDismissed(true);
321
-            $persistent_admin_notice->setPurge($purge);
322
-            $this->saveNotices();
323
-        }
324
-        if ($return) {
325
-            return;
326
-        }
327
-        if ($this->request->isAjax()) {
328
-            // grab any notices and concatenate into string
329
-            echo wp_json_encode(
330
-                array(
331
-                    'errors' => implode('<br />', EE_Error::get_notices(false)),
332
-                )
333
-            );
334
-            exit();
335
-        }
336
-        // save errors to a transient to be displayed on next request (after redirect)
337
-        EE_Error::get_notices(false, true);
338
-        wp_safe_redirect(
339
-            urldecode(
340
-                $this->request->getRequestParam('return_url', '')
341
-            )
342
-        );
343
-    }
344
-
345
-
346
-    /**
347
-     * saveNotices
348
-     *
349
-     * @throws DomainException
350
-     * @throws InvalidDataTypeException
351
-     * @throws InvalidInterfaceException
352
-     * @throws InvalidEntityException
353
-     * @throws DuplicateCollectionIdentifierException
354
-     */
355
-    public function saveNotices()
356
-    {
357
-        $this->notice_collection = $this->getPersistentAdminNoticeCollection();
358
-        if ($this->notice_collection->hasObjects()) {
359
-            $persistent_admin_notices = get_option(PersistentAdminNoticeManager::WP_OPTION_KEY, array());
360
-            // maybe initialize persistent_admin_notices
361
-            if (empty($persistent_admin_notices)) {
362
-                add_option(PersistentAdminNoticeManager::WP_OPTION_KEY, array(), '', 'no');
363
-            }
364
-            foreach ($this->notice_collection as $persistent_admin_notice) {
365
-                // are we deleting this notice ?
366
-                if ($persistent_admin_notice->getPurge()) {
367
-                    unset($persistent_admin_notices[ $persistent_admin_notice->getName() ]);
368
-                } else {
369
-                    /** @var PersistentAdminNotice $persistent_admin_notice */
370
-                    $persistent_admin_notices[ $persistent_admin_notice->getName() ] = array(
371
-                        'message'     => $persistent_admin_notice->getMessage(),
372
-                        'capability'  => $persistent_admin_notice->getCapability(),
373
-                        'cap_context' => $persistent_admin_notice->getCapContext(),
374
-                        'dismissed'   => $persistent_admin_notice->getDismissed(),
375
-                    );
376
-                }
377
-            }
378
-            update_option(PersistentAdminNoticeManager::WP_OPTION_KEY, $persistent_admin_notices);
379
-        }
380
-    }
381
-
382
-
383
-    /**
384
-     * @throws DomainException
385
-     * @throws InvalidDataTypeException
386
-     * @throws InvalidEntityException
387
-     * @throws InvalidInterfaceException
388
-     * @throws DuplicateCollectionIdentifierException
389
-     */
390
-    public function registerAndSaveNotices()
391
-    {
392
-        $this->getPersistentAdminNoticeCollection();
393
-        $this->registerNotices();
394
-        $this->saveNotices();
395
-        add_filter(
396
-            'PersistentAdminNoticeManager__registerAndSaveNotices__complete',
397
-            '__return_true'
398
-        );
399
-    }
400
-
401
-
402
-    /**
403
-     * @throws DomainException
404
-     * @throws InvalidDataTypeException
405
-     * @throws InvalidEntityException
406
-     * @throws InvalidInterfaceException
407
-     * @throws InvalidArgumentException
408
-     * @throws DuplicateCollectionIdentifierException
409
-     */
410
-    public static function loadRegisterAndSaveNotices()
411
-    {
412
-        /** @var PersistentAdminNoticeManager $persistent_admin_notice_manager */
413
-        $persistent_admin_notice_manager = LoaderFactory::getLoader()->getShared(
414
-            'EventEspresso\core\services\notifications\PersistentAdminNoticeManager'
415
-        );
416
-        // if shutdown has already run, then call registerAndSaveNotices() manually
417
-        if (did_action('shutdown')) {
418
-            $persistent_admin_notice_manager->registerAndSaveNotices();
419
-        }
420
-    }
33
+	const WP_OPTION_KEY = 'ee_pers_admin_notices';
34
+
35
+	/**
36
+	 * @var Collection|PersistentAdminNotice[] $notice_collection
37
+	 */
38
+	private $notice_collection;
39
+
40
+	/**
41
+	 * if AJAX is not enabled, then the return URL will be used for redirecting back to the admin page where the
42
+	 * persistent admin notice was displayed, and ultimately dismissed from.
43
+	 *
44
+	 * @var string $return_url
45
+	 */
46
+	private $return_url;
47
+
48
+	/**
49
+	 * @var CapabilitiesChecker $capabilities_checker
50
+	 */
51
+	private $capabilities_checker;
52
+
53
+	/**
54
+	 * @var RequestInterface $request
55
+	 */
56
+	private $request;
57
+
58
+
59
+	/**
60
+	 * PersistentAdminNoticeManager constructor
61
+	 *
62
+	 * @param CapabilitiesChecker $capabilities_checker
63
+	 * @param RequestInterface    $request
64
+	 * @param string              $return_url where to  redirect to after dismissing notices
65
+	 * @throws InvalidDataTypeException
66
+	 */
67
+	public function __construct(
68
+		CapabilitiesChecker $capabilities_checker,
69
+		RequestInterface $request,
70
+		$return_url = ''
71
+	) {
72
+		$this->setReturnUrl($return_url);
73
+		$this->capabilities_checker = $capabilities_checker;
74
+		$this->request = $request;
75
+		// setup up notices at priority 9 because `EE_Admin::display_admin_notices()` runs at priority 10,
76
+		// and we want to retrieve and generate any nag notices at the last possible moment
77
+		add_action('admin_notices', array($this, 'displayNotices'), 9);
78
+		add_action('network_admin_notices', array($this, 'displayNotices'), 9);
79
+		add_action('wp_ajax_dismiss_ee_nag_notice', array($this, 'dismissNotice'));
80
+		add_action('shutdown', array($this, 'registerAndSaveNotices'), 998);
81
+	}
82
+
83
+
84
+	/**
85
+	 * @param string $return_url
86
+	 * @throws InvalidDataTypeException
87
+	 */
88
+	public function setReturnUrl($return_url)
89
+	{
90
+		if (! is_string($return_url)) {
91
+			throw new InvalidDataTypeException('$return_url', $return_url, 'string');
92
+		}
93
+		$this->return_url = $return_url;
94
+	}
95
+
96
+
97
+	/**
98
+	 * @return Collection
99
+	 * @throws InvalidEntityException
100
+	 * @throws InvalidInterfaceException
101
+	 * @throws InvalidDataTypeException
102
+	 * @throws DomainException
103
+	 * @throws DuplicateCollectionIdentifierException
104
+	 */
105
+	protected function getPersistentAdminNoticeCollection()
106
+	{
107
+		if (! $this->notice_collection instanceof Collection) {
108
+			$this->notice_collection = new Collection(
109
+				'EventEspresso\core\domain\entities\notifications\PersistentAdminNotice'
110
+			);
111
+			$this->retrieveStoredNotices();
112
+			$this->registerNotices();
113
+		}
114
+		return $this->notice_collection;
115
+	}
116
+
117
+
118
+	/**
119
+	 * generates PersistentAdminNotice objects for all non-dismissed notices saved to the db
120
+	 *
121
+	 * @return void
122
+	 * @throws InvalidEntityException
123
+	 * @throws DomainException
124
+	 * @throws InvalidDataTypeException
125
+	 * @throws DuplicateCollectionIdentifierException
126
+	 */
127
+	protected function retrieveStoredNotices()
128
+	{
129
+		$persistent_admin_notices = get_option(PersistentAdminNoticeManager::WP_OPTION_KEY, array());
130
+		if (! empty($persistent_admin_notices)) {
131
+			foreach ($persistent_admin_notices as $name => $details) {
132
+				if (is_array($details)) {
133
+					if (
134
+						! isset(
135
+							$details['message'],
136
+							$details['capability'],
137
+							$details['cap_context'],
138
+							$details['dismissed']
139
+						)
140
+					) {
141
+						throw new DomainException(
142
+							sprintf(
143
+								esc_html__(
144
+									'The "%1$s" PersistentAdminNotice could not be retrieved from the database.',
145
+									'event_espresso'
146
+								),
147
+								$name
148
+							)
149
+						);
150
+					}
151
+					// new format for nag notices
152
+					$this->notice_collection->add(
153
+						new PersistentAdminNotice(
154
+							$name,
155
+							$details['message'],
156
+							false,
157
+							$details['capability'],
158
+							$details['cap_context'],
159
+							$details['dismissed']
160
+						),
161
+						sanitize_key($name)
162
+					);
163
+				} else {
164
+					try {
165
+						// old nag notices, that we want to convert to the new format
166
+						$this->notice_collection->add(
167
+							new PersistentAdminNotice(
168
+								$name,
169
+								(string) $details,
170
+								false,
171
+								'',
172
+								'',
173
+								empty($details)
174
+							),
175
+							sanitize_key($name)
176
+						);
177
+					} catch (Exception $e) {
178
+						EE_Error::add_error($e->getMessage(), __FILE__, __FUNCTION__, __LINE__);
179
+					}
180
+				}
181
+				// each notice will self register when the action hook in registerNotices is triggered
182
+			}
183
+		}
184
+	}
185
+
186
+
187
+	/**
188
+	 * exposes the Persistent Admin Notice Collection via an action
189
+	 * so that PersistentAdminNotice objects can be added and/or removed
190
+	 * without compromising the actual collection like a filter would
191
+	 */
192
+	protected function registerNotices()
193
+	{
194
+		do_action(
195
+			'AHEE__EventEspresso_core_services_notifications_PersistentAdminNoticeManager__registerNotices',
196
+			$this->notice_collection
197
+		);
198
+	}
199
+
200
+
201
+	/**
202
+	 * @throws DomainException
203
+	 * @throws InvalidClassException
204
+	 * @throws InvalidDataTypeException
205
+	 * @throws InvalidInterfaceException
206
+	 * @throws InvalidEntityException
207
+	 * @throws DuplicateCollectionIdentifierException
208
+	 */
209
+	public function displayNotices()
210
+	{
211
+		$this->notice_collection = $this->getPersistentAdminNoticeCollection();
212
+		if ($this->notice_collection->hasObjects()) {
213
+			$enqueue_assets = false;
214
+			// and display notices
215
+			foreach ($this->notice_collection as $persistent_admin_notice) {
216
+				/** @var PersistentAdminNotice $persistent_admin_notice */
217
+				// don't display notices that have already been dismissed
218
+				if ($persistent_admin_notice->getDismissed()) {
219
+					continue;
220
+				}
221
+				try {
222
+					$this->capabilities_checker->processCapCheck(
223
+						$persistent_admin_notice->getCapCheck()
224
+					);
225
+				} catch (InsufficientPermissionsException $e) {
226
+					// user does not have required cap, so skip to next notice
227
+					// and just eat the exception - nom nom nom nom
228
+					continue;
229
+				}
230
+				if ($persistent_admin_notice->getMessage() === '') {
231
+					continue;
232
+				}
233
+				$this->displayPersistentAdminNotice($persistent_admin_notice);
234
+				$enqueue_assets = true;
235
+			}
236
+			if ($enqueue_assets) {
237
+				$this->enqueueAssets();
238
+			}
239
+		}
240
+	}
241
+
242
+
243
+	/**
244
+	 * does what it's named
245
+	 *
246
+	 * @return void
247
+	 */
248
+	public function enqueueAssets()
249
+	{
250
+		wp_register_script(
251
+			'espresso_core',
252
+			EE_GLOBAL_ASSETS_URL . 'scripts/espresso_core.js',
253
+			array('jquery'),
254
+			EVENT_ESPRESSO_VERSION,
255
+			true
256
+		);
257
+		wp_register_script(
258
+			'ee_error_js',
259
+			EE_GLOBAL_ASSETS_URL . 'scripts/EE_Error.js',
260
+			array('espresso_core'),
261
+			EVENT_ESPRESSO_VERSION,
262
+			true
263
+		);
264
+		wp_localize_script(
265
+			'ee_error_js',
266
+			'ee_dismiss',
267
+			array(
268
+				'return_url'    => urlencode($this->return_url),
269
+				'ajax_url'      => WP_AJAX_URL,
270
+				'unknown_error' => wp_strip_all_tags(
271
+					__(
272
+						'An unknown error has occurred on the server while attempting to dismiss this notice.',
273
+						'event_espresso'
274
+					)
275
+				),
276
+			)
277
+		);
278
+		wp_enqueue_script('ee_error_js');
279
+	}
280
+
281
+
282
+	/**
283
+	 * displayPersistentAdminNoticeHtml
284
+	 *
285
+	 * @param  PersistentAdminNotice $persistent_admin_notice
286
+	 */
287
+	protected function displayPersistentAdminNotice(PersistentAdminNotice $persistent_admin_notice)
288
+	{
289
+		// used in template
290
+		$persistent_admin_notice_name = $persistent_admin_notice->getName();
291
+		$persistent_admin_notice_message = $persistent_admin_notice->getMessage();
292
+		require EE_TEMPLATES . '/notifications/persistent_admin_notice.template.php';
293
+	}
294
+
295
+
296
+	/**
297
+	 * dismissNotice
298
+	 *
299
+	 * @param string $pan_name the name, or key of the Persistent Admin Notice to be dismissed
300
+	 * @param bool   $purge    if true, then delete it from the db
301
+	 * @param bool   $return   forget all of this AJAX or redirect nonsense, and just return
302
+	 * @return void
303
+	 * @throws InvalidEntityException
304
+	 * @throws InvalidInterfaceException
305
+	 * @throws InvalidDataTypeException
306
+	 * @throws DomainException
307
+	 * @throws InvalidArgumentException
308
+	 * @throws InvalidArgumentException
309
+	 * @throws InvalidArgumentException
310
+	 * @throws InvalidArgumentException
311
+	 * @throws DuplicateCollectionIdentifierException
312
+	 */
313
+	public function dismissNotice($pan_name = '', $purge = false, $return = false)
314
+	{
315
+		$pan_name = $this->request->getRequestParam('ee_nag_notice', $pan_name);
316
+		$this->notice_collection = $this->getPersistentAdminNoticeCollection();
317
+		if (! empty($pan_name) && $this->notice_collection->has($pan_name)) {
318
+			/** @var PersistentAdminNotice $persistent_admin_notice */
319
+			$persistent_admin_notice = $this->notice_collection->get($pan_name);
320
+			$persistent_admin_notice->setDismissed(true);
321
+			$persistent_admin_notice->setPurge($purge);
322
+			$this->saveNotices();
323
+		}
324
+		if ($return) {
325
+			return;
326
+		}
327
+		if ($this->request->isAjax()) {
328
+			// grab any notices and concatenate into string
329
+			echo wp_json_encode(
330
+				array(
331
+					'errors' => implode('<br />', EE_Error::get_notices(false)),
332
+				)
333
+			);
334
+			exit();
335
+		}
336
+		// save errors to a transient to be displayed on next request (after redirect)
337
+		EE_Error::get_notices(false, true);
338
+		wp_safe_redirect(
339
+			urldecode(
340
+				$this->request->getRequestParam('return_url', '')
341
+			)
342
+		);
343
+	}
344
+
345
+
346
+	/**
347
+	 * saveNotices
348
+	 *
349
+	 * @throws DomainException
350
+	 * @throws InvalidDataTypeException
351
+	 * @throws InvalidInterfaceException
352
+	 * @throws InvalidEntityException
353
+	 * @throws DuplicateCollectionIdentifierException
354
+	 */
355
+	public function saveNotices()
356
+	{
357
+		$this->notice_collection = $this->getPersistentAdminNoticeCollection();
358
+		if ($this->notice_collection->hasObjects()) {
359
+			$persistent_admin_notices = get_option(PersistentAdminNoticeManager::WP_OPTION_KEY, array());
360
+			// maybe initialize persistent_admin_notices
361
+			if (empty($persistent_admin_notices)) {
362
+				add_option(PersistentAdminNoticeManager::WP_OPTION_KEY, array(), '', 'no');
363
+			}
364
+			foreach ($this->notice_collection as $persistent_admin_notice) {
365
+				// are we deleting this notice ?
366
+				if ($persistent_admin_notice->getPurge()) {
367
+					unset($persistent_admin_notices[ $persistent_admin_notice->getName() ]);
368
+				} else {
369
+					/** @var PersistentAdminNotice $persistent_admin_notice */
370
+					$persistent_admin_notices[ $persistent_admin_notice->getName() ] = array(
371
+						'message'     => $persistent_admin_notice->getMessage(),
372
+						'capability'  => $persistent_admin_notice->getCapability(),
373
+						'cap_context' => $persistent_admin_notice->getCapContext(),
374
+						'dismissed'   => $persistent_admin_notice->getDismissed(),
375
+					);
376
+				}
377
+			}
378
+			update_option(PersistentAdminNoticeManager::WP_OPTION_KEY, $persistent_admin_notices);
379
+		}
380
+	}
381
+
382
+
383
+	/**
384
+	 * @throws DomainException
385
+	 * @throws InvalidDataTypeException
386
+	 * @throws InvalidEntityException
387
+	 * @throws InvalidInterfaceException
388
+	 * @throws DuplicateCollectionIdentifierException
389
+	 */
390
+	public function registerAndSaveNotices()
391
+	{
392
+		$this->getPersistentAdminNoticeCollection();
393
+		$this->registerNotices();
394
+		$this->saveNotices();
395
+		add_filter(
396
+			'PersistentAdminNoticeManager__registerAndSaveNotices__complete',
397
+			'__return_true'
398
+		);
399
+	}
400
+
401
+
402
+	/**
403
+	 * @throws DomainException
404
+	 * @throws InvalidDataTypeException
405
+	 * @throws InvalidEntityException
406
+	 * @throws InvalidInterfaceException
407
+	 * @throws InvalidArgumentException
408
+	 * @throws DuplicateCollectionIdentifierException
409
+	 */
410
+	public static function loadRegisterAndSaveNotices()
411
+	{
412
+		/** @var PersistentAdminNoticeManager $persistent_admin_notice_manager */
413
+		$persistent_admin_notice_manager = LoaderFactory::getLoader()->getShared(
414
+			'EventEspresso\core\services\notifications\PersistentAdminNoticeManager'
415
+		);
416
+		// if shutdown has already run, then call registerAndSaveNotices() manually
417
+		if (did_action('shutdown')) {
418
+			$persistent_admin_notice_manager->registerAndSaveNotices();
419
+		}
420
+	}
421 421
 }
Please login to merge, or discard this patch.
core/services/request/sanitizers/AllowedTags.php 1 patch
Indentation   +224 added lines, -224 removed lines patch added patch discarded remove patch
@@ -12,228 +12,228 @@
 block discarded – undo
12 12
  */
13 13
 class AllowedTags
14 14
 {
15
-    /**
16
-     * @var array[]
17
-     */
18
-    private static $attributes = [
19
-        'accept-charset'    => 1,
20
-        'action'            => 1,
21
-        'alt'               => 1,
22
-        'allow'             => 1,
23
-        'allowfullscreen'   => 1,
24
-        'align'             => 1,
25
-        'aria-*'            => 1,
26
-        'autocomplete'      => 1,
27
-        'checked'           => 1,
28
-        'class'             => 1,
29
-        'cols'              => 1,
30
-        'content'           => 1,
31
-        'data-*'            => 1,
32
-        'dir'               => 1,
33
-        'disabled'          => 1,
34
-        'enctype'           => 1,
35
-        'for'               => 1,
36
-        'frameborder'       => 1,
37
-        'height'            => 1,
38
-        'href'              => 1,
39
-        'id'                => 1,
40
-        'itemprop'          => 1,
41
-        'itemscope'         => 1,
42
-        'itemtype'          => 1,
43
-        'label'             => 1,
44
-        'lang'              => 1,
45
-        'max'               => 1,
46
-        'maxlength'         => 1,
47
-        'method'            => 1,
48
-        'min'               => 1,
49
-        'multiple'          => 1,
50
-        'name'              => 1,
51
-        'novalidate'        => 1,
52
-        'placeholder'       => 1,
53
-        'readonly'          => 1,
54
-        'rel'               => 1,
55
-        'required'          => 1,
56
-        'rows'              => 1,
57
-        'selected'          => 1,
58
-        'src'               => 1,
59
-        'size'              => 1,
60
-        'style'             => 1,
61
-        'step'              => 1,
62
-        'tabindex'          => 1,
63
-        'target'            => 1,
64
-        'title'             => 1,
65
-        'type'              => 1,
66
-        'value'             => 1,
67
-        'width'             => 1,
68
-    ];
69
-
70
-
71
-    /**
72
-     * @var array
73
-     */
74
-    private static $tags = [
75
-        'a',
76
-        'abbr',
77
-        'b',
78
-        'br',
79
-        'code',
80
-        'div',
81
-        'em',
82
-        'h1',
83
-        'h2',
84
-        'h3',
85
-        'h4',
86
-        'h5',
87
-        'h6',
88
-        'hr',
89
-        'i',
90
-        'img',
91
-        'li',
92
-        'ol',
93
-        'p',
94
-        'pre',
95
-        'small',
96
-        'span',
97
-        'strong',
98
-        'table',
99
-        'td',
100
-        'tr',
101
-        'ul',
102
-    ];
103
-
104
-
105
-    /**
106
-     * @var array
107
-     */
108
-    private static $allowed_tags;
109
-
110
-
111
-    /**
112
-     * @var array
113
-     */
114
-    private static $allowed_with_embed_tags;
115
-
116
-
117
-    /**
118
-     * @var array
119
-     */
120
-    private static $allowed_with_form_tags;
121
-
122
-
123
-    /**
124
-     * @var array
125
-     */
126
-    private static $allowed_with_script_and_style_tags;
127
-
128
-
129
-    /**
130
-     * merges additional tags and attributes into the WP post tags
131
-     */
132
-    private static function initializeAllowedTags()
133
-    {
134
-        $allowed_post_tags = wp_kses_allowed_html('post');
135
-        $allowed_tags = [];
136
-        foreach (AllowedTags::$tags as $tag) {
137
-            $allowed_tags[ $tag ] = AllowedTags::$attributes;
138
-        }
139
-        AllowedTags::$allowed_tags = array_merge_recursive($allowed_post_tags, $allowed_tags);
140
-    }
141
-
142
-
143
-    /**
144
-     * merges embed tags and attributes into the EE all tags
145
-     */
146
-    private static function initializeWithEmbedTags()
147
-    {
148
-        $all_tags = AllowedTags::getAllowedTags();
149
-        $embed_tags = [
150
-            'iframe' => AllowedTags::$attributes
151
-        ];
152
-        AllowedTags::$allowed_with_embed_tags = array_merge_recursive($all_tags, $embed_tags);
153
-    }
154
-
155
-
156
-    /**
157
-     * merges form tags and attributes into the EE all tags
158
-     */
159
-    private static function initializeWithFormTags()
160
-    {
161
-        $all_tags = AllowedTags::getAllowedTags();
162
-        $form_tags = [
163
-            'form' => AllowedTags::$attributes,
164
-            'label' => AllowedTags::$attributes,
165
-            'input' => AllowedTags::$attributes,
166
-            'select' => AllowedTags::$attributes,
167
-            'option' => AllowedTags::$attributes,
168
-            'optgroup' => AllowedTags::$attributes,
169
-            'textarea' => AllowedTags::$attributes,
170
-            'button' => AllowedTags::$attributes,
171
-            'fieldset' => AllowedTags::$attributes,
172
-            'output' => AllowedTags::$attributes,
173
-        ];
174
-        AllowedTags::$allowed_with_form_tags = array_merge_recursive($all_tags, $form_tags);
175
-    }
176
-
177
-
178
-    /**
179
-     * merges form script and style tags and attributes into the EE all tags
180
-     */
181
-    private static function initializeWithScriptAndStyleTags()
182
-    {
183
-        $all_tags = AllowedTags::getAllowedTags();
184
-        $script_and_style_tags = [
185
-            'script' => AllowedTags::$attributes,
186
-            'style' => AllowedTags::$attributes,
187
-            'link' => AllowedTags::$attributes,
188
-        ];
189
-        AllowedTags::$allowed_with_script_and_style_tags = array_merge_recursive($all_tags, $script_and_style_tags);
190
-    }
191
-
192
-
193
-    /**
194
-     * @return array[]
195
-     */
196
-    public static function getAllowedTags()
197
-    {
198
-        if (empty(AllowedTags::$allowed_tags)) {
199
-            AllowedTags::initializeAllowedTags();
200
-        }
201
-        return AllowedTags::$allowed_tags;
202
-    }
203
-
204
-
205
-    /**
206
-     * @return array[]
207
-     */
208
-    public static function getWithEmbedTags()
209
-    {
210
-        if (empty(AllowedTags::$allowed_with_embed_tags)) {
211
-            AllowedTags::initializeWithEmbedTags();
212
-        }
213
-        return AllowedTags::$allowed_with_embed_tags;
214
-    }
215
-
216
-
217
-    /**
218
-     * @return array[]
219
-     */
220
-    public static function getWithFormTags()
221
-    {
222
-        if (empty(AllowedTags::$allowed_with_form_tags)) {
223
-            AllowedTags::initializeWithFormTags();
224
-        }
225
-        return AllowedTags::$allowed_with_form_tags;
226
-    }
227
-
228
-
229
-    /**
230
-     * @return array[]
231
-     */
232
-    public static function getWithScriptAndStyleTags()
233
-    {
234
-        if (empty(AllowedTags::$allowed_with_script_and_style_tags)) {
235
-            AllowedTags::initializeWithScriptAndStyleTags();
236
-        }
237
-        return AllowedTags::$allowed_with_script_and_style_tags;
238
-    }
15
+	/**
16
+	 * @var array[]
17
+	 */
18
+	private static $attributes = [
19
+		'accept-charset'    => 1,
20
+		'action'            => 1,
21
+		'alt'               => 1,
22
+		'allow'             => 1,
23
+		'allowfullscreen'   => 1,
24
+		'align'             => 1,
25
+		'aria-*'            => 1,
26
+		'autocomplete'      => 1,
27
+		'checked'           => 1,
28
+		'class'             => 1,
29
+		'cols'              => 1,
30
+		'content'           => 1,
31
+		'data-*'            => 1,
32
+		'dir'               => 1,
33
+		'disabled'          => 1,
34
+		'enctype'           => 1,
35
+		'for'               => 1,
36
+		'frameborder'       => 1,
37
+		'height'            => 1,
38
+		'href'              => 1,
39
+		'id'                => 1,
40
+		'itemprop'          => 1,
41
+		'itemscope'         => 1,
42
+		'itemtype'          => 1,
43
+		'label'             => 1,
44
+		'lang'              => 1,
45
+		'max'               => 1,
46
+		'maxlength'         => 1,
47
+		'method'            => 1,
48
+		'min'               => 1,
49
+		'multiple'          => 1,
50
+		'name'              => 1,
51
+		'novalidate'        => 1,
52
+		'placeholder'       => 1,
53
+		'readonly'          => 1,
54
+		'rel'               => 1,
55
+		'required'          => 1,
56
+		'rows'              => 1,
57
+		'selected'          => 1,
58
+		'src'               => 1,
59
+		'size'              => 1,
60
+		'style'             => 1,
61
+		'step'              => 1,
62
+		'tabindex'          => 1,
63
+		'target'            => 1,
64
+		'title'             => 1,
65
+		'type'              => 1,
66
+		'value'             => 1,
67
+		'width'             => 1,
68
+	];
69
+
70
+
71
+	/**
72
+	 * @var array
73
+	 */
74
+	private static $tags = [
75
+		'a',
76
+		'abbr',
77
+		'b',
78
+		'br',
79
+		'code',
80
+		'div',
81
+		'em',
82
+		'h1',
83
+		'h2',
84
+		'h3',
85
+		'h4',
86
+		'h5',
87
+		'h6',
88
+		'hr',
89
+		'i',
90
+		'img',
91
+		'li',
92
+		'ol',
93
+		'p',
94
+		'pre',
95
+		'small',
96
+		'span',
97
+		'strong',
98
+		'table',
99
+		'td',
100
+		'tr',
101
+		'ul',
102
+	];
103
+
104
+
105
+	/**
106
+	 * @var array
107
+	 */
108
+	private static $allowed_tags;
109
+
110
+
111
+	/**
112
+	 * @var array
113
+	 */
114
+	private static $allowed_with_embed_tags;
115
+
116
+
117
+	/**
118
+	 * @var array
119
+	 */
120
+	private static $allowed_with_form_tags;
121
+
122
+
123
+	/**
124
+	 * @var array
125
+	 */
126
+	private static $allowed_with_script_and_style_tags;
127
+
128
+
129
+	/**
130
+	 * merges additional tags and attributes into the WP post tags
131
+	 */
132
+	private static function initializeAllowedTags()
133
+	{
134
+		$allowed_post_tags = wp_kses_allowed_html('post');
135
+		$allowed_tags = [];
136
+		foreach (AllowedTags::$tags as $tag) {
137
+			$allowed_tags[ $tag ] = AllowedTags::$attributes;
138
+		}
139
+		AllowedTags::$allowed_tags = array_merge_recursive($allowed_post_tags, $allowed_tags);
140
+	}
141
+
142
+
143
+	/**
144
+	 * merges embed tags and attributes into the EE all tags
145
+	 */
146
+	private static function initializeWithEmbedTags()
147
+	{
148
+		$all_tags = AllowedTags::getAllowedTags();
149
+		$embed_tags = [
150
+			'iframe' => AllowedTags::$attributes
151
+		];
152
+		AllowedTags::$allowed_with_embed_tags = array_merge_recursive($all_tags, $embed_tags);
153
+	}
154
+
155
+
156
+	/**
157
+	 * merges form tags and attributes into the EE all tags
158
+	 */
159
+	private static function initializeWithFormTags()
160
+	{
161
+		$all_tags = AllowedTags::getAllowedTags();
162
+		$form_tags = [
163
+			'form' => AllowedTags::$attributes,
164
+			'label' => AllowedTags::$attributes,
165
+			'input' => AllowedTags::$attributes,
166
+			'select' => AllowedTags::$attributes,
167
+			'option' => AllowedTags::$attributes,
168
+			'optgroup' => AllowedTags::$attributes,
169
+			'textarea' => AllowedTags::$attributes,
170
+			'button' => AllowedTags::$attributes,
171
+			'fieldset' => AllowedTags::$attributes,
172
+			'output' => AllowedTags::$attributes,
173
+		];
174
+		AllowedTags::$allowed_with_form_tags = array_merge_recursive($all_tags, $form_tags);
175
+	}
176
+
177
+
178
+	/**
179
+	 * merges form script and style tags and attributes into the EE all tags
180
+	 */
181
+	private static function initializeWithScriptAndStyleTags()
182
+	{
183
+		$all_tags = AllowedTags::getAllowedTags();
184
+		$script_and_style_tags = [
185
+			'script' => AllowedTags::$attributes,
186
+			'style' => AllowedTags::$attributes,
187
+			'link' => AllowedTags::$attributes,
188
+		];
189
+		AllowedTags::$allowed_with_script_and_style_tags = array_merge_recursive($all_tags, $script_and_style_tags);
190
+	}
191
+
192
+
193
+	/**
194
+	 * @return array[]
195
+	 */
196
+	public static function getAllowedTags()
197
+	{
198
+		if (empty(AllowedTags::$allowed_tags)) {
199
+			AllowedTags::initializeAllowedTags();
200
+		}
201
+		return AllowedTags::$allowed_tags;
202
+	}
203
+
204
+
205
+	/**
206
+	 * @return array[]
207
+	 */
208
+	public static function getWithEmbedTags()
209
+	{
210
+		if (empty(AllowedTags::$allowed_with_embed_tags)) {
211
+			AllowedTags::initializeWithEmbedTags();
212
+		}
213
+		return AllowedTags::$allowed_with_embed_tags;
214
+	}
215
+
216
+
217
+	/**
218
+	 * @return array[]
219
+	 */
220
+	public static function getWithFormTags()
221
+	{
222
+		if (empty(AllowedTags::$allowed_with_form_tags)) {
223
+			AllowedTags::initializeWithFormTags();
224
+		}
225
+		return AllowedTags::$allowed_with_form_tags;
226
+	}
227
+
228
+
229
+	/**
230
+	 * @return array[]
231
+	 */
232
+	public static function getWithScriptAndStyleTags()
233
+	{
234
+		if (empty(AllowedTags::$allowed_with_script_and_style_tags)) {
235
+			AllowedTags::initializeWithScriptAndStyleTags();
236
+		}
237
+		return AllowedTags::$allowed_with_script_and_style_tags;
238
+	}
239 239
 }
Please login to merge, or discard this patch.
core/helpers/EEH_Debug_Tools.helper.php 1 patch
Indentation   +714 added lines, -714 removed lines patch added patch discarded remove patch
@@ -15,709 +15,709 @@  discard block
 block discarded – undo
15 15
  */
16 16
 class EEH_Debug_Tools
17 17
 {
18
-    /**
19
-     *    instance of the EEH_Autoloader object
20
-     *
21
-     * @var    $_instance
22
-     * @access    private
23
-     */
24
-    private static $_instance;
25
-
26
-    /**
27
-     * @var array
28
-     */
29
-    protected $_memory_usage_points = array();
30
-
31
-
32
-
33
-    /**
34
-     * @singleton method used to instantiate class object
35
-     * @access    public
36
-     * @return EEH_Debug_Tools
37
-     */
38
-    public static function instance()
39
-    {
40
-        // check if class object is instantiated, and instantiated properly
41
-        if (! self::$_instance instanceof EEH_Debug_Tools) {
42
-            self::$_instance = new self();
43
-        }
44
-        return self::$_instance;
45
-    }
46
-
47
-
48
-
49
-    /**
50
-     * private class constructor
51
-     */
52
-    private function __construct()
53
-    {
54
-        // load Kint PHP debugging library
55
-        if (
56
-            defined('EE_LOAD_KINT')
57
-            && ! class_exists('Kint')
58
-            && file_exists(EE_PLUGIN_DIR_PATH . 'tests/kint/Kint.class.php')
59
-        ) {
60
-            // despite EE4 having a check for an existing copy of the Kint debugging class,
61
-            // if another plugin was loaded AFTER EE4 and they did NOT perform a similar check,
62
-            // then hilarity would ensue as PHP throws a "Cannot redeclare class Kint" error
63
-            // so we've moved it to our test folder so that it is not included with production releases
64
-            // plz use https://wordpress.org/plugins/kint-debugger/  if testing production versions of EE
65
-            require_once(EE_PLUGIN_DIR_PATH . 'tests/kint/Kint.class.php');
66
-        }
67
-        $plugin = basename(EE_PLUGIN_DIR_PATH);
68
-        add_action("activate_{$plugin}", array('EEH_Debug_Tools', 'ee_plugin_activation_errors'));
69
-        add_action('activated_plugin', array('EEH_Debug_Tools', 'ee_plugin_activation_errors'));
70
-        add_action('shutdown', array('EEH_Debug_Tools', 'show_db_name'));
71
-    }
72
-
73
-
74
-
75
-    /**
76
-     *    show_db_name
77
-     *
78
-     * @return void
79
-     */
80
-    public static function show_db_name()
81
-    {
82
-        if (! defined('DOING_AJAX') && (defined('EE_ERROR_EMAILS') && EE_ERROR_EMAILS)) {
83
-            echo '<p style="font-size:10px;font-weight:normal;color:#E76700;margin: 1em 2em; text-align: right;">DB_NAME: '
84
-                 . DB_NAME
85
-                 . '</p>';
86
-        }
87
-        if (EE_DEBUG) {
88
-            Benchmark::displayResults();
89
-        }
90
-    }
91
-
92
-
93
-
94
-    /**
95
-     *    dump EE_Session object at bottom of page after everything else has happened
96
-     *
97
-     * @return void
98
-     */
99
-    public function espresso_session_footer_dump()
100
-    {
101
-        if (
102
-            (defined('WP_DEBUG') && WP_DEBUG)
103
-            && ! defined('DOING_AJAX')
104
-            && class_exists('Kint')
105
-            && function_exists('wp_get_current_user')
106
-            && current_user_can('update_core')
107
-            && class_exists('EE_Registry')
108
-        ) {
109
-            Kint::dump(EE_Registry::instance()->SSN->id());
110
-            Kint::dump(EE_Registry::instance()->SSN);
111
-            //          Kint::dump( EE_Registry::instance()->SSN->get_session_data('cart')->get_tickets() );
112
-            $this->espresso_list_hooked_functions();
113
-            Benchmark::displayResults();
114
-        }
115
-    }
116
-
117
-
118
-
119
-    /**
120
-     *    List All Hooked Functions
121
-     *    to list all functions for a specific hook, add ee_list_hooks={hook-name} to URL
122
-     *    http://wp.smashingmagazine.com/2009/08/18/10-useful-wordpress-hook-hacks/
123
-     *
124
-     * @param string $tag
125
-     * @return void
126
-     */
127
-    public function espresso_list_hooked_functions($tag = '')
128
-    {
129
-        global $wp_filter;
130
-        echo '<br/><br/><br/><h3>Hooked Functions</h3>';
131
-        if ($tag) {
132
-            $hook[ $tag ] = $wp_filter[ $tag ];
133
-            if (! is_array($hook[ $tag ])) {
134
-                trigger_error("Nothing found for '$tag' hook", E_USER_WARNING);
135
-                return;
136
-            }
137
-            echo '<h5>For Tag: ' . esc_html($tag) . '</h5>';
138
-        } else {
139
-            $hook = is_array($wp_filter) ? $wp_filter : array($wp_filter);
140
-            ksort($hook);
141
-        }
142
-        foreach ($hook as $tag_name => $priorities) {
143
-            echo "<br />&gt;&gt;&gt;&gt;&gt;\t<strong>esc_html($tag_name)</strong><br />";
144
-            ksort($priorities);
145
-            foreach ($priorities as $priority => $function) {
146
-                echo esc_html($priority);
147
-                foreach ($function as $name => $properties) {
148
-                    $name = esc_html($name);
149
-                    echo "\t$name<br />";
150
-                }
151
-            }
152
-        }
153
-    }
154
-
155
-
156
-
157
-    /**
158
-     *    registered_filter_callbacks
159
-     *
160
-     * @param string $hook_name
161
-     * @return array
162
-     */
163
-    public static function registered_filter_callbacks($hook_name = '')
164
-    {
165
-        $filters = array();
166
-        global $wp_filter;
167
-        if (isset($wp_filter[ $hook_name ])) {
168
-            $filters[ $hook_name ] = array();
169
-            foreach ($wp_filter[ $hook_name ] as $priority => $callbacks) {
170
-                $filters[ $hook_name ][ $priority ] = array();
171
-                foreach ($callbacks as $callback) {
172
-                    $filters[ $hook_name ][ $priority ][] = $callback['function'];
173
-                }
174
-            }
175
-        }
176
-        return $filters;
177
-    }
178
-
179
-
180
-
181
-    /**
182
-     *    captures plugin activation errors for debugging
183
-     *
184
-     * @return void
185
-     * @throws EE_Error
186
-     */
187
-    public static function ee_plugin_activation_errors()
188
-    {
189
-        if (WP_DEBUG) {
190
-            $activation_errors = ob_get_contents();
191
-            if (empty($activation_errors)) {
192
-                return;
193
-            }
194
-            $activation_errors = date('Y-m-d H:i:s') . "\n" . $activation_errors;
195
-            espresso_load_required('EEH_File', EE_HELPERS . 'EEH_File.helper.php');
196
-            if (class_exists('EEH_File')) {
197
-                try {
198
-                    EEH_File::ensure_file_exists_and_is_writable(
199
-                        EVENT_ESPRESSO_UPLOAD_DIR . 'logs/espresso_plugin_activation_errors.html'
200
-                    );
201
-                    EEH_File::write_to_file(
202
-                        EVENT_ESPRESSO_UPLOAD_DIR . 'logs/espresso_plugin_activation_errors.html',
203
-                        $activation_errors
204
-                    );
205
-                } catch (EE_Error $e) {
206
-                    EE_Error::add_error(
207
-                        sprintf(
208
-                            esc_html__(
209
-                                'The Event Espresso activation errors file could not be setup because: %s',
210
-                                'event_espresso'
211
-                            ),
212
-                            $e->getMessage()
213
-                        ),
214
-                        __FILE__,
215
-                        __FUNCTION__,
216
-                        __LINE__
217
-                    );
218
-                }
219
-            } else {
220
-                // old school attempt
221
-                file_put_contents(
222
-                    EVENT_ESPRESSO_UPLOAD_DIR . 'logs/espresso_plugin_activation_errors.html',
223
-                    $activation_errors
224
-                );
225
-            }
226
-            $activation_errors = get_option('ee_plugin_activation_errors', '') . $activation_errors;
227
-            update_option('ee_plugin_activation_errors', $activation_errors);
228
-        }
229
-    }
230
-
231
-
232
-
233
-    /**
234
-     * This basically mimics the WordPress _doing_it_wrong() function except adds our own messaging etc.
235
-     * Very useful for providing helpful messages to developers when the method of doing something has been deprecated,
236
-     * or we want to make sure they use something the right way.
237
-     *
238
-     * @access public
239
-     * @param string $function      The function that was called
240
-     * @param string $message       A message explaining what has been done incorrectly
241
-     * @param string $version       The version of Event Espresso where the error was added
242
-     * @param string $applies_when  a version string for when you want the doing_it_wrong notice to begin appearing
243
-     *                              for a deprecated function. This allows deprecation to occur during one version,
244
-     *                              but not have any notices appear until a later version. This allows developers
245
-     *                              extra time to update their code before notices appear.
246
-     * @param int    $error_type
247
-     * @uses   trigger_error()
248
-     */
249
-    public function doing_it_wrong(
250
-        $function,
251
-        $message,
252
-        $version,
253
-        $applies_when = '',
254
-        $error_type = null
255
-    ) {
256
-        $applies_when = ! empty($applies_when) ? $applies_when : espresso_version();
257
-        $error_type = $error_type !== null ? $error_type : E_USER_NOTICE;
258
-        // because we swapped the parameter order around for the last two params,
259
-        // let's verify that some third party isn't still passing an error type value for the third param
260
-        if (is_int($applies_when)) {
261
-            $error_type = $applies_when;
262
-            $applies_when = espresso_version();
263
-        }
264
-        // if not displaying notices yet, then just leave
265
-        if (version_compare(espresso_version(), $applies_when, '<')) {
266
-            return;
267
-        }
268
-        do_action('AHEE__EEH_Debug_Tools__doing_it_wrong_run', $function, $message, $version);
269
-        $version = $version === null
270
-            ? ''
271
-            : sprintf(
272
-                esc_html__('(This message was added in version %s of Event Espresso)', 'event_espresso'),
273
-                $version
274
-            );
275
-        $error_message = sprintf(
276
-            esc_html__('%1$s was called %2$sincorrectly%3$s. %4$s %5$s', 'event_espresso'),
277
-            $function,
278
-            '<strong>',
279
-            '</strong>',
280
-            $message,
281
-            $version
282
-        );
283
-        // don't trigger error if doing ajax,
284
-        // instead we'll add a transient EE_Error notice that in theory should show on the next request.
285
-        if (defined('DOING_AJAX') && DOING_AJAX) {
286
-            $error_message .= ' ' . esc_html__(
287
-                'This is a doing_it_wrong message that was triggered during an ajax request.  The request params on this request were: ',
288
-                'event_espresso'
289
-            );
290
-            $request = LoaderFactory::getLoader()->getShared(RequestInterface::class);
291
-            $error_message .= '<ul><li>';
292
-            $error_message .= implode('</li><li>', $request->requestParams());
293
-            $error_message .= '</ul>';
294
-            EE_Error::add_error($error_message, 'debug::doing_it_wrong', $function, '42');
295
-            // now we set this on the transient so it shows up on the next request.
296
-            EE_Error::get_notices(false, true);
297
-        } else {
298
-            trigger_error($error_message, $error_type);
299
-        }
300
-    }
301
-
302
-
303
-
304
-
305
-    /**
306
-     * Logger helpers
307
-     */
308
-    /**
309
-     * debug
310
-     *
311
-     * @param string $class
312
-     * @param string $func
313
-     * @param string $line
314
-     * @param array  $info
315
-     * @param bool   $display_request
316
-     * @param string $debug_index
317
-     * @param string $debug_key
318
-     */
319
-    public static function log(
320
-        $class = '',
321
-        $func = '',
322
-        $line = '',
323
-        $info = array(),
324
-        $display_request = false,
325
-        $debug_index = '',
326
-        $debug_key = 'EE_DEBUG_SPCO'
327
-    ) {
328
-        if (WP_DEBUG) {
329
-            $debug_key = $debug_key . '_' . EE_Session::instance()->id();
330
-            $debug_data = get_option($debug_key, array());
331
-            $default_data = array(
332
-                $class => $func . '() : ' . $line,
333
-            );
334
-            // don't serialize objects
335
-            $info = self::strip_objects($info);
336
-            $index = ! empty($debug_index) ? $debug_index : 0;
337
-            if (! isset($debug_data[ $index ])) {
338
-                $debug_data[ $index ] = array();
339
-            }
340
-            $debug_data[ $index ][ microtime() ] = array_merge($default_data, $info);
341
-            update_option($debug_key, $debug_data);
342
-        }
343
-    }
344
-
345
-
346
-
347
-    /**
348
-     * strip_objects
349
-     *
350
-     * @param array $info
351
-     * @return array
352
-     */
353
-    public static function strip_objects($info = array())
354
-    {
355
-        foreach ($info as $key => $value) {
356
-            if (is_array($value)) {
357
-                $info[ $key ] = self::strip_objects($value);
358
-            } elseif (is_object($value)) {
359
-                $object_class = get_class($value);
360
-                $info[ $object_class ] = array();
361
-                $info[ $object_class ]['ID'] = method_exists($value, 'ID') ? $value->ID() : spl_object_hash($value);
362
-                if (method_exists($value, 'ID')) {
363
-                    $info[ $object_class ]['ID'] = $value->ID();
364
-                }
365
-                if (method_exists($value, 'status')) {
366
-                    $info[ $object_class ]['status'] = $value->status();
367
-                } elseif (method_exists($value, 'status_ID')) {
368
-                    $info[ $object_class ]['status'] = $value->status_ID();
369
-                }
370
-                unset($info[ $key ]);
371
-            }
372
-        }
373
-        return (array) $info;
374
-    }
375
-
376
-
377
-
378
-    /**
379
-     * @param mixed      $var
380
-     * @param string     $var_name
381
-     * @param string     $file
382
-     * @param int|string $line
383
-     * @param int|string $heading_tag
384
-     * @param bool       $die
385
-     * @param string     $margin
386
-     */
387
-    public static function printv(
388
-        $var,
389
-        $var_name = '',
390
-        $file = '',
391
-        $line = '',
392
-        $heading_tag = 5,
393
-        $die = false,
394
-        $margin = ''
395
-    ) {
396
-        $var_name = ! $var_name ? 'string' : $var_name;
397
-        $var_name = ucwords(str_replace('$', '', $var_name));
398
-        $is_method = method_exists($var_name, $var);
399
-        $var_name = ucwords(str_replace('_', ' ', $var_name));
400
-        $heading_tag = EEH_Debug_Tools::headingTag($heading_tag);
401
-        // $result = EEH_Debug_Tools::headingSpacer($heading_tag);
402
-        $result = EEH_Debug_Tools::heading($var_name, $heading_tag, $margin, $line);
403
-        $result .= $is_method
404
-            ? EEH_Debug_Tools::grey_span('::') . EEH_Debug_Tools::orange_span($var . '()')
405
-            : EEH_Debug_Tools::grey_span(' : ') . EEH_Debug_Tools::orange_span($var);
406
-        $result .= EEH_Debug_Tools::file_and_line($file, $line, $heading_tag);
407
-        $result .= EEH_Debug_Tools::headingX($heading_tag);
408
-        if ($die) {
409
-            die($result);
410
-        }
411
-        echo wp_kses($result, AllowedTags::getWithFormTags());
412
-    }
413
-
414
-
415
-    protected static function headingTag($heading_tag)
416
-    {
417
-        $heading_tag = absint($heading_tag);
418
-        return $heading_tag > 0 && $heading_tag < 7 ? "h{$heading_tag}" : 'h5';
419
-    }
420
-
421
-    protected static function headingSpacer($heading_tag)
422
-    {
423
-        return EEH_Debug_Tools::plainOutput() && ($heading_tag === 'h1' || $heading_tag === 'h2')
424
-            ? self::lineBreak()
425
-            : '';
426
-    }
427
-
428
-
429
-    protected static function plainOutput()
430
-    {
431
-        return defined('EE_TESTS_DIR')
432
-               || (defined('DOING_AJAX') && DOING_AJAX && ! isset($_REQUEST['pretty_output']))
433
-               || (
434
-                   isset($_SERVER['REQUEST_URI'])
435
-                   && strpos(parse_url($_SERVER['REQUEST_URI'], PHP_URL_PATH), 'wp-json') !== false
436
-               );
437
-    }
438
-
439
-
440
-    /**
441
-     * @param string $var_name
442
-     * @param string $heading_tag
443
-     * @param string $margin
444
-     * @param int    $line
445
-     * @return string
446
-     */
447
-    protected static function heading($var_name = '', $heading_tag = 'h5', $margin = '', $line = 0)
448
-    {
449
-        if (EEH_Debug_Tools::plainOutput()) {
450
-            switch ($heading_tag) {
451
-                case 'h1':
452
-                    $line_breaks = EEH_Debug_Tools::lineBreak(3);
453
-                    break;
454
-                case 'h2':
455
-                    $line_breaks = EEH_Debug_Tools::lineBreak(2);
456
-                    break;
457
-                default:
458
-                    $line_breaks = EEH_Debug_Tools::lineBreak();
459
-                    break;
460
-            }
461
-            return "{$line_breaks}{$line}) {$var_name}";
462
-        }
463
-        $margin = "25px 0 0 {$margin}";
464
-        return '<' . $heading_tag . ' style="color:#2EA2CC; margin:' . $margin . ';"><b>' . $var_name . '</b>';
465
-    }
466
-
467
-
468
-
469
-    /**
470
-     * @param string $heading_tag
471
-     * @return string
472
-     */
473
-    protected static function headingX($heading_tag = 'h5')
474
-    {
475
-        if (EEH_Debug_Tools::plainOutput()) {
476
-            return '';
477
-        }
478
-        return '</' . $heading_tag . '>';
479
-    }
480
-
481
-
482
-
483
-    /**
484
-     * @param string $content
485
-     * @return string
486
-     */
487
-    protected static function grey_span($content = '')
488
-    {
489
-        if (EEH_Debug_Tools::plainOutput()) {
490
-            return $content;
491
-        }
492
-        return '<span style="color:#999">' . $content . '</span>';
493
-    }
494
-
495
-
496
-
497
-    /**
498
-     * @param string $file
499
-     * @param int    $line
500
-     * @return string
501
-     */
502
-    protected static function file_and_line($file, $line, $heading_tag)
503
-    {
504
-        if ($file === '' || $line === '') {
505
-            return '';
506
-        }
507
-        $file = str_replace(EE_PLUGIN_DIR_PATH, '/', $file);
508
-        if (EEH_Debug_Tools::plainOutput()) {
509
-            if ($heading_tag === 'h1' || $heading_tag === 'h2') {
510
-                return " ({$file})" . EEH_Debug_Tools::lineBreak();
511
-            }
512
-            return '';
513
-        }
514
-        return EEH_Debug_Tools::lineBreak()
515
-               . '<span style="font-size:9px;font-weight:normal;color:#666;line-height: 12px;">'
516
-               . $file
517
-               . EEH_Debug_Tools::lineBreak()
518
-               . 'line no: '
519
-               . $line
520
-               . '</span>';
521
-    }
522
-
523
-
524
-
525
-    /**
526
-     * @param string $content
527
-     * @return string
528
-     */
529
-    protected static function orange_span($content = '')
530
-    {
531
-        if (EEH_Debug_Tools::plainOutput()) {
532
-            return $content;
533
-        }
534
-        return '<span style="color:#E76700">' . $content . '</span>';
535
-    }
536
-
537
-
538
-
539
-    /**
540
-     * @param mixed $var
541
-     * @return string
542
-     */
543
-    protected static function pre_span($var)
544
-    {
545
-        ob_start();
546
-        var_dump($var);
547
-        $var = ob_get_clean();
548
-        if (EEH_Debug_Tools::plainOutput()) {
549
-            return str_replace("\n", '', $var);
550
-        }
551
-        return '<pre style="color: #9C3; display: inline-block; padding:.4em .6em; background: #334">' . $var . '</pre>';
552
-    }
553
-
554
-
555
-
556
-    /**
557
-     * @param mixed      $var
558
-     * @param string     $var_name
559
-     * @param string     $file
560
-     * @param int|string $line
561
-     * @param int|string $heading_tag
562
-     * @param bool       $die
563
-     */
564
-    public static function printr(
565
-        $var,
566
-        $var_name = '',
567
-        $file = '',
568
-        $line = '',
569
-        $heading_tag = 5,
570
-        $die = false
571
-    ) {
572
-        // return;
573
-        $file = str_replace(rtrim(ABSPATH, '\\/'), '', $file);
574
-        if (empty($var) && empty($var_name)) {
575
-            $var = $file;
576
-            $var_name = "line $line";
577
-            $file = '';
578
-            $line = '';
579
-        }
580
-        $margin = is_admin() ? ' 180px' : '0';
581
-        if (is_string($var)) {
582
-            EEH_Debug_Tools::printv($var, $var_name, $file, $line, $heading_tag, $die, $margin);
583
-            return;
584
-        }
585
-        if (is_object($var)) {
586
-            $var_name = ! $var_name ? 'object' : $var_name;
587
-        } elseif (is_array($var)) {
588
-            $var_name = ! $var_name ? 'array' : $var_name;
589
-        } elseif (is_numeric($var)) {
590
-            $var_name = ! $var_name ? 'numeric' : $var_name;
591
-        } elseif ($var === null) {
592
-            $var_name = ! $var_name ? 'null' : $var_name;
593
-        }
594
-        $var_name = EEH_Debug_Tools::trimVarName($var_name);
595
-        $heading_tag = EEH_Debug_Tools::headingTag($heading_tag);
596
-        // $result = EEH_Debug_Tools::headingSpacer($heading_tag);
597
-        $result = EEH_Debug_Tools::heading($var_name, $heading_tag, $margin, $line);
598
-        $result .= EEH_Debug_Tools::grey_span(' : ') . EEH_Debug_Tools::orange_span(
599
-            EEH_Debug_Tools::pre_span($var)
600
-        );
601
-        $result .= EEH_Debug_Tools::file_and_line($file, $line, $heading_tag);
602
-        $result .= EEH_Debug_Tools::headingX($heading_tag);
603
-        if ($die) {
604
-            die($result);
605
-        }
606
-        echo wp_kses($result, AllowedTags::getWithFormTags());
607
-    }
608
-
609
-
610
-    private static function trimVarName($var_name): string
611
-    {
612
-        $converted = str_replace(['$', '_', 'this->'], ['', ' ', ''], $var_name);
613
-        $words = explode(' ', $converted);
614
-        $words = array_map(
615
-            function ($word) {
616
-                return $word === 'id' || $word === 'Id' ? 'ID' : $word;
617
-            },
618
-            $words
619
-        );
620
-        return ucwords(implode(' ', $words));
621
-    }
622
-
623
-
624
-    private static function lineBreak($lines = 1): string
625
-    {
626
-        $linebreak = defined('DOING_AJAX') && DOING_AJAX ? '<br />' : PHP_EOL;
627
-        return str_repeat($linebreak, $lines);
628
-    }
629
-
630
-
631
-    public static function shortClassName(string $fqcn): string
632
-    {
633
-        return substr(strrchr($fqcn, '\\'), 1);
634
-    }
635
-
636
-
637
-
638
-    /******************** deprecated ********************/
639
-
640
-
641
-
642
-    /**
643
-     * @deprecated 4.9.39.rc.034
644
-     */
645
-    public function reset_times()
646
-    {
647
-        Benchmark::resetTimes();
648
-    }
649
-
650
-
651
-
652
-    /**
653
-     * @deprecated 4.9.39.rc.034
654
-     * @param null $timer_name
655
-     */
656
-    public function start_timer($timer_name = null)
657
-    {
658
-        Benchmark::startTimer($timer_name);
659
-    }
660
-
661
-
662
-
663
-    /**
664
-     * @deprecated 4.9.39.rc.034
665
-     * @param string $timer_name
666
-     */
667
-    public function stop_timer($timer_name = '')
668
-    {
669
-        Benchmark::stopTimer($timer_name);
670
-    }
671
-
672
-
673
-
674
-    /**
675
-     * @deprecated 4.9.39.rc.034
676
-     * @param string  $label      The label to show for this time eg "Start of calling Some_Class::some_function"
677
-     * @param boolean $output_now whether to echo now, or wait until EEH_Debug_Tools::show_times() is called
678
-     * @return void
679
-     */
680
-    public function measure_memory($label, $output_now = false)
681
-    {
682
-        Benchmark::measureMemory($label, $output_now);
683
-    }
684
-
685
-
686
-
687
-    /**
688
-     * @deprecated 4.9.39.rc.034
689
-     * @param int $size
690
-     * @return string
691
-     */
692
-    public function convert($size)
693
-    {
694
-        return Benchmark::convert($size);
695
-    }
696
-
697
-
18
+	/**
19
+	 *    instance of the EEH_Autoloader object
20
+	 *
21
+	 * @var    $_instance
22
+	 * @access    private
23
+	 */
24
+	private static $_instance;
25
+
26
+	/**
27
+	 * @var array
28
+	 */
29
+	protected $_memory_usage_points = array();
30
+
31
+
32
+
33
+	/**
34
+	 * @singleton method used to instantiate class object
35
+	 * @access    public
36
+	 * @return EEH_Debug_Tools
37
+	 */
38
+	public static function instance()
39
+	{
40
+		// check if class object is instantiated, and instantiated properly
41
+		if (! self::$_instance instanceof EEH_Debug_Tools) {
42
+			self::$_instance = new self();
43
+		}
44
+		return self::$_instance;
45
+	}
46
+
47
+
48
+
49
+	/**
50
+	 * private class constructor
51
+	 */
52
+	private function __construct()
53
+	{
54
+		// load Kint PHP debugging library
55
+		if (
56
+			defined('EE_LOAD_KINT')
57
+			&& ! class_exists('Kint')
58
+			&& file_exists(EE_PLUGIN_DIR_PATH . 'tests/kint/Kint.class.php')
59
+		) {
60
+			// despite EE4 having a check for an existing copy of the Kint debugging class,
61
+			// if another plugin was loaded AFTER EE4 and they did NOT perform a similar check,
62
+			// then hilarity would ensue as PHP throws a "Cannot redeclare class Kint" error
63
+			// so we've moved it to our test folder so that it is not included with production releases
64
+			// plz use https://wordpress.org/plugins/kint-debugger/  if testing production versions of EE
65
+			require_once(EE_PLUGIN_DIR_PATH . 'tests/kint/Kint.class.php');
66
+		}
67
+		$plugin = basename(EE_PLUGIN_DIR_PATH);
68
+		add_action("activate_{$plugin}", array('EEH_Debug_Tools', 'ee_plugin_activation_errors'));
69
+		add_action('activated_plugin', array('EEH_Debug_Tools', 'ee_plugin_activation_errors'));
70
+		add_action('shutdown', array('EEH_Debug_Tools', 'show_db_name'));
71
+	}
72
+
73
+
74
+
75
+	/**
76
+	 *    show_db_name
77
+	 *
78
+	 * @return void
79
+	 */
80
+	public static function show_db_name()
81
+	{
82
+		if (! defined('DOING_AJAX') && (defined('EE_ERROR_EMAILS') && EE_ERROR_EMAILS)) {
83
+			echo '<p style="font-size:10px;font-weight:normal;color:#E76700;margin: 1em 2em; text-align: right;">DB_NAME: '
84
+				 . DB_NAME
85
+				 . '</p>';
86
+		}
87
+		if (EE_DEBUG) {
88
+			Benchmark::displayResults();
89
+		}
90
+	}
91
+
92
+
93
+
94
+	/**
95
+	 *    dump EE_Session object at bottom of page after everything else has happened
96
+	 *
97
+	 * @return void
98
+	 */
99
+	public function espresso_session_footer_dump()
100
+	{
101
+		if (
102
+			(defined('WP_DEBUG') && WP_DEBUG)
103
+			&& ! defined('DOING_AJAX')
104
+			&& class_exists('Kint')
105
+			&& function_exists('wp_get_current_user')
106
+			&& current_user_can('update_core')
107
+			&& class_exists('EE_Registry')
108
+		) {
109
+			Kint::dump(EE_Registry::instance()->SSN->id());
110
+			Kint::dump(EE_Registry::instance()->SSN);
111
+			//          Kint::dump( EE_Registry::instance()->SSN->get_session_data('cart')->get_tickets() );
112
+			$this->espresso_list_hooked_functions();
113
+			Benchmark::displayResults();
114
+		}
115
+	}
116
+
117
+
118
+
119
+	/**
120
+	 *    List All Hooked Functions
121
+	 *    to list all functions for a specific hook, add ee_list_hooks={hook-name} to URL
122
+	 *    http://wp.smashingmagazine.com/2009/08/18/10-useful-wordpress-hook-hacks/
123
+	 *
124
+	 * @param string $tag
125
+	 * @return void
126
+	 */
127
+	public function espresso_list_hooked_functions($tag = '')
128
+	{
129
+		global $wp_filter;
130
+		echo '<br/><br/><br/><h3>Hooked Functions</h3>';
131
+		if ($tag) {
132
+			$hook[ $tag ] = $wp_filter[ $tag ];
133
+			if (! is_array($hook[ $tag ])) {
134
+				trigger_error("Nothing found for '$tag' hook", E_USER_WARNING);
135
+				return;
136
+			}
137
+			echo '<h5>For Tag: ' . esc_html($tag) . '</h5>';
138
+		} else {
139
+			$hook = is_array($wp_filter) ? $wp_filter : array($wp_filter);
140
+			ksort($hook);
141
+		}
142
+		foreach ($hook as $tag_name => $priorities) {
143
+			echo "<br />&gt;&gt;&gt;&gt;&gt;\t<strong>esc_html($tag_name)</strong><br />";
144
+			ksort($priorities);
145
+			foreach ($priorities as $priority => $function) {
146
+				echo esc_html($priority);
147
+				foreach ($function as $name => $properties) {
148
+					$name = esc_html($name);
149
+					echo "\t$name<br />";
150
+				}
151
+			}
152
+		}
153
+	}
154
+
155
+
156
+
157
+	/**
158
+	 *    registered_filter_callbacks
159
+	 *
160
+	 * @param string $hook_name
161
+	 * @return array
162
+	 */
163
+	public static function registered_filter_callbacks($hook_name = '')
164
+	{
165
+		$filters = array();
166
+		global $wp_filter;
167
+		if (isset($wp_filter[ $hook_name ])) {
168
+			$filters[ $hook_name ] = array();
169
+			foreach ($wp_filter[ $hook_name ] as $priority => $callbacks) {
170
+				$filters[ $hook_name ][ $priority ] = array();
171
+				foreach ($callbacks as $callback) {
172
+					$filters[ $hook_name ][ $priority ][] = $callback['function'];
173
+				}
174
+			}
175
+		}
176
+		return $filters;
177
+	}
178
+
179
+
180
+
181
+	/**
182
+	 *    captures plugin activation errors for debugging
183
+	 *
184
+	 * @return void
185
+	 * @throws EE_Error
186
+	 */
187
+	public static function ee_plugin_activation_errors()
188
+	{
189
+		if (WP_DEBUG) {
190
+			$activation_errors = ob_get_contents();
191
+			if (empty($activation_errors)) {
192
+				return;
193
+			}
194
+			$activation_errors = date('Y-m-d H:i:s') . "\n" . $activation_errors;
195
+			espresso_load_required('EEH_File', EE_HELPERS . 'EEH_File.helper.php');
196
+			if (class_exists('EEH_File')) {
197
+				try {
198
+					EEH_File::ensure_file_exists_and_is_writable(
199
+						EVENT_ESPRESSO_UPLOAD_DIR . 'logs/espresso_plugin_activation_errors.html'
200
+					);
201
+					EEH_File::write_to_file(
202
+						EVENT_ESPRESSO_UPLOAD_DIR . 'logs/espresso_plugin_activation_errors.html',
203
+						$activation_errors
204
+					);
205
+				} catch (EE_Error $e) {
206
+					EE_Error::add_error(
207
+						sprintf(
208
+							esc_html__(
209
+								'The Event Espresso activation errors file could not be setup because: %s',
210
+								'event_espresso'
211
+							),
212
+							$e->getMessage()
213
+						),
214
+						__FILE__,
215
+						__FUNCTION__,
216
+						__LINE__
217
+					);
218
+				}
219
+			} else {
220
+				// old school attempt
221
+				file_put_contents(
222
+					EVENT_ESPRESSO_UPLOAD_DIR . 'logs/espresso_plugin_activation_errors.html',
223
+					$activation_errors
224
+				);
225
+			}
226
+			$activation_errors = get_option('ee_plugin_activation_errors', '') . $activation_errors;
227
+			update_option('ee_plugin_activation_errors', $activation_errors);
228
+		}
229
+	}
230
+
231
+
232
+
233
+	/**
234
+	 * This basically mimics the WordPress _doing_it_wrong() function except adds our own messaging etc.
235
+	 * Very useful for providing helpful messages to developers when the method of doing something has been deprecated,
236
+	 * or we want to make sure they use something the right way.
237
+	 *
238
+	 * @access public
239
+	 * @param string $function      The function that was called
240
+	 * @param string $message       A message explaining what has been done incorrectly
241
+	 * @param string $version       The version of Event Espresso where the error was added
242
+	 * @param string $applies_when  a version string for when you want the doing_it_wrong notice to begin appearing
243
+	 *                              for a deprecated function. This allows deprecation to occur during one version,
244
+	 *                              but not have any notices appear until a later version. This allows developers
245
+	 *                              extra time to update their code before notices appear.
246
+	 * @param int    $error_type
247
+	 * @uses   trigger_error()
248
+	 */
249
+	public function doing_it_wrong(
250
+		$function,
251
+		$message,
252
+		$version,
253
+		$applies_when = '',
254
+		$error_type = null
255
+	) {
256
+		$applies_when = ! empty($applies_when) ? $applies_when : espresso_version();
257
+		$error_type = $error_type !== null ? $error_type : E_USER_NOTICE;
258
+		// because we swapped the parameter order around for the last two params,
259
+		// let's verify that some third party isn't still passing an error type value for the third param
260
+		if (is_int($applies_when)) {
261
+			$error_type = $applies_when;
262
+			$applies_when = espresso_version();
263
+		}
264
+		// if not displaying notices yet, then just leave
265
+		if (version_compare(espresso_version(), $applies_when, '<')) {
266
+			return;
267
+		}
268
+		do_action('AHEE__EEH_Debug_Tools__doing_it_wrong_run', $function, $message, $version);
269
+		$version = $version === null
270
+			? ''
271
+			: sprintf(
272
+				esc_html__('(This message was added in version %s of Event Espresso)', 'event_espresso'),
273
+				$version
274
+			);
275
+		$error_message = sprintf(
276
+			esc_html__('%1$s was called %2$sincorrectly%3$s. %4$s %5$s', 'event_espresso'),
277
+			$function,
278
+			'<strong>',
279
+			'</strong>',
280
+			$message,
281
+			$version
282
+		);
283
+		// don't trigger error if doing ajax,
284
+		// instead we'll add a transient EE_Error notice that in theory should show on the next request.
285
+		if (defined('DOING_AJAX') && DOING_AJAX) {
286
+			$error_message .= ' ' . esc_html__(
287
+				'This is a doing_it_wrong message that was triggered during an ajax request.  The request params on this request were: ',
288
+				'event_espresso'
289
+			);
290
+			$request = LoaderFactory::getLoader()->getShared(RequestInterface::class);
291
+			$error_message .= '<ul><li>';
292
+			$error_message .= implode('</li><li>', $request->requestParams());
293
+			$error_message .= '</ul>';
294
+			EE_Error::add_error($error_message, 'debug::doing_it_wrong', $function, '42');
295
+			// now we set this on the transient so it shows up on the next request.
296
+			EE_Error::get_notices(false, true);
297
+		} else {
298
+			trigger_error($error_message, $error_type);
299
+		}
300
+	}
301
+
302
+
303
+
304
+
305
+	/**
306
+	 * Logger helpers
307
+	 */
308
+	/**
309
+	 * debug
310
+	 *
311
+	 * @param string $class
312
+	 * @param string $func
313
+	 * @param string $line
314
+	 * @param array  $info
315
+	 * @param bool   $display_request
316
+	 * @param string $debug_index
317
+	 * @param string $debug_key
318
+	 */
319
+	public static function log(
320
+		$class = '',
321
+		$func = '',
322
+		$line = '',
323
+		$info = array(),
324
+		$display_request = false,
325
+		$debug_index = '',
326
+		$debug_key = 'EE_DEBUG_SPCO'
327
+	) {
328
+		if (WP_DEBUG) {
329
+			$debug_key = $debug_key . '_' . EE_Session::instance()->id();
330
+			$debug_data = get_option($debug_key, array());
331
+			$default_data = array(
332
+				$class => $func . '() : ' . $line,
333
+			);
334
+			// don't serialize objects
335
+			$info = self::strip_objects($info);
336
+			$index = ! empty($debug_index) ? $debug_index : 0;
337
+			if (! isset($debug_data[ $index ])) {
338
+				$debug_data[ $index ] = array();
339
+			}
340
+			$debug_data[ $index ][ microtime() ] = array_merge($default_data, $info);
341
+			update_option($debug_key, $debug_data);
342
+		}
343
+	}
344
+
345
+
346
+
347
+	/**
348
+	 * strip_objects
349
+	 *
350
+	 * @param array $info
351
+	 * @return array
352
+	 */
353
+	public static function strip_objects($info = array())
354
+	{
355
+		foreach ($info as $key => $value) {
356
+			if (is_array($value)) {
357
+				$info[ $key ] = self::strip_objects($value);
358
+			} elseif (is_object($value)) {
359
+				$object_class = get_class($value);
360
+				$info[ $object_class ] = array();
361
+				$info[ $object_class ]['ID'] = method_exists($value, 'ID') ? $value->ID() : spl_object_hash($value);
362
+				if (method_exists($value, 'ID')) {
363
+					$info[ $object_class ]['ID'] = $value->ID();
364
+				}
365
+				if (method_exists($value, 'status')) {
366
+					$info[ $object_class ]['status'] = $value->status();
367
+				} elseif (method_exists($value, 'status_ID')) {
368
+					$info[ $object_class ]['status'] = $value->status_ID();
369
+				}
370
+				unset($info[ $key ]);
371
+			}
372
+		}
373
+		return (array) $info;
374
+	}
375
+
376
+
377
+
378
+	/**
379
+	 * @param mixed      $var
380
+	 * @param string     $var_name
381
+	 * @param string     $file
382
+	 * @param int|string $line
383
+	 * @param int|string $heading_tag
384
+	 * @param bool       $die
385
+	 * @param string     $margin
386
+	 */
387
+	public static function printv(
388
+		$var,
389
+		$var_name = '',
390
+		$file = '',
391
+		$line = '',
392
+		$heading_tag = 5,
393
+		$die = false,
394
+		$margin = ''
395
+	) {
396
+		$var_name = ! $var_name ? 'string' : $var_name;
397
+		$var_name = ucwords(str_replace('$', '', $var_name));
398
+		$is_method = method_exists($var_name, $var);
399
+		$var_name = ucwords(str_replace('_', ' ', $var_name));
400
+		$heading_tag = EEH_Debug_Tools::headingTag($heading_tag);
401
+		// $result = EEH_Debug_Tools::headingSpacer($heading_tag);
402
+		$result = EEH_Debug_Tools::heading($var_name, $heading_tag, $margin, $line);
403
+		$result .= $is_method
404
+			? EEH_Debug_Tools::grey_span('::') . EEH_Debug_Tools::orange_span($var . '()')
405
+			: EEH_Debug_Tools::grey_span(' : ') . EEH_Debug_Tools::orange_span($var);
406
+		$result .= EEH_Debug_Tools::file_and_line($file, $line, $heading_tag);
407
+		$result .= EEH_Debug_Tools::headingX($heading_tag);
408
+		if ($die) {
409
+			die($result);
410
+		}
411
+		echo wp_kses($result, AllowedTags::getWithFormTags());
412
+	}
413
+
414
+
415
+	protected static function headingTag($heading_tag)
416
+	{
417
+		$heading_tag = absint($heading_tag);
418
+		return $heading_tag > 0 && $heading_tag < 7 ? "h{$heading_tag}" : 'h5';
419
+	}
420
+
421
+	protected static function headingSpacer($heading_tag)
422
+	{
423
+		return EEH_Debug_Tools::plainOutput() && ($heading_tag === 'h1' || $heading_tag === 'h2')
424
+			? self::lineBreak()
425
+			: '';
426
+	}
427
+
428
+
429
+	protected static function plainOutput()
430
+	{
431
+		return defined('EE_TESTS_DIR')
432
+			   || (defined('DOING_AJAX') && DOING_AJAX && ! isset($_REQUEST['pretty_output']))
433
+			   || (
434
+				   isset($_SERVER['REQUEST_URI'])
435
+				   && strpos(parse_url($_SERVER['REQUEST_URI'], PHP_URL_PATH), 'wp-json') !== false
436
+			   );
437
+	}
438
+
439
+
440
+	/**
441
+	 * @param string $var_name
442
+	 * @param string $heading_tag
443
+	 * @param string $margin
444
+	 * @param int    $line
445
+	 * @return string
446
+	 */
447
+	protected static function heading($var_name = '', $heading_tag = 'h5', $margin = '', $line = 0)
448
+	{
449
+		if (EEH_Debug_Tools::plainOutput()) {
450
+			switch ($heading_tag) {
451
+				case 'h1':
452
+					$line_breaks = EEH_Debug_Tools::lineBreak(3);
453
+					break;
454
+				case 'h2':
455
+					$line_breaks = EEH_Debug_Tools::lineBreak(2);
456
+					break;
457
+				default:
458
+					$line_breaks = EEH_Debug_Tools::lineBreak();
459
+					break;
460
+			}
461
+			return "{$line_breaks}{$line}) {$var_name}";
462
+		}
463
+		$margin = "25px 0 0 {$margin}";
464
+		return '<' . $heading_tag . ' style="color:#2EA2CC; margin:' . $margin . ';"><b>' . $var_name . '</b>';
465
+	}
466
+
467
+
468
+
469
+	/**
470
+	 * @param string $heading_tag
471
+	 * @return string
472
+	 */
473
+	protected static function headingX($heading_tag = 'h5')
474
+	{
475
+		if (EEH_Debug_Tools::plainOutput()) {
476
+			return '';
477
+		}
478
+		return '</' . $heading_tag . '>';
479
+	}
480
+
481
+
482
+
483
+	/**
484
+	 * @param string $content
485
+	 * @return string
486
+	 */
487
+	protected static function grey_span($content = '')
488
+	{
489
+		if (EEH_Debug_Tools::plainOutput()) {
490
+			return $content;
491
+		}
492
+		return '<span style="color:#999">' . $content . '</span>';
493
+	}
494
+
495
+
496
+
497
+	/**
498
+	 * @param string $file
499
+	 * @param int    $line
500
+	 * @return string
501
+	 */
502
+	protected static function file_and_line($file, $line, $heading_tag)
503
+	{
504
+		if ($file === '' || $line === '') {
505
+			return '';
506
+		}
507
+		$file = str_replace(EE_PLUGIN_DIR_PATH, '/', $file);
508
+		if (EEH_Debug_Tools::plainOutput()) {
509
+			if ($heading_tag === 'h1' || $heading_tag === 'h2') {
510
+				return " ({$file})" . EEH_Debug_Tools::lineBreak();
511
+			}
512
+			return '';
513
+		}
514
+		return EEH_Debug_Tools::lineBreak()
515
+			   . '<span style="font-size:9px;font-weight:normal;color:#666;line-height: 12px;">'
516
+			   . $file
517
+			   . EEH_Debug_Tools::lineBreak()
518
+			   . 'line no: '
519
+			   . $line
520
+			   . '</span>';
521
+	}
522
+
523
+
524
+
525
+	/**
526
+	 * @param string $content
527
+	 * @return string
528
+	 */
529
+	protected static function orange_span($content = '')
530
+	{
531
+		if (EEH_Debug_Tools::plainOutput()) {
532
+			return $content;
533
+		}
534
+		return '<span style="color:#E76700">' . $content . '</span>';
535
+	}
536
+
537
+
538
+
539
+	/**
540
+	 * @param mixed $var
541
+	 * @return string
542
+	 */
543
+	protected static function pre_span($var)
544
+	{
545
+		ob_start();
546
+		var_dump($var);
547
+		$var = ob_get_clean();
548
+		if (EEH_Debug_Tools::plainOutput()) {
549
+			return str_replace("\n", '', $var);
550
+		}
551
+		return '<pre style="color: #9C3; display: inline-block; padding:.4em .6em; background: #334">' . $var . '</pre>';
552
+	}
553
+
554
+
555
+
556
+	/**
557
+	 * @param mixed      $var
558
+	 * @param string     $var_name
559
+	 * @param string     $file
560
+	 * @param int|string $line
561
+	 * @param int|string $heading_tag
562
+	 * @param bool       $die
563
+	 */
564
+	public static function printr(
565
+		$var,
566
+		$var_name = '',
567
+		$file = '',
568
+		$line = '',
569
+		$heading_tag = 5,
570
+		$die = false
571
+	) {
572
+		// return;
573
+		$file = str_replace(rtrim(ABSPATH, '\\/'), '', $file);
574
+		if (empty($var) && empty($var_name)) {
575
+			$var = $file;
576
+			$var_name = "line $line";
577
+			$file = '';
578
+			$line = '';
579
+		}
580
+		$margin = is_admin() ? ' 180px' : '0';
581
+		if (is_string($var)) {
582
+			EEH_Debug_Tools::printv($var, $var_name, $file, $line, $heading_tag, $die, $margin);
583
+			return;
584
+		}
585
+		if (is_object($var)) {
586
+			$var_name = ! $var_name ? 'object' : $var_name;
587
+		} elseif (is_array($var)) {
588
+			$var_name = ! $var_name ? 'array' : $var_name;
589
+		} elseif (is_numeric($var)) {
590
+			$var_name = ! $var_name ? 'numeric' : $var_name;
591
+		} elseif ($var === null) {
592
+			$var_name = ! $var_name ? 'null' : $var_name;
593
+		}
594
+		$var_name = EEH_Debug_Tools::trimVarName($var_name);
595
+		$heading_tag = EEH_Debug_Tools::headingTag($heading_tag);
596
+		// $result = EEH_Debug_Tools::headingSpacer($heading_tag);
597
+		$result = EEH_Debug_Tools::heading($var_name, $heading_tag, $margin, $line);
598
+		$result .= EEH_Debug_Tools::grey_span(' : ') . EEH_Debug_Tools::orange_span(
599
+			EEH_Debug_Tools::pre_span($var)
600
+		);
601
+		$result .= EEH_Debug_Tools::file_and_line($file, $line, $heading_tag);
602
+		$result .= EEH_Debug_Tools::headingX($heading_tag);
603
+		if ($die) {
604
+			die($result);
605
+		}
606
+		echo wp_kses($result, AllowedTags::getWithFormTags());
607
+	}
608
+
609
+
610
+	private static function trimVarName($var_name): string
611
+	{
612
+		$converted = str_replace(['$', '_', 'this->'], ['', ' ', ''], $var_name);
613
+		$words = explode(' ', $converted);
614
+		$words = array_map(
615
+			function ($word) {
616
+				return $word === 'id' || $word === 'Id' ? 'ID' : $word;
617
+			},
618
+			$words
619
+		);
620
+		return ucwords(implode(' ', $words));
621
+	}
622
+
623
+
624
+	private static function lineBreak($lines = 1): string
625
+	{
626
+		$linebreak = defined('DOING_AJAX') && DOING_AJAX ? '<br />' : PHP_EOL;
627
+		return str_repeat($linebreak, $lines);
628
+	}
629
+
630
+
631
+	public static function shortClassName(string $fqcn): string
632
+	{
633
+		return substr(strrchr($fqcn, '\\'), 1);
634
+	}
635
+
636
+
637
+
638
+	/******************** deprecated ********************/
639
+
640
+
641
+
642
+	/**
643
+	 * @deprecated 4.9.39.rc.034
644
+	 */
645
+	public function reset_times()
646
+	{
647
+		Benchmark::resetTimes();
648
+	}
649
+
650
+
651
+
652
+	/**
653
+	 * @deprecated 4.9.39.rc.034
654
+	 * @param null $timer_name
655
+	 */
656
+	public function start_timer($timer_name = null)
657
+	{
658
+		Benchmark::startTimer($timer_name);
659
+	}
660
+
661
+
662
+
663
+	/**
664
+	 * @deprecated 4.9.39.rc.034
665
+	 * @param string $timer_name
666
+	 */
667
+	public function stop_timer($timer_name = '')
668
+	{
669
+		Benchmark::stopTimer($timer_name);
670
+	}
671
+
672
+
673
+
674
+	/**
675
+	 * @deprecated 4.9.39.rc.034
676
+	 * @param string  $label      The label to show for this time eg "Start of calling Some_Class::some_function"
677
+	 * @param boolean $output_now whether to echo now, or wait until EEH_Debug_Tools::show_times() is called
678
+	 * @return void
679
+	 */
680
+	public function measure_memory($label, $output_now = false)
681
+	{
682
+		Benchmark::measureMemory($label, $output_now);
683
+	}
684
+
685
+
686
+
687
+	/**
688
+	 * @deprecated 4.9.39.rc.034
689
+	 * @param int $size
690
+	 * @return string
691
+	 */
692
+	public function convert($size)
693
+	{
694
+		return Benchmark::convert($size);
695
+	}
696
+
697
+
698 698
 
699
-    /**
700
-     * @deprecated 4.9.39.rc.034
701
-     * @param bool $output_now
702
-     * @return string
703
-     */
704
-    public function show_times($output_now = true)
705
-    {
706
-        return Benchmark::displayResults($output_now);
707
-    }
699
+	/**
700
+	 * @deprecated 4.9.39.rc.034
701
+	 * @param bool $output_now
702
+	 * @return string
703
+	 */
704
+	public function show_times($output_now = true)
705
+	{
706
+		return Benchmark::displayResults($output_now);
707
+	}
708 708
 
709 709
 
710 710
 
711
-    /**
712
-     * @deprecated 4.9.39.rc.034
713
-     * @param string $timer_name
714
-     * @param float  $total_time
715
-     * @return string
716
-     */
717
-    public function format_time($timer_name, $total_time)
718
-    {
719
-        return Benchmark::formatTime($timer_name, $total_time);
720
-    }
711
+	/**
712
+	 * @deprecated 4.9.39.rc.034
713
+	 * @param string $timer_name
714
+	 * @param float  $total_time
715
+	 * @return string
716
+	 */
717
+	public function format_time($timer_name, $total_time)
718
+	{
719
+		return Benchmark::formatTime($timer_name, $total_time);
720
+	}
721 721
 }
722 722
 
723 723
 
@@ -727,31 +727,31 @@  discard block
 block discarded – undo
727 727
  * Plugin URI: http://upthemes.com/plugins/kint-debugger/
728 728
  */
729 729
 if (class_exists('Kint') && ! function_exists('dump_wp_query')) {
730
-    function dump_wp_query()
731
-    {
732
-        global $wp_query;
733
-        d($wp_query);
734
-    }
730
+	function dump_wp_query()
731
+	{
732
+		global $wp_query;
733
+		d($wp_query);
734
+	}
735 735
 }
736 736
 /**
737 737
  * borrowed from Kint Debugger
738 738
  * Plugin URI: http://upthemes.com/plugins/kint-debugger/
739 739
  */
740 740
 if (class_exists('Kint') && ! function_exists('dump_wp')) {
741
-    function dump_wp()
742
-    {
743
-        global $wp;
744
-        d($wp);
745
-    }
741
+	function dump_wp()
742
+	{
743
+		global $wp;
744
+		d($wp);
745
+	}
746 746
 }
747 747
 /**
748 748
  * borrowed from Kint Debugger
749 749
  * Plugin URI: http://upthemes.com/plugins/kint-debugger/
750 750
  */
751 751
 if (class_exists('Kint') && ! function_exists('dump_post')) {
752
-    function dump_post()
753
-    {
754
-        global $post;
755
-        d($post);
756
-    }
752
+	function dump_post()
753
+	{
754
+		global $post;
755
+		d($post);
756
+	}
757 757
 }
Please login to merge, or discard this patch.
core/helpers/EEH_Line_Item.helper.php 1 patch
Indentation   +2128 added lines, -2128 removed lines patch added patch discarded remove patch
@@ -21,2132 +21,2132 @@
 block discarded – undo
21 21
  */
22 22
 class EEH_Line_Item
23 23
 {
24
-    /**
25
-     * @var EE_Line_Item[]
26
-    */
27
-    private static $global_taxes;
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'      => $items_subtotal instanceof EE_Line_Item
71
-                    ? count($items_subtotal->children())
72
-                    : 0,
73
-                'LIN_total'      => (float) $unit_price * (int) $quantity,
74
-                'LIN_type'       => EEM_Line_Item::type_line_item,
75
-                'LIN_code'       => $code,
76
-            ]
77
-        );
78
-        $line_item      = apply_filters(
79
-            'FHEE__EEH_Line_Item__add_unrelated_item__line_item',
80
-            $line_item,
81
-            $parent_line_item
82
-        );
83
-        $added          = self::add_item($parent_line_item, $line_item, $recalculate_totals);
84
-        return $return_item ? $line_item : $added;
85
-    }
86
-
87
-
88
-    /**
89
-     * Adds a simple item ( unrelated to any other model object) to the total line item,
90
-     * in the correct spot in the line item tree. Does not automatically
91
-     * re-calculate the line item totals, nor update the related transaction, nor upgrade the transaction's
92
-     * registrations' final prices (which should probably change because of this).
93
-     * You should call recalculate_total_including_taxes() on the grand total line item, then
94
-     * update the transaction's total, and EE_Registration_Processor::update_registration_final_prices()
95
-     * after using this, to keep the registration final prices in-sync with the transaction's total.
96
-     *
97
-     * @param EE_Line_Item $parent_line_item
98
-     * @param string       $name
99
-     * @param float        $percentage_amount
100
-     * @param string       $description
101
-     * @param boolean      $taxable
102
-     * @param string|null  $code
103
-     * @param bool         $return_item
104
-     * @return boolean|EE_Line_Item success
105
-     * @throws EE_Error
106
-     * @throws ReflectionException
107
-     */
108
-    public static function add_percentage_based_item(
109
-        EE_Line_Item $parent_line_item,
110
-        string $name,
111
-        float $percentage_amount,
112
-        string $description = '',
113
-        bool $taxable = false,
114
-        ?string $code = null,
115
-        bool $return_item = false
116
-    ) {
117
-        $total = $percentage_amount * $parent_line_item->total() / 100;
118
-        $line_item = EE_Line_Item::new_instance(
119
-            [
120
-                'LIN_name'       => $name,
121
-                'LIN_desc'       => $description,
122
-                'LIN_unit_price' => 0,
123
-                'LIN_percent'    => $percentage_amount,
124
-                'LIN_quantity'   => 1,
125
-                'LIN_is_taxable' => $taxable,
126
-                'LIN_total'      => (float) $total,
127
-                'LIN_type'       => EEM_Line_Item::type_line_item,
128
-                'LIN_parent'     => $parent_line_item->ID(),
129
-                'LIN_code'       => $code,
130
-            ]
131
-        );
132
-        $line_item = apply_filters(
133
-            'FHEE__EEH_Line_Item__add_percentage_based_item__line_item',
134
-            $line_item
135
-        );
136
-        $added     = $parent_line_item->add_child_line_item($line_item, false);
137
-        return $return_item ? $line_item : $added;
138
-    }
139
-
140
-
141
-    /**
142
-     * Returns the new line item created by adding a purchase of the ticket
143
-     * ensures that ticket line item is saved, and that cart total has been recalculated.
144
-     * If this ticket has already been purchased, just increments its count.
145
-     * Automatically re-calculates the line item totals and updates the related transaction. But
146
-     * DOES NOT automatically upgrade the transaction's registrations' final prices (which
147
-     * should probably change because of this).
148
-     * You should call EE_Registration_Processor::calculate_reg_final_prices_per_line_item()
149
-     * after using this, to keep the registration final prices in-sync with the transaction's total.
150
-     *
151
-     * @param EE_Line_Item $total_line_item grand total line item of type EEM_Line_Item::type_total
152
-     * @param EE_Ticket    $ticket
153
-     * @param int          $qty
154
-     * @return EE_Line_Item
155
-     * @throws EE_Error
156
-     * @throws InvalidArgumentException
157
-     * @throws InvalidDataTypeException
158
-     * @throws InvalidInterfaceException
159
-     * @throws ReflectionException
160
-     */
161
-    public static function add_ticket_purchase(EE_Line_Item $total_line_item, EE_Ticket $ticket, $qty = 1)
162
-    {
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
-        $total_line_item->recalculate_total_including_taxes();
182
-        return $line_item;
183
-    }
184
-
185
-
186
-    /**
187
-     * Returns the new line item created by adding a purchase of the ticket
188
-     *
189
-     * @param EE_Line_Item $total_line_item
190
-     * @param EE_Ticket    $ticket
191
-     * @param int          $qty
192
-     * @return EE_Line_Item
193
-     * @throws EE_Error
194
-     * @throws InvalidArgumentException
195
-     * @throws InvalidDataTypeException
196
-     * @throws InvalidInterfaceException
197
-     * @throws ReflectionException
198
-     */
199
-    public static function increment_ticket_qty_if_already_in_cart(
200
-        EE_Line_Item $total_line_item,
201
-        EE_Ticket $ticket,
202
-        $qty = 1
203
-    ) {
204
-        $line_item = null;
205
-        if ($total_line_item instanceof EE_Line_Item && $total_line_item->is_total()) {
206
-            $ticket_line_items = EEH_Line_Item::get_ticket_line_items($total_line_item);
207
-            foreach ((array) $ticket_line_items as $ticket_line_item) {
208
-                if (
209
-                    $ticket_line_item instanceof EE_Line_Item
210
-                    && (int) $ticket_line_item->OBJ_ID() === (int) $ticket->ID()
211
-                ) {
212
-                    $line_item = $ticket_line_item;
213
-                    break;
214
-                }
215
-            }
216
-        }
217
-        if ($line_item instanceof EE_Line_Item) {
218
-            EEH_Line_Item::increment_quantity($line_item, $qty);
219
-            return $line_item;
220
-        }
221
-        return null;
222
-    }
223
-
224
-
225
-    /**
226
-     * Increments the line item and all its children's quantity by $qty (but percent line items are unaffected).
227
-     * Does NOT save or recalculate other line items totals
228
-     *
229
-     * @param EE_Line_Item $line_item
230
-     * @param int          $qty
231
-     * @return void
232
-     * @throws EE_Error
233
-     * @throws InvalidArgumentException
234
-     * @throws InvalidDataTypeException
235
-     * @throws InvalidInterfaceException
236
-     * @throws ReflectionException
237
-     */
238
-    public static function increment_quantity(EE_Line_Item $line_item, $qty = 1)
239
-    {
240
-        if (! $line_item->is_percent()) {
241
-            $qty += $line_item->quantity();
242
-            $line_item->set_quantity($qty);
243
-            $line_item->set_total($line_item->unit_price() * $qty);
244
-            $line_item->save();
245
-        }
246
-        foreach ($line_item->children() as $child) {
247
-            if ($child->is_sub_line_item()) {
248
-                EEH_Line_Item::update_quantity($child, $qty);
249
-            }
250
-        }
251
-    }
252
-
253
-
254
-    /**
255
-     * Decrements the line item and all its children's quantity by $qty (but percent line items are unaffected).
256
-     * Does NOT save or recalculate other line items totals
257
-     *
258
-     * @param EE_Line_Item $line_item
259
-     * @param int          $qty
260
-     * @return void
261
-     * @throws EE_Error
262
-     * @throws InvalidArgumentException
263
-     * @throws InvalidDataTypeException
264
-     * @throws InvalidInterfaceException
265
-     * @throws ReflectionException
266
-     */
267
-    public static function decrement_quantity(EE_Line_Item $line_item, $qty = 1)
268
-    {
269
-        if (! $line_item->is_percent()) {
270
-            $qty = $line_item->quantity() - $qty;
271
-            $qty = max($qty, 0);
272
-            $line_item->set_quantity($qty);
273
-            $line_item->set_total($line_item->unit_price() * $qty);
274
-            $line_item->save();
275
-        }
276
-        foreach ($line_item->children() as $child) {
277
-            if ($child->is_sub_line_item()) {
278
-                EEH_Line_Item::update_quantity($child, $qty);
279
-            }
280
-        }
281
-    }
282
-
283
-
284
-    /**
285
-     * Updates the line item and its children's quantities to the specified number.
286
-     * Does NOT save them or recalculate totals.
287
-     *
288
-     * @param EE_Line_Item $line_item
289
-     * @param int          $new_quantity
290
-     * @throws EE_Error
291
-     * @throws InvalidArgumentException
292
-     * @throws InvalidDataTypeException
293
-     * @throws InvalidInterfaceException
294
-     * @throws ReflectionException
295
-     */
296
-    public static function update_quantity(EE_Line_Item $line_item, $new_quantity)
297
-    {
298
-        if (! $line_item->is_percent()) {
299
-            $line_item->set_quantity($new_quantity);
300
-            $line_item->set_total($line_item->unit_price() * $new_quantity);
301
-            $line_item->save();
302
-        }
303
-        foreach ($line_item->children() as $child) {
304
-            if ($child->is_sub_line_item()) {
305
-                EEH_Line_Item::update_quantity($child, $new_quantity);
306
-            }
307
-        }
308
-    }
309
-
310
-
311
-    /**
312
-     * Returns the new line item created by adding a purchase of the ticket
313
-     *
314
-     * @param EE_Line_Item $total_line_item of type EEM_Line_Item::type_total
315
-     * @param EE_Ticket    $ticket
316
-     * @param int          $qty
317
-     * @return EE_Line_Item
318
-     * @throws EE_Error
319
-     * @throws InvalidArgumentException
320
-     * @throws InvalidDataTypeException
321
-     * @throws InvalidInterfaceException
322
-     * @throws ReflectionException
323
-     */
324
-    public static function create_ticket_line_item(EE_Line_Item $total_line_item, EE_Ticket $ticket, $qty = 1)
325
-    {
326
-        $datetimes = $ticket->datetimes();
327
-        $first_datetime = reset($datetimes);
328
-        $first_datetime_name = esc_html__('Event', 'event_espresso');
329
-        if ($first_datetime instanceof EE_Datetime && $first_datetime->event() instanceof EE_Event) {
330
-            $first_datetime_name = $first_datetime->event()->name();
331
-        }
332
-        $event = sprintf(_x('(For %1$s)', '(For Event Name)', 'event_espresso'), $first_datetime_name);
333
-        // get event subtotal line
334
-        $events_sub_total = self::get_event_line_item_for_ticket($total_line_item, $ticket);
335
-        $taxes = $ticket->tax_price_modifiers();
336
-        // add $ticket to cart
337
-        $line_item = EE_Line_Item::new_instance(array(
338
-            'LIN_name'       => $ticket->name(),
339
-            'LIN_desc'       => $ticket->description() !== '' ? $ticket->description() . ' ' . $event : $event,
340
-            'LIN_unit_price' => $ticket->price(),
341
-            'LIN_quantity'   => $qty,
342
-            'LIN_is_taxable' => empty($taxes) && $ticket->taxable(),
343
-            'LIN_order'      => count($events_sub_total->children()),
344
-            'LIN_total'      => $ticket->price() * $qty,
345
-            'LIN_type'       => EEM_Line_Item::type_line_item,
346
-            'OBJ_ID'         => $ticket->ID(),
347
-            'OBJ_type'       => EEM_Line_Item::OBJ_TYPE_TICKET,
348
-        ));
349
-        $line_item = apply_filters(
350
-            'FHEE__EEH_Line_Item__create_ticket_line_item__line_item',
351
-            $line_item
352
-        );
353
-        if (!$line_item instanceof EE_Line_Item) {
354
-            throw new DomainException(
355
-                esc_html__('Invalid EE_Line_Item received.', 'event_espresso')
356
-            );
357
-        }
358
-        $events_sub_total->add_child_line_item($line_item);
359
-        // now add the sub-line items
360
-        $running_total = 0;
361
-        $running_pre_tax_total = 0;
362
-        foreach ($ticket->prices() as $price) {
363
-            $sign = $price->is_discount() ? -1 : 1;
364
-            $price_total = $price->is_percent()
365
-                ? $running_pre_tax_total * $price->amount() / 100
366
-                : $price->amount() * $qty;
367
-            if ($price->is_percent()) {
368
-                $percent = $sign * $price->amount();
369
-                $unit_price = 0;
370
-            } else {
371
-                $percent    = 0;
372
-                $unit_price = $sign * $price->amount();
373
-            }
374
-            $sub_line_item = EE_Line_Item::new_instance(array(
375
-                'LIN_name'       => $price->name(),
376
-                'LIN_desc'       => $price->desc(),
377
-                'LIN_quantity'   => $price->is_percent() ? null : $qty,
378
-                'LIN_is_taxable' => false,
379
-                'LIN_order'      => $price->order(),
380
-                'LIN_total'      => $price_total,
381
-                'LIN_pretax'     => 0,
382
-                'LIN_unit_price' => $unit_price,
383
-                'LIN_percent'    => $percent,
384
-                'LIN_type'       => $price->is_tax() ? EEM_Line_Item::type_sub_tax : EEM_Line_Item::type_sub_line_item,
385
-                'OBJ_ID'         => $price->ID(),
386
-                'OBJ_type'       => EEM_Line_Item::OBJ_TYPE_PRICE,
387
-            ));
388
-            $sub_line_item = apply_filters(
389
-                'FHEE__EEH_Line_Item__create_ticket_line_item__sub_line_item',
390
-                $sub_line_item
391
-            );
392
-            $running_total += $sign * $price_total;
393
-            $running_pre_tax_total += ! $price->is_tax() ? $sign * $price_total : 0;
394
-            $line_item->add_child_line_item($sub_line_item);
395
-        }
396
-        $line_item->setPretaxTotal($running_pre_tax_total);
397
-        return $line_item;
398
-    }
399
-
400
-
401
-    /**
402
-     * Adds the specified item under the pre-tax-sub-total line item. Automatically
403
-     * re-calculates the line item totals and updates the related transaction. But
404
-     * DOES NOT automatically upgrade the transaction's registrations' final prices (which
405
-     * should probably change because of this).
406
-     * You should call EE_Registration_Processor::calculate_reg_final_prices_per_line_item()
407
-     * after using this, to keep the registration final prices in-sync with the transaction's total.
408
-     *
409
-     * @param EE_Line_Item $total_line_item
410
-     * @param EE_Line_Item $item to be added
411
-     * @return boolean
412
-     * @throws EE_Error
413
-     * @throws InvalidArgumentException
414
-     * @throws InvalidDataTypeException
415
-     * @throws InvalidInterfaceException
416
-     * @throws ReflectionException
417
-     */
418
-    public static function add_item(EE_Line_Item $total_line_item, EE_Line_Item $item, $recalculate_totals = true)
419
-    {
420
-        $pre_tax_subtotal = self::get_pre_tax_subtotal($total_line_item);
421
-        if ($pre_tax_subtotal instanceof EE_Line_Item) {
422
-            $success = $pre_tax_subtotal->add_child_line_item($item);
423
-        } else {
424
-            return false;
425
-        }
426
-        if ($recalculate_totals) {
427
-            $total_line_item->recalculate_total_including_taxes();
428
-        }
429
-        return $success;
430
-    }
431
-
432
-
433
-    /**
434
-     * cancels an existing ticket line item,
435
-     * by decrementing it's quantity by 1 and adding a new "type_cancellation" sub-line-item.
436
-     * ALL totals and subtotals will NEED TO BE UPDATED after performing this action
437
-     *
438
-     * @param EE_Line_Item $ticket_line_item
439
-     * @param int          $qty
440
-     * @return bool success
441
-     * @throws EE_Error
442
-     * @throws InvalidArgumentException
443
-     * @throws InvalidDataTypeException
444
-     * @throws InvalidInterfaceException
445
-     * @throws ReflectionException
446
-     */
447
-    public static function cancel_ticket_line_item(EE_Line_Item $ticket_line_item, $qty = 1)
448
-    {
449
-        // validate incoming line_item
450
-        if ($ticket_line_item->OBJ_type() !== EEM_Line_Item::OBJ_TYPE_TICKET) {
451
-            throw new EE_Error(
452
-                sprintf(
453
-                    esc_html__(
454
-                        'The supplied line item must have an Object Type of "Ticket", not %1$s.',
455
-                        'event_espresso'
456
-                    ),
457
-                    $ticket_line_item->type()
458
-                )
459
-            );
460
-        }
461
-        if ($ticket_line_item->quantity() < $qty) {
462
-            throw new EE_Error(
463
-                sprintf(
464
-                    esc_html__(
465
-                        'Can not cancel %1$d ticket(s) because the supplied line item has a quantity of %2$d.',
466
-                        'event_espresso'
467
-                    ),
468
-                    $qty,
469
-                    $ticket_line_item->quantity()
470
-                )
471
-            );
472
-        }
473
-        // decrement ticket quantity; don't rely on auto-fixing when recalculating totals to do this
474
-        $ticket_line_item->set_quantity($ticket_line_item->quantity() - $qty);
475
-        foreach ($ticket_line_item->children() as $child_line_item) {
476
-            if (
477
-                $child_line_item->is_sub_line_item()
478
-                && ! $child_line_item->is_percent()
479
-                && ! $child_line_item->is_cancellation()
480
-            ) {
481
-                $child_line_item->set_quantity($child_line_item->quantity() - $qty);
482
-            }
483
-        }
484
-        // get cancellation sub line item
485
-        $cancellation_line_item = EEH_Line_Item::get_descendants_of_type(
486
-            $ticket_line_item,
487
-            EEM_Line_Item::type_cancellation
488
-        );
489
-        $cancellation_line_item = reset($cancellation_line_item);
490
-        // verify that this ticket was indeed previously cancelled
491
-        if ($cancellation_line_item instanceof EE_Line_Item) {
492
-            // increment cancelled quantity
493
-            $cancellation_line_item->set_quantity($cancellation_line_item->quantity() + $qty);
494
-        } else {
495
-            // create cancellation sub line item
496
-            $cancellation_line_item = EE_Line_Item::new_instance(array(
497
-                'LIN_name'       => esc_html__('Cancellation', 'event_espresso'),
498
-                'LIN_desc'       => sprintf(
499
-                    esc_html_x(
500
-                        'Cancelled %1$s : %2$s',
501
-                        'Cancelled Ticket Name : 2015-01-01 11:11',
502
-                        'event_espresso'
503
-                    ),
504
-                    $ticket_line_item->name(),
505
-                    current_time(get_option('date_format') . ' ' . get_option('time_format'))
506
-                ),
507
-                'LIN_unit_price' => 0, // $ticket_line_item->unit_price()
508
-                'LIN_quantity'   => $qty,
509
-                'LIN_is_taxable' => $ticket_line_item->is_taxable(),
510
-                'LIN_order'      => count($ticket_line_item->children()),
511
-                'LIN_total'      => 0, // $ticket_line_item->unit_price()
512
-                'LIN_type'       => EEM_Line_Item::type_cancellation,
513
-            ));
514
-            $ticket_line_item->add_child_line_item($cancellation_line_item);
515
-        }
516
-        if ($ticket_line_item->save_this_and_descendants() > 0) {
517
-            // decrement parent line item quantity
518
-            $event_line_item = $ticket_line_item->parent();
519
-            if (
520
-                $event_line_item instanceof EE_Line_Item
521
-                && $event_line_item->OBJ_type() === EEM_Line_Item::OBJ_TYPE_EVENT
522
-            ) {
523
-                $event_line_item->set_quantity($event_line_item->quantity() - $qty);
524
-                $event_line_item->save();
525
-            }
526
-            EEH_Line_Item::get_grand_total_and_recalculate_everything($ticket_line_item);
527
-            return true;
528
-        }
529
-        return false;
530
-    }
531
-
532
-
533
-    /**
534
-     * reinstates (un-cancels?) a previously canceled ticket line item,
535
-     * by incrementing it's quantity by 1, and decrementing it's "type_cancellation" sub-line-item.
536
-     * ALL totals and subtotals will NEED TO BE UPDATED after performing this action
537
-     *
538
-     * @param EE_Line_Item $ticket_line_item
539
-     * @param int          $qty
540
-     * @return bool success
541
-     * @throws EE_Error
542
-     * @throws InvalidArgumentException
543
-     * @throws InvalidDataTypeException
544
-     * @throws InvalidInterfaceException
545
-     * @throws ReflectionException
546
-     */
547
-    public static function reinstate_canceled_ticket_line_item(EE_Line_Item $ticket_line_item, $qty = 1)
548
-    {
549
-        // validate incoming line_item
550
-        if ($ticket_line_item->OBJ_type() !== EEM_Line_Item::OBJ_TYPE_TICKET) {
551
-            throw new EE_Error(
552
-                sprintf(
553
-                    esc_html__(
554
-                        'The supplied line item must have an Object Type of "Ticket", not %1$s.',
555
-                        'event_espresso'
556
-                    ),
557
-                    $ticket_line_item->type()
558
-                )
559
-            );
560
-        }
561
-        // get cancellation sub line item
562
-        $cancellation_line_item = EEH_Line_Item::get_descendants_of_type(
563
-            $ticket_line_item,
564
-            EEM_Line_Item::type_cancellation
565
-        );
566
-        $cancellation_line_item = reset($cancellation_line_item);
567
-        // verify that this ticket was indeed previously cancelled
568
-        if (! $cancellation_line_item instanceof EE_Line_Item) {
569
-            return false;
570
-        }
571
-        if ($cancellation_line_item->quantity() > $qty) {
572
-            // decrement cancelled quantity
573
-            $cancellation_line_item->set_quantity($cancellation_line_item->quantity() - $qty);
574
-        } elseif ($cancellation_line_item->quantity() === $qty) {
575
-            // decrement cancelled quantity in case anyone still has the object kicking around
576
-            $cancellation_line_item->set_quantity($cancellation_line_item->quantity() - $qty);
577
-            // delete because quantity will end up as 0
578
-            $cancellation_line_item->delete();
579
-            // and attempt to destroy the object,
580
-            // even though PHP won't actually destroy it until it needs the memory
581
-            unset($cancellation_line_item);
582
-        } else {
583
-            // what ?!?! negative quantity ?!?!
584
-            throw new EE_Error(
585
-                sprintf(
586
-                    esc_html__(
587
-                        'Can not reinstate %1$d cancelled ticket(s) because the cancelled ticket quantity is only %2$d.',
588
-                        'event_espresso'
589
-                    ),
590
-                    $qty,
591
-                    $cancellation_line_item->quantity()
592
-                )
593
-            );
594
-        }
595
-        // increment ticket quantity
596
-        $ticket_line_item->set_quantity($ticket_line_item->quantity() + $qty);
597
-        if ($ticket_line_item->save_this_and_descendants() > 0) {
598
-            // increment parent line item quantity
599
-            $event_line_item = $ticket_line_item->parent();
600
-            if (
601
-                $event_line_item instanceof EE_Line_Item
602
-                && $event_line_item->OBJ_type() === EEM_Line_Item::OBJ_TYPE_EVENT
603
-            ) {
604
-                $event_line_item->set_quantity($event_line_item->quantity() + $qty);
605
-            }
606
-            EEH_Line_Item::get_grand_total_and_recalculate_everything($ticket_line_item);
607
-            return true;
608
-        }
609
-        return false;
610
-    }
611
-
612
-
613
-    /**
614
-     * calls EEH_Line_Item::find_transaction_grand_total_for_line_item()
615
-     * then EE_Line_Item::recalculate_total_including_taxes() on the result
616
-     *
617
-     * @param EE_Line_Item $line_item
618
-     * @return float
619
-     * @throws EE_Error
620
-     * @throws InvalidArgumentException
621
-     * @throws InvalidDataTypeException
622
-     * @throws InvalidInterfaceException
623
-     * @throws ReflectionException
624
-     */
625
-    public static function get_grand_total_and_recalculate_everything(EE_Line_Item $line_item)
626
-    {
627
-        $grand_total_line_item = EEH_Line_Item::find_transaction_grand_total_for_line_item($line_item);
628
-        return $grand_total_line_item->recalculate_total_including_taxes();
629
-    }
630
-
631
-
632
-    /**
633
-     * Gets the line item which contains the subtotal of all the items
634
-     *
635
-     * @param EE_Line_Item $total_line_item of type EEM_Line_Item::type_total
636
-     * @return EE_Line_Item
637
-     * @throws EE_Error
638
-     * @throws InvalidArgumentException
639
-     * @throws InvalidDataTypeException
640
-     * @throws InvalidInterfaceException
641
-     * @throws ReflectionException
642
-     */
643
-    public static function get_pre_tax_subtotal(EE_Line_Item $total_line_item)
644
-    {
645
-        $pre_tax_subtotal = $total_line_item->get_child_line_item('pre-tax-subtotal');
646
-        return $pre_tax_subtotal instanceof EE_Line_Item
647
-            ? $pre_tax_subtotal
648
-            : self::create_pre_tax_subtotal($total_line_item);
649
-    }
650
-
651
-
652
-    /**
653
-     * Gets the line item for the taxes subtotal
654
-     *
655
-     * @param EE_Line_Item $total_line_item of type EEM_Line_Item::type_total
656
-     * @return EE_Line_Item
657
-     * @throws EE_Error
658
-     * @throws InvalidArgumentException
659
-     * @throws InvalidDataTypeException
660
-     * @throws InvalidInterfaceException
661
-     * @throws ReflectionException
662
-     */
663
-    public static function get_taxes_subtotal(EE_Line_Item $total_line_item)
664
-    {
665
-        $taxes = $total_line_item->get_child_line_item('taxes');
666
-        return $taxes ? $taxes : self::create_taxes_subtotal($total_line_item);
667
-    }
668
-
669
-
670
-    /**
671
-     * sets the TXN ID on an EE_Line_Item if passed a valid EE_Transaction object
672
-     *
673
-     * @param EE_Line_Item   $line_item
674
-     * @param EE_Transaction $transaction
675
-     * @return void
676
-     * @throws EE_Error
677
-     * @throws InvalidArgumentException
678
-     * @throws InvalidDataTypeException
679
-     * @throws InvalidInterfaceException
680
-     * @throws ReflectionException
681
-     */
682
-    public static function set_TXN_ID(EE_Line_Item $line_item, $transaction = null)
683
-    {
684
-        if ($transaction) {
685
-            /** @type EEM_Transaction $EEM_Transaction */
686
-            $EEM_Transaction = EE_Registry::instance()->load_model('Transaction');
687
-            $TXN_ID = $EEM_Transaction->ensure_is_ID($transaction);
688
-            $line_item->set_TXN_ID($TXN_ID);
689
-        }
690
-    }
691
-
692
-
693
-    /**
694
-     * Creates a new default total line item for the transaction,
695
-     * and its tickets subtotal and taxes subtotal line items (and adds the
696
-     * existing taxes as children of the taxes subtotal line item)
697
-     *
698
-     * @param EE_Transaction $transaction
699
-     * @return EE_Line_Item of type total
700
-     * @throws EE_Error
701
-     * @throws InvalidArgumentException
702
-     * @throws InvalidDataTypeException
703
-     * @throws InvalidInterfaceException
704
-     * @throws ReflectionException
705
-     */
706
-    public static function create_total_line_item($transaction = null)
707
-    {
708
-        $total_line_item = EE_Line_Item::new_instance(array(
709
-            'LIN_code' => 'total',
710
-            'LIN_name' => esc_html__('Grand Total', 'event_espresso'),
711
-            'LIN_type' => EEM_Line_Item::type_total,
712
-            'OBJ_type' => EEM_Line_Item::OBJ_TYPE_TRANSACTION,
713
-        ));
714
-        $total_line_item = apply_filters(
715
-            'FHEE__EEH_Line_Item__create_total_line_item__total_line_item',
716
-            $total_line_item
717
-        );
718
-        self::set_TXN_ID($total_line_item, $transaction);
719
-        self::create_pre_tax_subtotal($total_line_item, $transaction);
720
-        self::create_taxes_subtotal($total_line_item, $transaction);
721
-        return $total_line_item;
722
-    }
723
-
724
-
725
-    /**
726
-     * Creates a default items subtotal line item
727
-     *
728
-     * @param EE_Line_Item   $total_line_item
729
-     * @param EE_Transaction $transaction
730
-     * @return EE_Line_Item
731
-     * @throws EE_Error
732
-     * @throws InvalidArgumentException
733
-     * @throws InvalidDataTypeException
734
-     * @throws InvalidInterfaceException
735
-     * @throws ReflectionException
736
-     */
737
-    protected static function create_pre_tax_subtotal(EE_Line_Item $total_line_item, $transaction = null)
738
-    {
739
-        $pre_tax_line_item = EE_Line_Item::new_instance(array(
740
-            'LIN_code' => 'pre-tax-subtotal',
741
-            'LIN_name' => esc_html__('Pre-Tax Subtotal', 'event_espresso'),
742
-            'LIN_type' => EEM_Line_Item::type_sub_total,
743
-        ));
744
-        $pre_tax_line_item = apply_filters(
745
-            'FHEE__EEH_Line_Item__create_pre_tax_subtotal__pre_tax_line_item',
746
-            $pre_tax_line_item
747
-        );
748
-        self::set_TXN_ID($pre_tax_line_item, $transaction);
749
-        $total_line_item->add_child_line_item($pre_tax_line_item);
750
-        self::create_event_subtotal($pre_tax_line_item, $transaction);
751
-        return $pre_tax_line_item;
752
-    }
753
-
754
-
755
-    /**
756
-     * Creates a line item for the taxes subtotal and finds all the tax prices
757
-     * and applies taxes to it
758
-     *
759
-     * @param EE_Line_Item   $total_line_item of type EEM_Line_Item::type_total
760
-     * @param EE_Transaction $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_taxes_subtotal(EE_Line_Item $total_line_item, $transaction = null)
769
-    {
770
-        $tax_line_item = EE_Line_Item::new_instance(array(
771
-            'LIN_code'  => 'taxes',
772
-            'LIN_name'  => esc_html__('Taxes', 'event_espresso'),
773
-            'LIN_type'  => EEM_Line_Item::type_tax_sub_total,
774
-            'LIN_order' => 1000,// this should always come last
775
-        ));
776
-        $tax_line_item = apply_filters(
777
-            'FHEE__EEH_Line_Item__create_taxes_subtotal__tax_line_item',
778
-            $tax_line_item
779
-        );
780
-        self::set_TXN_ID($tax_line_item, $transaction);
781
-        $total_line_item->add_child_line_item($tax_line_item);
782
-        // and lastly, add the actual taxes
783
-        self::apply_taxes($total_line_item);
784
-        return $tax_line_item;
785
-    }
786
-
787
-
788
-    /**
789
-     * Creates a default items subtotal line item
790
-     *
791
-     * @param EE_Line_Item   $pre_tax_line_item
792
-     * @param EE_Transaction $transaction
793
-     * @param EE_Event       $event
794
-     * @return EE_Line_Item
795
-     * @throws EE_Error
796
-     * @throws InvalidArgumentException
797
-     * @throws InvalidDataTypeException
798
-     * @throws InvalidInterfaceException
799
-     * @throws ReflectionException
800
-     */
801
-    public static function create_event_subtotal(EE_Line_Item $pre_tax_line_item, $transaction = null, $event = null)
802
-    {
803
-        $event_line_item = EE_Line_Item::new_instance(array(
804
-            'LIN_code' => self::get_event_code($event),
805
-            'LIN_name' => self::get_event_name($event),
806
-            'LIN_desc' => self::get_event_desc($event),
807
-            'LIN_type' => EEM_Line_Item::type_sub_total,
808
-            'OBJ_type' => EEM_Line_Item::OBJ_TYPE_EVENT,
809
-            'OBJ_ID'   => $event instanceof EE_Event ? $event->ID() : 0,
810
-        ));
811
-        $event_line_item = apply_filters(
812
-            'FHEE__EEH_Line_Item__create_event_subtotal__event_line_item',
813
-            $event_line_item
814
-        );
815
-        self::set_TXN_ID($event_line_item, $transaction);
816
-        $pre_tax_line_item->add_child_line_item($event_line_item);
817
-        return $event_line_item;
818
-    }
819
-
820
-
821
-    /**
822
-     * Gets what the event ticket's code SHOULD be
823
-     *
824
-     * @param EE_Event $event
825
-     * @return string
826
-     * @throws EE_Error
827
-     */
828
-    public static function get_event_code($event)
829
-    {
830
-        return 'event-' . ($event instanceof EE_Event ? $event->ID() : '0');
831
-    }
832
-
833
-
834
-    /**
835
-     * Gets the event name
836
-     *
837
-     * @param EE_Event $event
838
-     * @return string
839
-     * @throws EE_Error
840
-     */
841
-    public static function get_event_name($event)
842
-    {
843
-        return $event instanceof EE_Event
844
-            ? mb_substr($event->name(), 0, 245)
845
-            : esc_html__('Event', 'event_espresso');
846
-    }
847
-
848
-
849
-    /**
850
-     * Gets the event excerpt
851
-     *
852
-     * @param EE_Event $event
853
-     * @return string
854
-     * @throws EE_Error
855
-     */
856
-    public static function get_event_desc($event)
857
-    {
858
-        return $event instanceof EE_Event ? $event->short_description() : '';
859
-    }
860
-
861
-
862
-    /**
863
-     * Given the grand total line item and a ticket, finds the event sub-total
864
-     * line item the ticket's purchase should be added onto
865
-     *
866
-     * @access public
867
-     * @param EE_Line_Item $grand_total the grand total line item
868
-     * @param EE_Ticket    $ticket
869
-     * @return EE_Line_Item
870
-     * @throws EE_Error
871
-     * @throws InvalidArgumentException
872
-     * @throws InvalidDataTypeException
873
-     * @throws InvalidInterfaceException
874
-     * @throws ReflectionException
875
-     */
876
-    public static function get_event_line_item_for_ticket(EE_Line_Item $grand_total, EE_Ticket $ticket)
877
-    {
878
-        $first_datetime = $ticket->first_datetime();
879
-        if (! $first_datetime instanceof EE_Datetime) {
880
-            throw new EE_Error(
881
-                sprintf(
882
-                    esc_html__('The supplied ticket (ID %d) has no datetimes', 'event_espresso'),
883
-                    $ticket->ID()
884
-                )
885
-            );
886
-        }
887
-        $event = $first_datetime->event();
888
-        if (! $event instanceof EE_Event) {
889
-            throw new EE_Error(
890
-                sprintf(
891
-                    esc_html__(
892
-                        'The supplied ticket (ID %d) has no event data associated with it.',
893
-                        'event_espresso'
894
-                    ),
895
-                    $ticket->ID()
896
-                )
897
-            );
898
-        }
899
-        $events_sub_total = EEH_Line_Item::get_event_line_item($grand_total, $event);
900
-        if (! $events_sub_total instanceof EE_Line_Item) {
901
-            throw new EE_Error(
902
-                sprintf(
903
-                    esc_html__(
904
-                        'There is no events sub-total for ticket %s on total line item %d',
905
-                        'event_espresso'
906
-                    ),
907
-                    $ticket->ID(),
908
-                    $grand_total->ID()
909
-                )
910
-            );
911
-        }
912
-        return $events_sub_total;
913
-    }
914
-
915
-
916
-    /**
917
-     * Gets the event line item
918
-     *
919
-     * @param EE_Line_Item $grand_total
920
-     * @param EE_Event     $event
921
-     * @return EE_Line_Item for the event subtotal which is a child of $grand_total
922
-     * @throws EE_Error
923
-     * @throws InvalidArgumentException
924
-     * @throws InvalidDataTypeException
925
-     * @throws InvalidInterfaceException
926
-     * @throws ReflectionException
927
-     */
928
-    public static function get_event_line_item(EE_Line_Item $grand_total, $event)
929
-    {
930
-        /** @type EE_Event $event */
931
-        $event = EEM_Event::instance()->ensure_is_obj($event, true);
932
-        $event_line_item = null;
933
-        $found = false;
934
-        foreach (EEH_Line_Item::get_event_subtotals($grand_total) as $event_line_item) {
935
-            // default event subtotal, we should only ever find this the first time this method is called
936
-            if (! $event_line_item->OBJ_ID()) {
937
-                // let's use this! but first... set the event details
938
-                EEH_Line_Item::set_event_subtotal_details($event_line_item, $event);
939
-                $found = true;
940
-                break;
941
-            }
942
-            if ($event_line_item->OBJ_ID() === $event->ID()) {
943
-                // found existing line item for this event in the cart, so break out of loop and use this one
944
-                $found = true;
945
-                break;
946
-            }
947
-        }
948
-        if (! $found) {
949
-            // there is no event sub-total yet, so add it
950
-            $pre_tax_subtotal = EEH_Line_Item::get_pre_tax_subtotal($grand_total);
951
-            // create a new "event" subtotal below that
952
-            $event_line_item = EEH_Line_Item::create_event_subtotal($pre_tax_subtotal, null, $event);
953
-            // and set the event details
954
-            EEH_Line_Item::set_event_subtotal_details($event_line_item, $event);
955
-        }
956
-        return $event_line_item;
957
-    }
958
-
959
-
960
-    /**
961
-     * Creates a default items subtotal line item
962
-     *
963
-     * @param EE_Line_Item   $event_line_item
964
-     * @param EE_Event       $event
965
-     * @param EE_Transaction $transaction
966
-     * @return void
967
-     * @throws EE_Error
968
-     * @throws InvalidArgumentException
969
-     * @throws InvalidDataTypeException
970
-     * @throws InvalidInterfaceException
971
-     * @throws ReflectionException
972
-     */
973
-    public static function set_event_subtotal_details(
974
-        EE_Line_Item $event_line_item,
975
-        EE_Event $event,
976
-        $transaction = null
977
-    ) {
978
-        if ($event instanceof EE_Event) {
979
-            $event_line_item->set_code(self::get_event_code($event));
980
-            $event_line_item->set_name(self::get_event_name($event));
981
-            $event_line_item->set_desc(self::get_event_desc($event));
982
-            $event_line_item->set_OBJ_ID($event->ID());
983
-        }
984
-        self::set_TXN_ID($event_line_item, $transaction);
985
-    }
986
-
987
-
988
-    /**
989
-     * Finds what taxes should apply, adds them as tax line items under the taxes sub-total,
990
-     * and recalculates the taxes sub-total and the grand total. Resets the taxes, so
991
-     * any old taxes are removed
992
-     *
993
-     * @param EE_Line_Item $total_line_item of type EEM_Line_Item::type_total
994
-     * @param bool         $update_txn_status
995
-     * @return bool
996
-     * @throws EE_Error
997
-     * @throws InvalidArgumentException
998
-     * @throws InvalidDataTypeException
999
-     * @throws InvalidInterfaceException
1000
-     * @throws ReflectionException
1001
-     * @throws RuntimeException
1002
-     */
1003
-    public static function apply_taxes(EE_Line_Item $total_line_item, $update_txn_status = false)
1004
-    {
1005
-        $total_line_item = EEH_Line_Item::find_transaction_grand_total_for_line_item($total_line_item);
1006
-        $taxes_line_item = self::get_taxes_subtotal($total_line_item);
1007
-        $existing_global_taxes = $taxes_line_item->tax_descendants();
1008
-        $updates = false;
1009
-        // loop thru taxes
1010
-        $global_taxes = EEH_Line_Item::getGlobalTaxes();
1011
-        foreach ($global_taxes as $order => $taxes) {
1012
-            foreach ($taxes as $tax) {
1013
-                if ($tax instanceof EE_Price) {
1014
-                    $found = false;
1015
-                    // check if this is already an existing tax
1016
-                    foreach ($existing_global_taxes as $existing_global_tax) {
1017
-                        if ($tax->ID() === $existing_global_tax->OBJ_ID()) {
1018
-                            // maybe update the tax rate in case it has changed
1019
-                            if ($existing_global_tax->percent() !== $tax->amount()) {
1020
-                                $existing_global_tax->set_percent($tax->amount());
1021
-                                $existing_global_tax->save();
1022
-                                $updates = true;
1023
-                            }
1024
-                            $found = true;
1025
-                            break;
1026
-                        }
1027
-                    }
1028
-                    if (! $found) {
1029
-                        // add a new line item for this global tax
1030
-                        $tax_line_item = apply_filters(
1031
-                            'FHEE__EEH_Line_Item__apply_taxes__tax_line_item',
1032
-                            EE_Line_Item::new_instance(
1033
-                                [
1034
-                                    'LIN_name'       => $tax->name(),
1035
-                                    'LIN_desc'       => $tax->desc(),
1036
-                                    'LIN_percent'    => $tax->amount(),
1037
-                                    'LIN_is_taxable' => false,
1038
-                                    'LIN_order'      => $order,
1039
-                                    'LIN_total'      => 0,
1040
-                                    'LIN_type'       => EEM_Line_Item::type_tax,
1041
-                                    'OBJ_type'       => EEM_Line_Item::OBJ_TYPE_PRICE,
1042
-                                    'OBJ_ID'         => $tax->ID(),
1043
-                                ]
1044
-                            )
1045
-                        );
1046
-                        $updates = $taxes_line_item->add_child_line_item($tax_line_item) ? true : $updates;
1047
-                    }
1048
-                }
1049
-            }
1050
-        }
1051
-        // only recalculate totals if something changed
1052
-        if ($updates) {
1053
-            $total_line_item->recalculate_total_including_taxes($update_txn_status);
1054
-            return true;
1055
-        }
1056
-        return false;
1057
-    }
1058
-
1059
-
1060
-    /**
1061
-     * Ensures that taxes have been applied to the order, if not applies them.
1062
-     * Returns the total amount of tax
1063
-     *
1064
-     * @param EE_Line_Item $total_line_item of type EEM_Line_Item::type_total
1065
-     * @return float
1066
-     * @throws EE_Error
1067
-     * @throws InvalidArgumentException
1068
-     * @throws InvalidDataTypeException
1069
-     * @throws InvalidInterfaceException
1070
-     * @throws ReflectionException
1071
-     */
1072
-    public static function ensure_taxes_applied($total_line_item)
1073
-    {
1074
-        $taxes_subtotal = self::get_taxes_subtotal($total_line_item);
1075
-        if (! $taxes_subtotal->children()) {
1076
-            self::apply_taxes($total_line_item);
1077
-        }
1078
-        return $taxes_subtotal->total();
1079
-    }
1080
-
1081
-
1082
-    /**
1083
-     * Deletes ALL children of the passed line item
1084
-     *
1085
-     * @param EE_Line_Item $parent_line_item
1086
-     * @return bool
1087
-     * @throws EE_Error
1088
-     * @throws InvalidArgumentException
1089
-     * @throws InvalidDataTypeException
1090
-     * @throws InvalidInterfaceException
1091
-     * @throws ReflectionException
1092
-     */
1093
-    public static function delete_all_child_items(EE_Line_Item $parent_line_item)
1094
-    {
1095
-        $deleted = 0;
1096
-        foreach ($parent_line_item->children() as $child_line_item) {
1097
-            if ($child_line_item instanceof EE_Line_Item) {
1098
-                $deleted += EEH_Line_Item::delete_all_child_items($child_line_item);
1099
-                if ($child_line_item->ID()) {
1100
-                    $child_line_item->delete();
1101
-                    unset($child_line_item);
1102
-                } else {
1103
-                    $parent_line_item->delete_child_line_item($child_line_item->code());
1104
-                }
1105
-                $deleted++;
1106
-            }
1107
-        }
1108
-        return $deleted;
1109
-    }
1110
-
1111
-
1112
-    /**
1113
-     * Deletes the line items as indicated by the line item code(s) provided,
1114
-     * regardless of where they're found in the line item tree. Automatically
1115
-     * re-calculates the line item totals and updates the related transaction. But
1116
-     * DOES NOT automatically upgrade the transaction's registrations' final prices (which
1117
-     * should probably change because of this).
1118
-     * You should call EE_Registration_Processor::calculate_reg_final_prices_per_line_item()
1119
-     * after using this, to keep the registration final prices in-sync with the transaction's total.
1120
-     *
1121
-     * @param EE_Line_Item      $total_line_item of type EEM_Line_Item::type_total
1122
-     * @param array|bool|string $line_item_codes
1123
-     * @return int number of items successfully removed
1124
-     * @throws EE_Error
1125
-     */
1126
-    public static function delete_items(EE_Line_Item $total_line_item, $line_item_codes = false)
1127
-    {
1128
-
1129
-        if ($total_line_item->type() !== EEM_Line_Item::type_total) {
1130
-            EE_Error::doing_it_wrong(
1131
-                'EEH_Line_Item::delete_items',
1132
-                esc_html__(
1133
-                    'This static method should only be called with a TOTAL line item, otherwise we won\'t recalculate the totals correctly',
1134
-                    'event_espresso'
1135
-                ),
1136
-                '4.6.18'
1137
-            );
1138
-        }
1139
-        do_action('AHEE_log', __FILE__, __FUNCTION__, '');
1140
-
1141
-        // check if only a single line_item_id was passed
1142
-        if (! empty($line_item_codes) && ! is_array($line_item_codes)) {
1143
-            // place single line_item_id in an array to appear as multiple line_item_ids
1144
-            $line_item_codes = array($line_item_codes);
1145
-        }
1146
-        $removals = 0;
1147
-        // cycle thru line_item_ids
1148
-        foreach ($line_item_codes as $line_item_id) {
1149
-            $removals += $total_line_item->delete_child_line_item($line_item_id);
1150
-        }
1151
-
1152
-        if ($removals > 0) {
1153
-            $total_line_item->recalculate_taxes_and_tax_total();
1154
-            return $removals;
1155
-        } else {
1156
-            return false;
1157
-        }
1158
-    }
1159
-
1160
-
1161
-    /**
1162
-     * Overwrites the previous tax by clearing out the old taxes, and creates a new
1163
-     * tax and updates the total line item accordingly
1164
-     *
1165
-     * @param EE_Line_Item $total_line_item
1166
-     * @param float        $amount
1167
-     * @param string       $name
1168
-     * @param string       $description
1169
-     * @param string       $code
1170
-     * @param boolean      $add_to_existing_line_item
1171
-     *                          if true, and a duplicate line item with the same code is found,
1172
-     *                          $amount will be added onto it; otherwise will simply set the taxes to match $amount
1173
-     * @return EE_Line_Item the new tax line item created
1174
-     * @throws EE_Error
1175
-     * @throws InvalidArgumentException
1176
-     * @throws InvalidDataTypeException
1177
-     * @throws InvalidInterfaceException
1178
-     * @throws ReflectionException
1179
-     */
1180
-    public static function set_total_tax_to(
1181
-        EE_Line_Item $total_line_item,
1182
-        $amount,
1183
-        $name = null,
1184
-        $description = null,
1185
-        $code = null,
1186
-        $add_to_existing_line_item = false
1187
-    ) {
1188
-        $tax_subtotal = self::get_taxes_subtotal($total_line_item);
1189
-        $taxable_total = $total_line_item->taxable_total();
1190
-
1191
-        if ($add_to_existing_line_item) {
1192
-            $new_tax = $tax_subtotal->get_child_line_item($code);
1193
-            EEM_Line_Item::instance()->delete(
1194
-                array(array('LIN_code' => array('!=', $code), 'LIN_parent' => $tax_subtotal->ID()))
1195
-            );
1196
-        } else {
1197
-            $new_tax = null;
1198
-            $tax_subtotal->delete_children_line_items();
1199
-        }
1200
-        if ($new_tax) {
1201
-            $new_tax->set_total($new_tax->total() + $amount);
1202
-            $new_tax->set_percent($taxable_total ? $new_tax->total() / $taxable_total * 100 : 0);
1203
-        } else {
1204
-            // no existing tax item. Create it
1205
-            $new_tax = EE_Line_Item::new_instance(array(
1206
-                'TXN_ID'      => $total_line_item->TXN_ID(),
1207
-                'LIN_name'    => $name ?: esc_html__('Tax', 'event_espresso'),
1208
-                'LIN_desc'    => $description ?: '',
1209
-                'LIN_percent' => $taxable_total ? ($amount / $taxable_total * 100) : 0,
1210
-                'LIN_total'   => $amount,
1211
-                'LIN_parent'  => $tax_subtotal->ID(),
1212
-                'LIN_type'    => EEM_Line_Item::type_tax,
1213
-                'LIN_code'    => $code,
1214
-            ));
1215
-        }
1216
-
1217
-        $new_tax = apply_filters(
1218
-            'FHEE__EEH_Line_Item__set_total_tax_to__new_tax_subtotal',
1219
-            $new_tax,
1220
-            $total_line_item
1221
-        );
1222
-        $new_tax->save();
1223
-        $tax_subtotal->set_total($new_tax->total());
1224
-        $tax_subtotal->save();
1225
-        $total_line_item->recalculate_total_including_taxes();
1226
-        return $new_tax;
1227
-    }
1228
-
1229
-
1230
-    /**
1231
-     * Makes all the line items which are children of $line_item taxable (or not).
1232
-     * Does NOT save the line items
1233
-     *
1234
-     * @param EE_Line_Item $line_item
1235
-     * @param boolean      $taxable
1236
-     * @param string       $code_substring_for_whitelist if this string is part of the line item's code
1237
-     *                                                   it will be whitelisted (ie, except from becoming taxable)
1238
-     * @throws EE_Error
1239
-     */
1240
-    public static function set_line_items_taxable(
1241
-        EE_Line_Item $line_item,
1242
-        $taxable = true,
1243
-        $code_substring_for_whitelist = null
1244
-    ) {
1245
-        $whitelisted = false;
1246
-        if ($code_substring_for_whitelist !== null) {
1247
-            $whitelisted = strpos($line_item->code(), $code_substring_for_whitelist) !== false;
1248
-        }
1249
-        if (! $whitelisted && $line_item->is_line_item()) {
1250
-            $line_item->set_is_taxable($taxable);
1251
-        }
1252
-        foreach ($line_item->children() as $child_line_item) {
1253
-            EEH_Line_Item::set_line_items_taxable(
1254
-                $child_line_item,
1255
-                $taxable,
1256
-                $code_substring_for_whitelist
1257
-            );
1258
-        }
1259
-    }
1260
-
1261
-
1262
-    /**
1263
-     * Gets all descendants that are event subtotals
1264
-     *
1265
-     * @uses  EEH_Line_Item::get_subtotals_of_object_type()
1266
-     * @param EE_Line_Item $parent_line_item - the line item to find descendants of
1267
-     * @return EE_Line_Item[]
1268
-     * @throws EE_Error
1269
-     */
1270
-    public static function get_event_subtotals(EE_Line_Item $parent_line_item)
1271
-    {
1272
-        return self::get_subtotals_of_object_type($parent_line_item, EEM_Line_Item::OBJ_TYPE_EVENT);
1273
-    }
1274
-
1275
-
1276
-    /**
1277
-     * Gets all descendants subtotals that match the supplied object type
1278
-     *
1279
-     * @uses  EEH_Line_Item::_get_descendants_by_type_and_object_type()
1280
-     * @param EE_Line_Item $parent_line_item - the line item to find descendants of
1281
-     * @param string       $obj_type
1282
-     * @return EE_Line_Item[]
1283
-     * @throws EE_Error
1284
-     */
1285
-    public static function get_subtotals_of_object_type(EE_Line_Item $parent_line_item, $obj_type = '')
1286
-    {
1287
-        return self::_get_descendants_by_type_and_object_type(
1288
-            $parent_line_item,
1289
-            EEM_Line_Item::type_sub_total,
1290
-            $obj_type
1291
-        );
1292
-    }
1293
-
1294
-
1295
-    /**
1296
-     * Gets all descendants that are tickets
1297
-     *
1298
-     * @uses  EEH_Line_Item::get_line_items_of_object_type()
1299
-     * @param EE_Line_Item $parent_line_item - the line item to find descendants of
1300
-     * @return EE_Line_Item[]
1301
-     * @throws EE_Error
1302
-     */
1303
-    public static function get_ticket_line_items(EE_Line_Item $parent_line_item)
1304
-    {
1305
-        return self::get_line_items_of_object_type(
1306
-            $parent_line_item,
1307
-            EEM_Line_Item::OBJ_TYPE_TICKET
1308
-        );
1309
-    }
1310
-
1311
-
1312
-    /**
1313
-     * Gets all descendants subtotals that match the supplied object type
1314
-     *
1315
-     * @uses  EEH_Line_Item::_get_descendants_by_type_and_object_type()
1316
-     * @param EE_Line_Item $parent_line_item - the line item to find descendants of
1317
-     * @param string       $obj_type
1318
-     * @return EE_Line_Item[]
1319
-     * @throws EE_Error
1320
-     */
1321
-    public static function get_line_items_of_object_type(EE_Line_Item $parent_line_item, $obj_type = '')
1322
-    {
1323
-        return self::_get_descendants_by_type_and_object_type(
1324
-            $parent_line_item,
1325
-            EEM_Line_Item::type_line_item,
1326
-            $obj_type
1327
-        );
1328
-    }
1329
-
1330
-
1331
-    /**
1332
-     * Gets all the descendants (ie, children or children of children etc) that are of the type 'tax'
1333
-     *
1334
-     * @uses  EEH_Line_Item::get_descendants_of_type()
1335
-     * @param EE_Line_Item $parent_line_item - the line item to find descendants of
1336
-     * @return EE_Line_Item[]
1337
-     * @throws EE_Error
1338
-     */
1339
-    public static function get_tax_descendants(EE_Line_Item $parent_line_item)
1340
-    {
1341
-        return EEH_Line_Item::get_descendants_of_type(
1342
-            $parent_line_item,
1343
-            EEM_Line_Item::type_tax
1344
-        );
1345
-    }
1346
-
1347
-
1348
-    /**
1349
-     * Gets all the real items purchased which are children of this item
1350
-     *
1351
-     * @uses  EEH_Line_Item::get_descendants_of_type()
1352
-     * @param EE_Line_Item $parent_line_item - the line item to find descendants of
1353
-     * @return EE_Line_Item[]
1354
-     * @throws EE_Error
1355
-     */
1356
-    public static function get_line_item_descendants(EE_Line_Item $parent_line_item)
1357
-    {
1358
-        return EEH_Line_Item::get_descendants_of_type(
1359
-            $parent_line_item,
1360
-            EEM_Line_Item::type_line_item
1361
-        );
1362
-    }
1363
-
1364
-
1365
-    /**
1366
-     * Gets all descendants of supplied line item that match the supplied line item type
1367
-     *
1368
-     * @uses  EEH_Line_Item::_get_descendants_by_type_and_object_type()
1369
-     * @param EE_Line_Item $parent_line_item - the line item to find descendants of
1370
-     * @param string       $line_item_type   one of the EEM_Line_Item constants
1371
-     * @return EE_Line_Item[]
1372
-     * @throws EE_Error
1373
-     */
1374
-    public static function get_descendants_of_type(EE_Line_Item $parent_line_item, $line_item_type)
1375
-    {
1376
-        return self::_get_descendants_by_type_and_object_type(
1377
-            $parent_line_item,
1378
-            $line_item_type,
1379
-            null
1380
-        );
1381
-    }
1382
-
1383
-
1384
-    /**
1385
-     * Gets all descendants of supplied line item that match the supplied line item type and possibly the object type
1386
-     * as well
1387
-     *
1388
-     * @param EE_Line_Item  $parent_line_item - the line item to find descendants of
1389
-     * @param string        $line_item_type   one of the EEM_Line_Item constants
1390
-     * @param string | NULL $obj_type         object model class name (minus prefix) or NULL to ignore object type when
1391
-     *                                        searching
1392
-     * @return EE_Line_Item[]
1393
-     * @throws EE_Error
1394
-     */
1395
-    protected static function _get_descendants_by_type_and_object_type(
1396
-        EE_Line_Item $parent_line_item,
1397
-        $line_item_type,
1398
-        $obj_type = null
1399
-    ) {
1400
-        $objects = array();
1401
-        foreach ($parent_line_item->children() as $child_line_item) {
1402
-            if ($child_line_item instanceof EE_Line_Item) {
1403
-                if (
1404
-                    $child_line_item->type() === $line_item_type
1405
-                    && (
1406
-                        $child_line_item->OBJ_type() === $obj_type || $obj_type === null
1407
-                    )
1408
-                ) {
1409
-                    $objects[] = $child_line_item;
1410
-                } else {
1411
-                    // go-through-all-its children looking for more matches
1412
-                    $objects = array_merge(
1413
-                        $objects,
1414
-                        self::_get_descendants_by_type_and_object_type(
1415
-                            $child_line_item,
1416
-                            $line_item_type,
1417
-                            $obj_type
1418
-                        )
1419
-                    );
1420
-                }
1421
-            }
1422
-        }
1423
-        return $objects;
1424
-    }
1425
-
1426
-
1427
-    /**
1428
-     * Gets all descendants subtotals that match the supplied object type
1429
-     *
1430
-     * @uses  EEH_Line_Item::_get_descendants_by_type_and_object_type()
1431
-     * @param EE_Line_Item $parent_line_item - the line item to find descendants of
1432
-     * @param string       $OBJ_type         object type (like Event)
1433
-     * @param array        $OBJ_IDs          array of OBJ_IDs
1434
-     * @return EE_Line_Item[]
1435
-     * @throws EE_Error
1436
-     */
1437
-    public static function get_line_items_by_object_type_and_IDs(
1438
-        EE_Line_Item $parent_line_item,
1439
-        $OBJ_type = '',
1440
-        $OBJ_IDs = array()
1441
-    ) {
1442
-        return self::_get_descendants_by_object_type_and_object_ID(
1443
-            $parent_line_item,
1444
-            $OBJ_type,
1445
-            $OBJ_IDs
1446
-        );
1447
-    }
1448
-
1449
-
1450
-    /**
1451
-     * Gets all descendants of supplied line item that match the supplied line item type and possibly the object type
1452
-     * as well
1453
-     *
1454
-     * @param EE_Line_Item $parent_line_item - the line item to find descendants of
1455
-     * @param string       $OBJ_type         object type (like Event)
1456
-     * @param array        $OBJ_IDs          array of OBJ_IDs
1457
-     * @return EE_Line_Item[]
1458
-     * @throws EE_Error
1459
-     */
1460
-    protected static function _get_descendants_by_object_type_and_object_ID(
1461
-        EE_Line_Item $parent_line_item,
1462
-        $OBJ_type,
1463
-        $OBJ_IDs
1464
-    ) {
1465
-        $objects = array();
1466
-        foreach ($parent_line_item->children() as $child_line_item) {
1467
-            if ($child_line_item instanceof EE_Line_Item) {
1468
-                if (
1469
-                    $child_line_item->OBJ_type() === $OBJ_type
1470
-                    && is_array($OBJ_IDs)
1471
-                    && in_array($child_line_item->OBJ_ID(), $OBJ_IDs)
1472
-                ) {
1473
-                    $objects[] = $child_line_item;
1474
-                } else {
1475
-                    // go-through-all-its children looking for more matches
1476
-                    $objects = array_merge(
1477
-                        $objects,
1478
-                        self::_get_descendants_by_object_type_and_object_ID(
1479
-                            $child_line_item,
1480
-                            $OBJ_type,
1481
-                            $OBJ_IDs
1482
-                        )
1483
-                    );
1484
-                }
1485
-            }
1486
-        }
1487
-        return $objects;
1488
-    }
1489
-
1490
-
1491
-    /**
1492
-     * Uses a breadth-first-search in order to find the nearest descendant of
1493
-     * the specified type and returns it, else NULL
1494
-     *
1495
-     * @uses  EEH_Line_Item::_get_nearest_descendant()
1496
-     * @param EE_Line_Item $parent_line_item - the line item to find descendants of
1497
-     * @param string       $type             like one of the EEM_Line_Item::type_*
1498
-     * @return EE_Line_Item
1499
-     * @throws EE_Error
1500
-     * @throws InvalidArgumentException
1501
-     * @throws InvalidDataTypeException
1502
-     * @throws InvalidInterfaceException
1503
-     * @throws ReflectionException
1504
-     */
1505
-    public static function get_nearest_descendant_of_type(EE_Line_Item $parent_line_item, $type)
1506
-    {
1507
-        return self::_get_nearest_descendant($parent_line_item, 'LIN_type', $type);
1508
-    }
1509
-
1510
-
1511
-    /**
1512
-     * Uses a breadth-first-search in order to find the nearest descendant
1513
-     * having the specified LIN_code and returns it, else NULL
1514
-     *
1515
-     * @uses  EEH_Line_Item::_get_nearest_descendant()
1516
-     * @param EE_Line_Item $parent_line_item - the line item to find descendants of
1517
-     * @param string       $code             any value used for LIN_code
1518
-     * @return EE_Line_Item
1519
-     * @throws EE_Error
1520
-     * @throws InvalidArgumentException
1521
-     * @throws InvalidDataTypeException
1522
-     * @throws InvalidInterfaceException
1523
-     * @throws ReflectionException
1524
-     */
1525
-    public static function get_nearest_descendant_having_code(EE_Line_Item $parent_line_item, $code)
1526
-    {
1527
-        return self::_get_nearest_descendant($parent_line_item, 'LIN_code', $code);
1528
-    }
1529
-
1530
-
1531
-    /**
1532
-     * Uses a breadth-first-search in order to find the nearest descendant
1533
-     * having the specified LIN_code and returns it, else NULL
1534
-     *
1535
-     * @param EE_Line_Item $parent_line_item - the line item to find descendants of
1536
-     * @param string       $search_field     name of EE_Line_Item property
1537
-     * @param string       $value            any value stored in $search_field
1538
-     * @return EE_Line_Item
1539
-     * @throws EE_Error
1540
-     * @throws InvalidArgumentException
1541
-     * @throws InvalidDataTypeException
1542
-     * @throws InvalidInterfaceException
1543
-     * @throws ReflectionException
1544
-     */
1545
-    protected static function _get_nearest_descendant(EE_Line_Item $parent_line_item, $search_field, $value)
1546
-    {
1547
-        foreach ($parent_line_item->children() as $child) {
1548
-            if ($child->get($search_field) == $value) {
1549
-                return $child;
1550
-            }
1551
-        }
1552
-        foreach ($parent_line_item->children() as $child) {
1553
-            $descendant_found = self::_get_nearest_descendant(
1554
-                $child,
1555
-                $search_field,
1556
-                $value
1557
-            );
1558
-            if ($descendant_found) {
1559
-                return $descendant_found;
1560
-            }
1561
-        }
1562
-        return null;
1563
-    }
1564
-
1565
-
1566
-    /**
1567
-     * if passed line item has a TXN ID, uses that to jump directly to the grand total line item for the transaction,
1568
-     * else recursively walks up the line item tree until a parent of type total is found,
1569
-     *
1570
-     * @param EE_Line_Item $line_item
1571
-     * @return EE_Line_Item
1572
-     * @throws EE_Error
1573
-     * @throws ReflectionException
1574
-     */
1575
-    public static function find_transaction_grand_total_for_line_item(EE_Line_Item $line_item): EE_Line_Item
1576
-    {
1577
-        if ($line_item->is_total()) {
1578
-            return $line_item;
1579
-        }
1580
-        if ($line_item->TXN_ID()) {
1581
-            $total_line_item = $line_item->transaction()->total_line_item(false);
1582
-            if ($total_line_item instanceof EE_Line_Item) {
1583
-                return $total_line_item;
1584
-            }
1585
-        } else {
1586
-            $line_item_parent = $line_item->parent();
1587
-            if ($line_item_parent instanceof EE_Line_Item) {
1588
-                if ($line_item_parent->is_total()) {
1589
-                    return $line_item_parent;
1590
-                }
1591
-                return EEH_Line_Item::find_transaction_grand_total_for_line_item($line_item_parent);
1592
-            }
1593
-        }
1594
-        throw new EE_Error(
1595
-            sprintf(
1596
-                esc_html__(
1597
-                    'A valid grand total for line item %1$d was not found.',
1598
-                    'event_espresso'
1599
-                ),
1600
-                $line_item->ID()
1601
-            )
1602
-        );
1603
-    }
1604
-
1605
-
1606
-    /**
1607
-     * Prints out a representation of the line item tree
1608
-     *
1609
-     * @param EE_Line_Item $line_item
1610
-     * @param int          $indentation
1611
-     * @return void
1612
-     * @throws EE_Error
1613
-     */
1614
-    public static function visualize(EE_Line_Item $line_item, $indentation = 0)
1615
-    {
1616
-        $new_line = defined('EE_TESTS_DIR') ? "\n" : '<br />';
1617
-        echo $new_line;
1618
-        if (! $indentation) {
1619
-            echo $new_line;
1620
-        }
1621
-        echo str_repeat('. ', $indentation);
1622
-        $breakdown = '';
1623
-        if ($line_item->is_line_item() || $line_item->is_sub_line_item() || $line_item->isSubTax()) {
1624
-            if ($line_item->is_percent()) {
1625
-                $breakdown = "{$line_item->percent()}%";
1626
-            } else {
1627
-                $breakdown = "\${$line_item->unit_price()} x {$line_item->quantity()}";
1628
-            }
1629
-        }
1630
-        echo wp_kses($line_item->name(), AllowedTags::getAllowedTags());
1631
-        echo " [ ID:{$line_item->ID()} | qty:{$line_item->quantity()} ] {$line_item->type()} : ";
1632
-        echo "\${$line_item->total()}";
1633
-        if ($breakdown) {
1634
-            echo " ( {$breakdown} )";
1635
-        }
1636
-        if ($line_item->is_taxable()) {
1637
-            echo '  * taxable';
1638
-        }
1639
-        if ($line_item->children()) {
1640
-            foreach ($line_item->children() as $child) {
1641
-                self::visualize($child, $indentation + 1);
1642
-            }
1643
-        }
1644
-        if (! $indentation) {
1645
-            echo $new_line . $new_line;
1646
-        }
1647
-    }
1648
-
1649
-
1650
-    /**
1651
-     * Calculates the registration's final price, taking into account that they
1652
-     * need to not only help pay for their OWN ticket, but also any transaction-wide surcharges and taxes,
1653
-     * and receive a portion of any transaction-wide discounts.
1654
-     * eg1, if I buy a $1 ticket and brent buys a $9 ticket, and we receive a $5 discount
1655
-     * then I'll get 1/10 of that $5 discount, which is $0.50, and brent will get
1656
-     * 9/10ths of that $5 discount, which is $4.50. So my final price should be $0.50
1657
-     * and brent's final price should be $5.50.
1658
-     * In order to do this, we basically need to traverse the line item tree calculating
1659
-     * the running totals (just as if we were recalculating the total), but when we identify
1660
-     * regular line items, we need to keep track of their share of the grand total.
1661
-     * Also, we need to keep track of the TAXABLE total for each ticket purchase, so
1662
-     * we can know how to apply taxes to it. (Note: "taxable total" does not equal the "pretax total"
1663
-     * when there are non-taxable items; otherwise they would be the same)
1664
-     *
1665
-     * @param EE_Line_Item $line_item
1666
-     * @param array        $billable_ticket_quantities  array of EE_Ticket IDs and their corresponding quantity that
1667
-     *                                                  can be included in price calculations at this moment
1668
-     * @return array        keys are line items for tickets IDs and values are their share of the running total,
1669
-     *                                                  plus the key 'total', and 'taxable' which also has keys of all
1670
-     *                                                  the ticket IDs.
1671
-     *                                                  Eg array(
1672
-     *                                                      12 => 4.3
1673
-     *                                                      23 => 8.0
1674
-     *                                                      'total' => 16.6,
1675
-     *                                                      'taxable' => array(
1676
-     *                                                          12 => 10,
1677
-     *                                                          23 => 4
1678
-     *                                                      ).
1679
-     *                                                  So to find which registrations have which final price, we need
1680
-     *                                                  to find which line item is theirs, which can be done with
1681
-     *                                                  `EEM_Line_Item::instance()->get_line_item_for_registration(
1682
-     *                                                  $registration );`
1683
-     * @throws EE_Error
1684
-     * @throws InvalidArgumentException
1685
-     * @throws InvalidDataTypeException
1686
-     * @throws InvalidInterfaceException
1687
-     * @throws ReflectionException
1688
-     */
1689
-    public static function calculate_reg_final_prices_per_line_item(
1690
-        EE_Line_Item $line_item,
1691
-        $billable_ticket_quantities = array()
1692
-    ) {
1693
-        $running_totals = [
1694
-            'total'   => 0,
1695
-            'taxable' => ['total' => 0]
1696
-        ];
1697
-        foreach ($line_item->children() as $child_line_item) {
1698
-            switch ($child_line_item->type()) {
1699
-                case EEM_Line_Item::type_sub_total:
1700
-                    $running_totals_from_subtotal = EEH_Line_Item::calculate_reg_final_prices_per_line_item(
1701
-                        $child_line_item,
1702
-                        $billable_ticket_quantities
1703
-                    );
1704
-                    // combine arrays but preserve numeric keys
1705
-                    $running_totals = array_replace_recursive($running_totals_from_subtotal, $running_totals);
1706
-                    $running_totals['total'] += $running_totals_from_subtotal['total'];
1707
-                    $running_totals['taxable']['total'] += $running_totals_from_subtotal['taxable']['total'];
1708
-                    break;
1709
-
1710
-                case EEM_Line_Item::type_tax_sub_total:
1711
-                    // find how much the taxes percentage is
1712
-                    if ($child_line_item->percent() !== 0) {
1713
-                        $tax_percent_decimal = $child_line_item->percent() / 100;
1714
-                    } else {
1715
-                        $tax_percent_decimal = EE_Taxes::get_total_taxes_percentage() / 100;
1716
-                    }
1717
-                    // and apply to all the taxable totals, and add to the pretax totals
1718
-                    foreach ($running_totals as $line_item_id => $this_running_total) {
1719
-                        // "total" and "taxable" array key is an exception
1720
-                        if ($line_item_id === 'taxable') {
1721
-                            continue;
1722
-                        }
1723
-                        $taxable_total = $running_totals['taxable'][ $line_item_id ];
1724
-                        $running_totals[ $line_item_id ] += ($taxable_total * $tax_percent_decimal);
1725
-                    }
1726
-                    break;
1727
-
1728
-                case EEM_Line_Item::type_line_item:
1729
-                    // ticket line items or ????
1730
-                    if ($child_line_item->OBJ_type() === EEM_Line_Item::OBJ_TYPE_TICKET) {
1731
-                        // kk it's a ticket
1732
-                        if (isset($running_totals[ $child_line_item->ID() ])) {
1733
-                            // huh? that shouldn't happen.
1734
-                            $running_totals['total'] += $child_line_item->total();
1735
-                        } else {
1736
-                            // its not in our running totals yet. great.
1737
-                            if ($child_line_item->is_taxable()) {
1738
-                                $taxable_amount = $child_line_item->unit_price();
1739
-                            } else {
1740
-                                $taxable_amount = 0;
1741
-                            }
1742
-                            // are we only calculating totals for some tickets?
1743
-                            if (isset($billable_ticket_quantities[ $child_line_item->OBJ_ID() ])) {
1744
-                                $quantity = $billable_ticket_quantities[ $child_line_item->OBJ_ID() ];
1745
-                                $running_totals[ $child_line_item->ID() ] = $quantity
1746
-                                    ? $child_line_item->unit_price()
1747
-                                    : 0;
1748
-                                $running_totals['taxable'][ $child_line_item->ID() ] = $quantity
1749
-                                    ? $taxable_amount
1750
-                                    : 0;
1751
-                            } else {
1752
-                                $quantity = $child_line_item->quantity();
1753
-                                $running_totals[ $child_line_item->ID() ] = $child_line_item->unit_price();
1754
-                                $running_totals['taxable'][ $child_line_item->ID() ] = $taxable_amount;
1755
-                            }
1756
-                            $running_totals['taxable']['total'] += $taxable_amount * $quantity;
1757
-                            $running_totals['total'] += $child_line_item->unit_price() * $quantity;
1758
-                        }
1759
-                    } else {
1760
-                        // it's some other type of item added to the cart
1761
-                        // it should affect the running totals
1762
-                        // basically we want to convert it into a PERCENT modifier. Because
1763
-                        // more clearly affect all registration's final price equally
1764
-                        $line_items_percent_of_running_total = $running_totals['total'] > 0
1765
-                            ? ($child_line_item->total() / $running_totals['total']) + 1
1766
-                            : 1;
1767
-                        foreach ($running_totals as $line_item_id => $this_running_total) {
1768
-                            // the "taxable" array key is an exception
1769
-                            if ($line_item_id === 'taxable') {
1770
-                                continue;
1771
-                            }
1772
-                            // update the running totals
1773
-                            // yes this actually even works for the running grand total!
1774
-                            $running_totals[ $line_item_id ] =
1775
-                                $line_items_percent_of_running_total * $this_running_total;
1776
-
1777
-                            if ($child_line_item->is_taxable()) {
1778
-                                $running_totals['taxable'][ $line_item_id ] =
1779
-                                    $line_items_percent_of_running_total * $running_totals['taxable'][ $line_item_id ];
1780
-                            }
1781
-                        }
1782
-                    }
1783
-                    break;
1784
-            }
1785
-        }
1786
-        return $running_totals;
1787
-    }
1788
-
1789
-
1790
-    /**
1791
-     * @param EE_Line_Item $total_line_item
1792
-     * @param EE_Line_Item $ticket_line_item
1793
-     * @return float | null
1794
-     * @throws EE_Error
1795
-     * @throws InvalidArgumentException
1796
-     * @throws InvalidDataTypeException
1797
-     * @throws InvalidInterfaceException
1798
-     * @throws OutOfRangeException
1799
-     * @throws ReflectionException
1800
-     */
1801
-    public static function calculate_final_price_for_ticket_line_item(
1802
-        EE_Line_Item $total_line_item,
1803
-        EE_Line_Item $ticket_line_item
1804
-    ) {
1805
-        static $final_prices_per_ticket_line_item = array();
1806
-        if (empty($final_prices_per_ticket_line_item) || empty($final_prices_per_ticket_line_item[ $total_line_item->ID() ])) {
1807
-            $final_prices_per_ticket_line_item[ $total_line_item->ID() ] = EEH_Line_Item::calculate_reg_final_prices_per_line_item(
1808
-                $total_line_item
1809
-            );
1810
-        }
1811
-        // ok now find this new registration's final price
1812
-        if (isset($final_prices_per_ticket_line_item[ $total_line_item->ID() ][ $ticket_line_item->ID() ])) {
1813
-            return $final_prices_per_ticket_line_item[ $total_line_item->ID() ][ $ticket_line_item->ID() ];
1814
-        }
1815
-        $message = sprintf(
1816
-            esc_html__(
1817
-                'The final price for the ticket line item (ID:%1$d) on the total line item (ID:%2$d) could not be calculated.',
1818
-                'event_espresso'
1819
-            ),
1820
-            $ticket_line_item->ID(),
1821
-            $total_line_item->ID()
1822
-        );
1823
-        if (WP_DEBUG) {
1824
-            $message .= '<br>' . print_r($final_prices_per_ticket_line_item, true);
1825
-            throw new OutOfRangeException($message);
1826
-        }
1827
-        EE_Log::instance()->log(__CLASS__, __FUNCTION__, $message);
1828
-        return null;
1829
-    }
1830
-
1831
-
1832
-    /**
1833
-     * Creates a duplicate of the line item tree, except only includes billable items
1834
-     * and the portion of line items attributed to billable things
1835
-     *
1836
-     * @param EE_Line_Item      $line_item
1837
-     * @param EE_Registration[] $registrations
1838
-     * @return EE_Line_Item
1839
-     * @throws EE_Error
1840
-     * @throws InvalidArgumentException
1841
-     * @throws InvalidDataTypeException
1842
-     * @throws InvalidInterfaceException
1843
-     * @throws ReflectionException
1844
-     */
1845
-    public static function billable_line_item_tree(EE_Line_Item $line_item, $registrations)
1846
-    {
1847
-        $copy_li = EEH_Line_Item::billable_line_item($line_item, $registrations);
1848
-        foreach ($line_item->children() as $child_li) {
1849
-            $copy_li->add_child_line_item(
1850
-                EEH_Line_Item::billable_line_item_tree($child_li, $registrations)
1851
-            );
1852
-        }
1853
-        // if this is the grand total line item, make sure the totals all add up
1854
-        // (we could have duplicated this logic AS we copied the line items, but
1855
-        // it seems DRYer this way)
1856
-        if ($copy_li->type() === EEM_Line_Item::type_total) {
1857
-            $copy_li->recalculate_total_including_taxes();
1858
-        }
1859
-        return $copy_li;
1860
-    }
1861
-
1862
-
1863
-    /**
1864
-     * Creates a new, unsaved line item from $line_item that factors in the
1865
-     * number of billable registrations on $registrations.
1866
-     *
1867
-     * @param EE_Line_Item      $line_item
1868
-     * @param EE_Registration[] $registrations
1869
-     * @return EE_Line_Item
1870
-     * @throws EE_Error
1871
-     * @throws InvalidArgumentException
1872
-     * @throws InvalidDataTypeException
1873
-     * @throws InvalidInterfaceException
1874
-     * @throws ReflectionException
1875
-     */
1876
-    public static function billable_line_item(EE_Line_Item $line_item, $registrations)
1877
-    {
1878
-        $new_li_fields = $line_item->model_field_array();
1879
-        if (
1880
-            $line_item->type() === EEM_Line_Item::type_line_item &&
1881
-            $line_item->OBJ_type() === EEM_Line_Item::OBJ_TYPE_TICKET
1882
-        ) {
1883
-            $count = 0;
1884
-            foreach ($registrations as $registration) {
1885
-                if (
1886
-                    $line_item->OBJ_ID() === $registration->ticket_ID() &&
1887
-                    in_array(
1888
-                        $registration->status_ID(),
1889
-                        EEM_Registration::reg_statuses_that_allow_payment(),
1890
-                        true
1891
-                    )
1892
-                ) {
1893
-                    $count++;
1894
-                }
1895
-            }
1896
-            $new_li_fields['LIN_quantity'] = $count;
1897
-        }
1898
-        // don't set the total. We'll leave that up to the code that calculates it
1899
-        unset($new_li_fields['LIN_ID'], $new_li_fields['LIN_parent'], $new_li_fields['LIN_total']);
1900
-        return EE_Line_Item::new_instance($new_li_fields);
1901
-    }
1902
-
1903
-
1904
-    /**
1905
-     * Returns a modified line item tree where all the subtotals which have a total of 0
1906
-     * are removed, and line items with a quantity of 0
1907
-     *
1908
-     * @param EE_Line_Item $line_item |null
1909
-     * @return EE_Line_Item|null
1910
-     * @throws EE_Error
1911
-     * @throws InvalidArgumentException
1912
-     * @throws InvalidDataTypeException
1913
-     * @throws InvalidInterfaceException
1914
-     * @throws ReflectionException
1915
-     */
1916
-    public static function non_empty_line_items(EE_Line_Item $line_item)
1917
-    {
1918
-        $copied_li = EEH_Line_Item::non_empty_line_item($line_item);
1919
-        if ($copied_li === null) {
1920
-            return null;
1921
-        }
1922
-        // if this is an event subtotal, we want to only include it if it
1923
-        // has a non-zero total and at least one ticket line item child
1924
-        $ticket_children = 0;
1925
-        foreach ($line_item->children() as $child_li) {
1926
-            $child_li_copy = EEH_Line_Item::non_empty_line_items($child_li);
1927
-            if ($child_li_copy !== null) {
1928
-                $copied_li->add_child_line_item($child_li_copy);
1929
-                if (
1930
-                    $child_li_copy->type() === EEM_Line_Item::type_line_item &&
1931
-                    $child_li_copy->OBJ_type() === EEM_Line_Item::OBJ_TYPE_TICKET
1932
-                ) {
1933
-                    $ticket_children++;
1934
-                }
1935
-            }
1936
-        }
1937
-        // if this is an event subtotal with NO ticket children
1938
-        // we basically want to ignore it
1939
-        if (
1940
-            $ticket_children === 0
1941
-            && $line_item->type() === EEM_Line_Item::type_sub_total
1942
-            && $line_item->OBJ_type() === EEM_Line_Item::OBJ_TYPE_EVENT
1943
-            && $line_item->total() === 0
1944
-        ) {
1945
-            return null;
1946
-        }
1947
-        return $copied_li;
1948
-    }
1949
-
1950
-
1951
-    /**
1952
-     * Creates a new, unsaved line item, but if it's a ticket line item
1953
-     * with a total of 0, or a subtotal of 0, returns null instead
1954
-     *
1955
-     * @param EE_Line_Item $line_item
1956
-     * @return EE_Line_Item
1957
-     * @throws EE_Error
1958
-     * @throws InvalidArgumentException
1959
-     * @throws InvalidDataTypeException
1960
-     * @throws InvalidInterfaceException
1961
-     * @throws ReflectionException
1962
-     */
1963
-    public static function non_empty_line_item(EE_Line_Item $line_item)
1964
-    {
1965
-        if (
1966
-            $line_item->type() === EEM_Line_Item::type_line_item
1967
-            && $line_item->OBJ_type() === EEM_Line_Item::OBJ_TYPE_TICKET
1968
-            && $line_item->quantity() === 0
1969
-        ) {
1970
-            return null;
1971
-        }
1972
-        $new_li_fields = $line_item->model_field_array();
1973
-        // don't set the total. We'll leave that up to the code that calculates it
1974
-        unset($new_li_fields['LIN_ID'], $new_li_fields['LIN_parent']);
1975
-        return EE_Line_Item::new_instance($new_li_fields);
1976
-    }
1977
-
1978
-
1979
-    /**
1980
-     * Cycles through all of the ticket line items for the supplied total line item
1981
-     * and ensures that the line item's "is_taxable" field matches that of its corresponding ticket
1982
-     *
1983
-     * @param EE_Line_Item $total_line_item
1984
-     * @since 4.9.79.p
1985
-     * @throws EE_Error
1986
-     * @throws InvalidArgumentException
1987
-     * @throws InvalidDataTypeException
1988
-     * @throws InvalidInterfaceException
1989
-     * @throws ReflectionException
1990
-     */
1991
-    public static function resetIsTaxableForTickets(EE_Line_Item $total_line_item)
1992
-    {
1993
-        $ticket_line_items = self::get_ticket_line_items($total_line_item);
1994
-        foreach ($ticket_line_items as $ticket_line_item) {
1995
-            if (
1996
-                $ticket_line_item instanceof EE_Line_Item
1997
-                && $ticket_line_item->OBJ_type() === EEM_Line_Item::OBJ_TYPE_TICKET
1998
-            ) {
1999
-                $ticket = $ticket_line_item->ticket();
2000
-                if ($ticket instanceof EE_Ticket && $ticket->taxable() !== $ticket_line_item->is_taxable()) {
2001
-                    $ticket_line_item->set_is_taxable($ticket->taxable());
2002
-                    $ticket_line_item->save();
2003
-                }
2004
-            }
2005
-        }
2006
-    }
2007
-
2008
-
2009
-    /**
2010
-     * @return EE_Line_Item[]
2011
-     * @throws EE_Error
2012
-     * @throws ReflectionException
2013
-     * @since   $VID:$
2014
-     */
2015
-    private static function getGlobalTaxes(): array
2016
-    {
2017
-        if (EEH_Line_Item::$global_taxes === null) {
2018
-
2019
-            /** @type EEM_Price $EEM_Price */
2020
-            $EEM_Price = EE_Registry::instance()->load_model('Price');
2021
-            // get array of taxes via Price Model
2022
-            EEH_Line_Item::$global_taxes = $EEM_Price->get_all_prices_that_are_taxes();
2023
-            ksort(EEH_Line_Item::$global_taxes);
2024
-        }
2025
-        return EEH_Line_Item::$global_taxes;
2026
-    }
2027
-
2028
-
2029
-
2030
-    /**************************************** @DEPRECATED METHODS *************************************** */
2031
-    /**
2032
-     * @deprecated
2033
-     * @param EE_Line_Item $total_line_item
2034
-     * @return EE_Line_Item
2035
-     * @throws EE_Error
2036
-     * @throws InvalidArgumentException
2037
-     * @throws InvalidDataTypeException
2038
-     * @throws InvalidInterfaceException
2039
-     * @throws ReflectionException
2040
-     */
2041
-    public static function get_items_subtotal(EE_Line_Item $total_line_item)
2042
-    {
2043
-        EE_Error::doing_it_wrong(
2044
-            'EEH_Line_Item::get_items_subtotal()',
2045
-            sprintf(
2046
-                esc_html__('Method replaced with %1$s', 'event_espresso'),
2047
-                'EEH_Line_Item::get_pre_tax_subtotal()'
2048
-            ),
2049
-            '4.6.0'
2050
-        );
2051
-        return self::get_pre_tax_subtotal($total_line_item);
2052
-    }
2053
-
2054
-
2055
-    /**
2056
-     * @deprecated
2057
-     * @param EE_Transaction $transaction
2058
-     * @return EE_Line_Item
2059
-     * @throws EE_Error
2060
-     * @throws InvalidArgumentException
2061
-     * @throws InvalidDataTypeException
2062
-     * @throws InvalidInterfaceException
2063
-     * @throws ReflectionException
2064
-     */
2065
-    public static function create_default_total_line_item($transaction = null)
2066
-    {
2067
-        EE_Error::doing_it_wrong(
2068
-            'EEH_Line_Item::create_default_total_line_item()',
2069
-            sprintf(
2070
-                esc_html__('Method replaced with %1$s', 'event_espresso'),
2071
-                'EEH_Line_Item::create_total_line_item()'
2072
-            ),
2073
-            '4.6.0'
2074
-        );
2075
-        return self::create_total_line_item($transaction);
2076
-    }
2077
-
2078
-
2079
-    /**
2080
-     * @deprecated
2081
-     * @param EE_Line_Item   $total_line_item
2082
-     * @param EE_Transaction $transaction
2083
-     * @return EE_Line_Item
2084
-     * @throws EE_Error
2085
-     * @throws InvalidArgumentException
2086
-     * @throws InvalidDataTypeException
2087
-     * @throws InvalidInterfaceException
2088
-     * @throws ReflectionException
2089
-     */
2090
-    public static function create_default_tickets_subtotal(EE_Line_Item $total_line_item, $transaction = null)
2091
-    {
2092
-        EE_Error::doing_it_wrong(
2093
-            'EEH_Line_Item::create_default_tickets_subtotal()',
2094
-            sprintf(
2095
-                esc_html__('Method replaced with %1$s', 'event_espresso'),
2096
-                'EEH_Line_Item::create_pre_tax_subtotal()'
2097
-            ),
2098
-            '4.6.0'
2099
-        );
2100
-        return self::create_pre_tax_subtotal($total_line_item, $transaction);
2101
-    }
2102
-
2103
-
2104
-    /**
2105
-     * @deprecated
2106
-     * @param EE_Line_Item   $total_line_item
2107
-     * @param EE_Transaction $transaction
2108
-     * @return EE_Line_Item
2109
-     * @throws EE_Error
2110
-     * @throws InvalidArgumentException
2111
-     * @throws InvalidDataTypeException
2112
-     * @throws InvalidInterfaceException
2113
-     * @throws ReflectionException
2114
-     */
2115
-    public static function create_default_taxes_subtotal(EE_Line_Item $total_line_item, $transaction = null)
2116
-    {
2117
-        EE_Error::doing_it_wrong(
2118
-            'EEH_Line_Item::create_default_taxes_subtotal()',
2119
-            sprintf(
2120
-                esc_html__('Method replaced with %1$s', 'event_espresso'),
2121
-                'EEH_Line_Item::create_taxes_subtotal()'
2122
-            ),
2123
-            '4.6.0'
2124
-        );
2125
-        return self::create_taxes_subtotal($total_line_item, $transaction);
2126
-    }
2127
-
2128
-
2129
-    /**
2130
-     * @deprecated
2131
-     * @param EE_Line_Item   $total_line_item
2132
-     * @param EE_Transaction $transaction
2133
-     * @return EE_Line_Item
2134
-     * @throws EE_Error
2135
-     * @throws InvalidArgumentException
2136
-     * @throws InvalidDataTypeException
2137
-     * @throws InvalidInterfaceException
2138
-     * @throws ReflectionException
2139
-     */
2140
-    public static function create_default_event_subtotal(EE_Line_Item $total_line_item, $transaction = null)
2141
-    {
2142
-        EE_Error::doing_it_wrong(
2143
-            'EEH_Line_Item::create_default_event_subtotal()',
2144
-            sprintf(
2145
-                esc_html__('Method replaced with %1$s', 'event_espresso'),
2146
-                'EEH_Line_Item::create_event_subtotal()'
2147
-            ),
2148
-            '4.6.0'
2149
-        );
2150
-        return self::create_event_subtotal($total_line_item, $transaction);
2151
-    }
24
+	/**
25
+	 * @var EE_Line_Item[]
26
+	 */
27
+	private static $global_taxes;
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'      => $items_subtotal instanceof EE_Line_Item
71
+					? count($items_subtotal->children())
72
+					: 0,
73
+				'LIN_total'      => (float) $unit_price * (int) $quantity,
74
+				'LIN_type'       => EEM_Line_Item::type_line_item,
75
+				'LIN_code'       => $code,
76
+			]
77
+		);
78
+		$line_item      = apply_filters(
79
+			'FHEE__EEH_Line_Item__add_unrelated_item__line_item',
80
+			$line_item,
81
+			$parent_line_item
82
+		);
83
+		$added          = self::add_item($parent_line_item, $line_item, $recalculate_totals);
84
+		return $return_item ? $line_item : $added;
85
+	}
86
+
87
+
88
+	/**
89
+	 * Adds a simple item ( unrelated to any other model object) to the total line item,
90
+	 * in the correct spot in the line item tree. Does not automatically
91
+	 * re-calculate the line item totals, nor update the related transaction, nor upgrade the transaction's
92
+	 * registrations' final prices (which should probably change because of this).
93
+	 * You should call recalculate_total_including_taxes() on the grand total line item, then
94
+	 * update the transaction's total, and EE_Registration_Processor::update_registration_final_prices()
95
+	 * after using this, to keep the registration final prices in-sync with the transaction's total.
96
+	 *
97
+	 * @param EE_Line_Item $parent_line_item
98
+	 * @param string       $name
99
+	 * @param float        $percentage_amount
100
+	 * @param string       $description
101
+	 * @param boolean      $taxable
102
+	 * @param string|null  $code
103
+	 * @param bool         $return_item
104
+	 * @return boolean|EE_Line_Item success
105
+	 * @throws EE_Error
106
+	 * @throws ReflectionException
107
+	 */
108
+	public static function add_percentage_based_item(
109
+		EE_Line_Item $parent_line_item,
110
+		string $name,
111
+		float $percentage_amount,
112
+		string $description = '',
113
+		bool $taxable = false,
114
+		?string $code = null,
115
+		bool $return_item = false
116
+	) {
117
+		$total = $percentage_amount * $parent_line_item->total() / 100;
118
+		$line_item = EE_Line_Item::new_instance(
119
+			[
120
+				'LIN_name'       => $name,
121
+				'LIN_desc'       => $description,
122
+				'LIN_unit_price' => 0,
123
+				'LIN_percent'    => $percentage_amount,
124
+				'LIN_quantity'   => 1,
125
+				'LIN_is_taxable' => $taxable,
126
+				'LIN_total'      => (float) $total,
127
+				'LIN_type'       => EEM_Line_Item::type_line_item,
128
+				'LIN_parent'     => $parent_line_item->ID(),
129
+				'LIN_code'       => $code,
130
+			]
131
+		);
132
+		$line_item = apply_filters(
133
+			'FHEE__EEH_Line_Item__add_percentage_based_item__line_item',
134
+			$line_item
135
+		);
136
+		$added     = $parent_line_item->add_child_line_item($line_item, false);
137
+		return $return_item ? $line_item : $added;
138
+	}
139
+
140
+
141
+	/**
142
+	 * Returns the new line item created by adding a purchase of the ticket
143
+	 * ensures that ticket line item is saved, and that cart total has been recalculated.
144
+	 * If this ticket has already been purchased, just increments its count.
145
+	 * Automatically re-calculates the line item totals and updates the related transaction. But
146
+	 * DOES NOT automatically upgrade the transaction's registrations' final prices (which
147
+	 * should probably change because of this).
148
+	 * You should call EE_Registration_Processor::calculate_reg_final_prices_per_line_item()
149
+	 * after using this, to keep the registration final prices in-sync with the transaction's total.
150
+	 *
151
+	 * @param EE_Line_Item $total_line_item grand total line item of type EEM_Line_Item::type_total
152
+	 * @param EE_Ticket    $ticket
153
+	 * @param int          $qty
154
+	 * @return EE_Line_Item
155
+	 * @throws EE_Error
156
+	 * @throws InvalidArgumentException
157
+	 * @throws InvalidDataTypeException
158
+	 * @throws InvalidInterfaceException
159
+	 * @throws ReflectionException
160
+	 */
161
+	public static function add_ticket_purchase(EE_Line_Item $total_line_item, EE_Ticket $ticket, $qty = 1)
162
+	{
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
+		$total_line_item->recalculate_total_including_taxes();
182
+		return $line_item;
183
+	}
184
+
185
+
186
+	/**
187
+	 * Returns the new line item created by adding a purchase of the ticket
188
+	 *
189
+	 * @param EE_Line_Item $total_line_item
190
+	 * @param EE_Ticket    $ticket
191
+	 * @param int          $qty
192
+	 * @return EE_Line_Item
193
+	 * @throws EE_Error
194
+	 * @throws InvalidArgumentException
195
+	 * @throws InvalidDataTypeException
196
+	 * @throws InvalidInterfaceException
197
+	 * @throws ReflectionException
198
+	 */
199
+	public static function increment_ticket_qty_if_already_in_cart(
200
+		EE_Line_Item $total_line_item,
201
+		EE_Ticket $ticket,
202
+		$qty = 1
203
+	) {
204
+		$line_item = null;
205
+		if ($total_line_item instanceof EE_Line_Item && $total_line_item->is_total()) {
206
+			$ticket_line_items = EEH_Line_Item::get_ticket_line_items($total_line_item);
207
+			foreach ((array) $ticket_line_items as $ticket_line_item) {
208
+				if (
209
+					$ticket_line_item instanceof EE_Line_Item
210
+					&& (int) $ticket_line_item->OBJ_ID() === (int) $ticket->ID()
211
+				) {
212
+					$line_item = $ticket_line_item;
213
+					break;
214
+				}
215
+			}
216
+		}
217
+		if ($line_item instanceof EE_Line_Item) {
218
+			EEH_Line_Item::increment_quantity($line_item, $qty);
219
+			return $line_item;
220
+		}
221
+		return null;
222
+	}
223
+
224
+
225
+	/**
226
+	 * Increments the line item and all its children's quantity by $qty (but percent line items are unaffected).
227
+	 * Does NOT save or recalculate other line items totals
228
+	 *
229
+	 * @param EE_Line_Item $line_item
230
+	 * @param int          $qty
231
+	 * @return void
232
+	 * @throws EE_Error
233
+	 * @throws InvalidArgumentException
234
+	 * @throws InvalidDataTypeException
235
+	 * @throws InvalidInterfaceException
236
+	 * @throws ReflectionException
237
+	 */
238
+	public static function increment_quantity(EE_Line_Item $line_item, $qty = 1)
239
+	{
240
+		if (! $line_item->is_percent()) {
241
+			$qty += $line_item->quantity();
242
+			$line_item->set_quantity($qty);
243
+			$line_item->set_total($line_item->unit_price() * $qty);
244
+			$line_item->save();
245
+		}
246
+		foreach ($line_item->children() as $child) {
247
+			if ($child->is_sub_line_item()) {
248
+				EEH_Line_Item::update_quantity($child, $qty);
249
+			}
250
+		}
251
+	}
252
+
253
+
254
+	/**
255
+	 * Decrements the line item and all its children's quantity by $qty (but percent line items are unaffected).
256
+	 * Does NOT save or recalculate other line items totals
257
+	 *
258
+	 * @param EE_Line_Item $line_item
259
+	 * @param int          $qty
260
+	 * @return void
261
+	 * @throws EE_Error
262
+	 * @throws InvalidArgumentException
263
+	 * @throws InvalidDataTypeException
264
+	 * @throws InvalidInterfaceException
265
+	 * @throws ReflectionException
266
+	 */
267
+	public static function decrement_quantity(EE_Line_Item $line_item, $qty = 1)
268
+	{
269
+		if (! $line_item->is_percent()) {
270
+			$qty = $line_item->quantity() - $qty;
271
+			$qty = max($qty, 0);
272
+			$line_item->set_quantity($qty);
273
+			$line_item->set_total($line_item->unit_price() * $qty);
274
+			$line_item->save();
275
+		}
276
+		foreach ($line_item->children() as $child) {
277
+			if ($child->is_sub_line_item()) {
278
+				EEH_Line_Item::update_quantity($child, $qty);
279
+			}
280
+		}
281
+	}
282
+
283
+
284
+	/**
285
+	 * Updates the line item and its children's quantities to the specified number.
286
+	 * Does NOT save them or recalculate totals.
287
+	 *
288
+	 * @param EE_Line_Item $line_item
289
+	 * @param int          $new_quantity
290
+	 * @throws EE_Error
291
+	 * @throws InvalidArgumentException
292
+	 * @throws InvalidDataTypeException
293
+	 * @throws InvalidInterfaceException
294
+	 * @throws ReflectionException
295
+	 */
296
+	public static function update_quantity(EE_Line_Item $line_item, $new_quantity)
297
+	{
298
+		if (! $line_item->is_percent()) {
299
+			$line_item->set_quantity($new_quantity);
300
+			$line_item->set_total($line_item->unit_price() * $new_quantity);
301
+			$line_item->save();
302
+		}
303
+		foreach ($line_item->children() as $child) {
304
+			if ($child->is_sub_line_item()) {
305
+				EEH_Line_Item::update_quantity($child, $new_quantity);
306
+			}
307
+		}
308
+	}
309
+
310
+
311
+	/**
312
+	 * Returns the new line item created by adding a purchase of the ticket
313
+	 *
314
+	 * @param EE_Line_Item $total_line_item of type EEM_Line_Item::type_total
315
+	 * @param EE_Ticket    $ticket
316
+	 * @param int          $qty
317
+	 * @return EE_Line_Item
318
+	 * @throws EE_Error
319
+	 * @throws InvalidArgumentException
320
+	 * @throws InvalidDataTypeException
321
+	 * @throws InvalidInterfaceException
322
+	 * @throws ReflectionException
323
+	 */
324
+	public static function create_ticket_line_item(EE_Line_Item $total_line_item, EE_Ticket $ticket, $qty = 1)
325
+	{
326
+		$datetimes = $ticket->datetimes();
327
+		$first_datetime = reset($datetimes);
328
+		$first_datetime_name = esc_html__('Event', 'event_espresso');
329
+		if ($first_datetime instanceof EE_Datetime && $first_datetime->event() instanceof EE_Event) {
330
+			$first_datetime_name = $first_datetime->event()->name();
331
+		}
332
+		$event = sprintf(_x('(For %1$s)', '(For Event Name)', 'event_espresso'), $first_datetime_name);
333
+		// get event subtotal line
334
+		$events_sub_total = self::get_event_line_item_for_ticket($total_line_item, $ticket);
335
+		$taxes = $ticket->tax_price_modifiers();
336
+		// add $ticket to cart
337
+		$line_item = EE_Line_Item::new_instance(array(
338
+			'LIN_name'       => $ticket->name(),
339
+			'LIN_desc'       => $ticket->description() !== '' ? $ticket->description() . ' ' . $event : $event,
340
+			'LIN_unit_price' => $ticket->price(),
341
+			'LIN_quantity'   => $qty,
342
+			'LIN_is_taxable' => empty($taxes) && $ticket->taxable(),
343
+			'LIN_order'      => count($events_sub_total->children()),
344
+			'LIN_total'      => $ticket->price() * $qty,
345
+			'LIN_type'       => EEM_Line_Item::type_line_item,
346
+			'OBJ_ID'         => $ticket->ID(),
347
+			'OBJ_type'       => EEM_Line_Item::OBJ_TYPE_TICKET,
348
+		));
349
+		$line_item = apply_filters(
350
+			'FHEE__EEH_Line_Item__create_ticket_line_item__line_item',
351
+			$line_item
352
+		);
353
+		if (!$line_item instanceof EE_Line_Item) {
354
+			throw new DomainException(
355
+				esc_html__('Invalid EE_Line_Item received.', 'event_espresso')
356
+			);
357
+		}
358
+		$events_sub_total->add_child_line_item($line_item);
359
+		// now add the sub-line items
360
+		$running_total = 0;
361
+		$running_pre_tax_total = 0;
362
+		foreach ($ticket->prices() as $price) {
363
+			$sign = $price->is_discount() ? -1 : 1;
364
+			$price_total = $price->is_percent()
365
+				? $running_pre_tax_total * $price->amount() / 100
366
+				: $price->amount() * $qty;
367
+			if ($price->is_percent()) {
368
+				$percent = $sign * $price->amount();
369
+				$unit_price = 0;
370
+			} else {
371
+				$percent    = 0;
372
+				$unit_price = $sign * $price->amount();
373
+			}
374
+			$sub_line_item = EE_Line_Item::new_instance(array(
375
+				'LIN_name'       => $price->name(),
376
+				'LIN_desc'       => $price->desc(),
377
+				'LIN_quantity'   => $price->is_percent() ? null : $qty,
378
+				'LIN_is_taxable' => false,
379
+				'LIN_order'      => $price->order(),
380
+				'LIN_total'      => $price_total,
381
+				'LIN_pretax'     => 0,
382
+				'LIN_unit_price' => $unit_price,
383
+				'LIN_percent'    => $percent,
384
+				'LIN_type'       => $price->is_tax() ? EEM_Line_Item::type_sub_tax : EEM_Line_Item::type_sub_line_item,
385
+				'OBJ_ID'         => $price->ID(),
386
+				'OBJ_type'       => EEM_Line_Item::OBJ_TYPE_PRICE,
387
+			));
388
+			$sub_line_item = apply_filters(
389
+				'FHEE__EEH_Line_Item__create_ticket_line_item__sub_line_item',
390
+				$sub_line_item
391
+			);
392
+			$running_total += $sign * $price_total;
393
+			$running_pre_tax_total += ! $price->is_tax() ? $sign * $price_total : 0;
394
+			$line_item->add_child_line_item($sub_line_item);
395
+		}
396
+		$line_item->setPretaxTotal($running_pre_tax_total);
397
+		return $line_item;
398
+	}
399
+
400
+
401
+	/**
402
+	 * Adds the specified item under the pre-tax-sub-total line item. Automatically
403
+	 * re-calculates the line item totals and updates the related transaction. But
404
+	 * DOES NOT automatically upgrade the transaction's registrations' final prices (which
405
+	 * should probably change because of this).
406
+	 * You should call EE_Registration_Processor::calculate_reg_final_prices_per_line_item()
407
+	 * after using this, to keep the registration final prices in-sync with the transaction's total.
408
+	 *
409
+	 * @param EE_Line_Item $total_line_item
410
+	 * @param EE_Line_Item $item to be added
411
+	 * @return boolean
412
+	 * @throws EE_Error
413
+	 * @throws InvalidArgumentException
414
+	 * @throws InvalidDataTypeException
415
+	 * @throws InvalidInterfaceException
416
+	 * @throws ReflectionException
417
+	 */
418
+	public static function add_item(EE_Line_Item $total_line_item, EE_Line_Item $item, $recalculate_totals = true)
419
+	{
420
+		$pre_tax_subtotal = self::get_pre_tax_subtotal($total_line_item);
421
+		if ($pre_tax_subtotal instanceof EE_Line_Item) {
422
+			$success = $pre_tax_subtotal->add_child_line_item($item);
423
+		} else {
424
+			return false;
425
+		}
426
+		if ($recalculate_totals) {
427
+			$total_line_item->recalculate_total_including_taxes();
428
+		}
429
+		return $success;
430
+	}
431
+
432
+
433
+	/**
434
+	 * cancels an existing ticket line item,
435
+	 * by decrementing it's quantity by 1 and adding a new "type_cancellation" sub-line-item.
436
+	 * ALL totals and subtotals will NEED TO BE UPDATED after performing this action
437
+	 *
438
+	 * @param EE_Line_Item $ticket_line_item
439
+	 * @param int          $qty
440
+	 * @return bool success
441
+	 * @throws EE_Error
442
+	 * @throws InvalidArgumentException
443
+	 * @throws InvalidDataTypeException
444
+	 * @throws InvalidInterfaceException
445
+	 * @throws ReflectionException
446
+	 */
447
+	public static function cancel_ticket_line_item(EE_Line_Item $ticket_line_item, $qty = 1)
448
+	{
449
+		// validate incoming line_item
450
+		if ($ticket_line_item->OBJ_type() !== EEM_Line_Item::OBJ_TYPE_TICKET) {
451
+			throw new EE_Error(
452
+				sprintf(
453
+					esc_html__(
454
+						'The supplied line item must have an Object Type of "Ticket", not %1$s.',
455
+						'event_espresso'
456
+					),
457
+					$ticket_line_item->type()
458
+				)
459
+			);
460
+		}
461
+		if ($ticket_line_item->quantity() < $qty) {
462
+			throw new EE_Error(
463
+				sprintf(
464
+					esc_html__(
465
+						'Can not cancel %1$d ticket(s) because the supplied line item has a quantity of %2$d.',
466
+						'event_espresso'
467
+					),
468
+					$qty,
469
+					$ticket_line_item->quantity()
470
+				)
471
+			);
472
+		}
473
+		// decrement ticket quantity; don't rely on auto-fixing when recalculating totals to do this
474
+		$ticket_line_item->set_quantity($ticket_line_item->quantity() - $qty);
475
+		foreach ($ticket_line_item->children() as $child_line_item) {
476
+			if (
477
+				$child_line_item->is_sub_line_item()
478
+				&& ! $child_line_item->is_percent()
479
+				&& ! $child_line_item->is_cancellation()
480
+			) {
481
+				$child_line_item->set_quantity($child_line_item->quantity() - $qty);
482
+			}
483
+		}
484
+		// get cancellation sub line item
485
+		$cancellation_line_item = EEH_Line_Item::get_descendants_of_type(
486
+			$ticket_line_item,
487
+			EEM_Line_Item::type_cancellation
488
+		);
489
+		$cancellation_line_item = reset($cancellation_line_item);
490
+		// verify that this ticket was indeed previously cancelled
491
+		if ($cancellation_line_item instanceof EE_Line_Item) {
492
+			// increment cancelled quantity
493
+			$cancellation_line_item->set_quantity($cancellation_line_item->quantity() + $qty);
494
+		} else {
495
+			// create cancellation sub line item
496
+			$cancellation_line_item = EE_Line_Item::new_instance(array(
497
+				'LIN_name'       => esc_html__('Cancellation', 'event_espresso'),
498
+				'LIN_desc'       => sprintf(
499
+					esc_html_x(
500
+						'Cancelled %1$s : %2$s',
501
+						'Cancelled Ticket Name : 2015-01-01 11:11',
502
+						'event_espresso'
503
+					),
504
+					$ticket_line_item->name(),
505
+					current_time(get_option('date_format') . ' ' . get_option('time_format'))
506
+				),
507
+				'LIN_unit_price' => 0, // $ticket_line_item->unit_price()
508
+				'LIN_quantity'   => $qty,
509
+				'LIN_is_taxable' => $ticket_line_item->is_taxable(),
510
+				'LIN_order'      => count($ticket_line_item->children()),
511
+				'LIN_total'      => 0, // $ticket_line_item->unit_price()
512
+				'LIN_type'       => EEM_Line_Item::type_cancellation,
513
+			));
514
+			$ticket_line_item->add_child_line_item($cancellation_line_item);
515
+		}
516
+		if ($ticket_line_item->save_this_and_descendants() > 0) {
517
+			// decrement parent line item quantity
518
+			$event_line_item = $ticket_line_item->parent();
519
+			if (
520
+				$event_line_item instanceof EE_Line_Item
521
+				&& $event_line_item->OBJ_type() === EEM_Line_Item::OBJ_TYPE_EVENT
522
+			) {
523
+				$event_line_item->set_quantity($event_line_item->quantity() - $qty);
524
+				$event_line_item->save();
525
+			}
526
+			EEH_Line_Item::get_grand_total_and_recalculate_everything($ticket_line_item);
527
+			return true;
528
+		}
529
+		return false;
530
+	}
531
+
532
+
533
+	/**
534
+	 * reinstates (un-cancels?) a previously canceled ticket line item,
535
+	 * by incrementing it's quantity by 1, and decrementing it's "type_cancellation" sub-line-item.
536
+	 * ALL totals and subtotals will NEED TO BE UPDATED after performing this action
537
+	 *
538
+	 * @param EE_Line_Item $ticket_line_item
539
+	 * @param int          $qty
540
+	 * @return bool success
541
+	 * @throws EE_Error
542
+	 * @throws InvalidArgumentException
543
+	 * @throws InvalidDataTypeException
544
+	 * @throws InvalidInterfaceException
545
+	 * @throws ReflectionException
546
+	 */
547
+	public static function reinstate_canceled_ticket_line_item(EE_Line_Item $ticket_line_item, $qty = 1)
548
+	{
549
+		// validate incoming line_item
550
+		if ($ticket_line_item->OBJ_type() !== EEM_Line_Item::OBJ_TYPE_TICKET) {
551
+			throw new EE_Error(
552
+				sprintf(
553
+					esc_html__(
554
+						'The supplied line item must have an Object Type of "Ticket", not %1$s.',
555
+						'event_espresso'
556
+					),
557
+					$ticket_line_item->type()
558
+				)
559
+			);
560
+		}
561
+		// get cancellation sub line item
562
+		$cancellation_line_item = EEH_Line_Item::get_descendants_of_type(
563
+			$ticket_line_item,
564
+			EEM_Line_Item::type_cancellation
565
+		);
566
+		$cancellation_line_item = reset($cancellation_line_item);
567
+		// verify that this ticket was indeed previously cancelled
568
+		if (! $cancellation_line_item instanceof EE_Line_Item) {
569
+			return false;
570
+		}
571
+		if ($cancellation_line_item->quantity() > $qty) {
572
+			// decrement cancelled quantity
573
+			$cancellation_line_item->set_quantity($cancellation_line_item->quantity() - $qty);
574
+		} elseif ($cancellation_line_item->quantity() === $qty) {
575
+			// decrement cancelled quantity in case anyone still has the object kicking around
576
+			$cancellation_line_item->set_quantity($cancellation_line_item->quantity() - $qty);
577
+			// delete because quantity will end up as 0
578
+			$cancellation_line_item->delete();
579
+			// and attempt to destroy the object,
580
+			// even though PHP won't actually destroy it until it needs the memory
581
+			unset($cancellation_line_item);
582
+		} else {
583
+			// what ?!?! negative quantity ?!?!
584
+			throw new EE_Error(
585
+				sprintf(
586
+					esc_html__(
587
+						'Can not reinstate %1$d cancelled ticket(s) because the cancelled ticket quantity is only %2$d.',
588
+						'event_espresso'
589
+					),
590
+					$qty,
591
+					$cancellation_line_item->quantity()
592
+				)
593
+			);
594
+		}
595
+		// increment ticket quantity
596
+		$ticket_line_item->set_quantity($ticket_line_item->quantity() + $qty);
597
+		if ($ticket_line_item->save_this_and_descendants() > 0) {
598
+			// increment parent line item quantity
599
+			$event_line_item = $ticket_line_item->parent();
600
+			if (
601
+				$event_line_item instanceof EE_Line_Item
602
+				&& $event_line_item->OBJ_type() === EEM_Line_Item::OBJ_TYPE_EVENT
603
+			) {
604
+				$event_line_item->set_quantity($event_line_item->quantity() + $qty);
605
+			}
606
+			EEH_Line_Item::get_grand_total_and_recalculate_everything($ticket_line_item);
607
+			return true;
608
+		}
609
+		return false;
610
+	}
611
+
612
+
613
+	/**
614
+	 * calls EEH_Line_Item::find_transaction_grand_total_for_line_item()
615
+	 * then EE_Line_Item::recalculate_total_including_taxes() on the result
616
+	 *
617
+	 * @param EE_Line_Item $line_item
618
+	 * @return float
619
+	 * @throws EE_Error
620
+	 * @throws InvalidArgumentException
621
+	 * @throws InvalidDataTypeException
622
+	 * @throws InvalidInterfaceException
623
+	 * @throws ReflectionException
624
+	 */
625
+	public static function get_grand_total_and_recalculate_everything(EE_Line_Item $line_item)
626
+	{
627
+		$grand_total_line_item = EEH_Line_Item::find_transaction_grand_total_for_line_item($line_item);
628
+		return $grand_total_line_item->recalculate_total_including_taxes();
629
+	}
630
+
631
+
632
+	/**
633
+	 * Gets the line item which contains the subtotal of all the items
634
+	 *
635
+	 * @param EE_Line_Item $total_line_item of type EEM_Line_Item::type_total
636
+	 * @return EE_Line_Item
637
+	 * @throws EE_Error
638
+	 * @throws InvalidArgumentException
639
+	 * @throws InvalidDataTypeException
640
+	 * @throws InvalidInterfaceException
641
+	 * @throws ReflectionException
642
+	 */
643
+	public static function get_pre_tax_subtotal(EE_Line_Item $total_line_item)
644
+	{
645
+		$pre_tax_subtotal = $total_line_item->get_child_line_item('pre-tax-subtotal');
646
+		return $pre_tax_subtotal instanceof EE_Line_Item
647
+			? $pre_tax_subtotal
648
+			: self::create_pre_tax_subtotal($total_line_item);
649
+	}
650
+
651
+
652
+	/**
653
+	 * Gets the line item for the taxes subtotal
654
+	 *
655
+	 * @param EE_Line_Item $total_line_item of type EEM_Line_Item::type_total
656
+	 * @return EE_Line_Item
657
+	 * @throws EE_Error
658
+	 * @throws InvalidArgumentException
659
+	 * @throws InvalidDataTypeException
660
+	 * @throws InvalidInterfaceException
661
+	 * @throws ReflectionException
662
+	 */
663
+	public static function get_taxes_subtotal(EE_Line_Item $total_line_item)
664
+	{
665
+		$taxes = $total_line_item->get_child_line_item('taxes');
666
+		return $taxes ? $taxes : self::create_taxes_subtotal($total_line_item);
667
+	}
668
+
669
+
670
+	/**
671
+	 * sets the TXN ID on an EE_Line_Item if passed a valid EE_Transaction object
672
+	 *
673
+	 * @param EE_Line_Item   $line_item
674
+	 * @param EE_Transaction $transaction
675
+	 * @return void
676
+	 * @throws EE_Error
677
+	 * @throws InvalidArgumentException
678
+	 * @throws InvalidDataTypeException
679
+	 * @throws InvalidInterfaceException
680
+	 * @throws ReflectionException
681
+	 */
682
+	public static function set_TXN_ID(EE_Line_Item $line_item, $transaction = null)
683
+	{
684
+		if ($transaction) {
685
+			/** @type EEM_Transaction $EEM_Transaction */
686
+			$EEM_Transaction = EE_Registry::instance()->load_model('Transaction');
687
+			$TXN_ID = $EEM_Transaction->ensure_is_ID($transaction);
688
+			$line_item->set_TXN_ID($TXN_ID);
689
+		}
690
+	}
691
+
692
+
693
+	/**
694
+	 * Creates a new default total line item for the transaction,
695
+	 * and its tickets subtotal and taxes subtotal line items (and adds the
696
+	 * existing taxes as children of the taxes subtotal line item)
697
+	 *
698
+	 * @param EE_Transaction $transaction
699
+	 * @return EE_Line_Item of type total
700
+	 * @throws EE_Error
701
+	 * @throws InvalidArgumentException
702
+	 * @throws InvalidDataTypeException
703
+	 * @throws InvalidInterfaceException
704
+	 * @throws ReflectionException
705
+	 */
706
+	public static function create_total_line_item($transaction = null)
707
+	{
708
+		$total_line_item = EE_Line_Item::new_instance(array(
709
+			'LIN_code' => 'total',
710
+			'LIN_name' => esc_html__('Grand Total', 'event_espresso'),
711
+			'LIN_type' => EEM_Line_Item::type_total,
712
+			'OBJ_type' => EEM_Line_Item::OBJ_TYPE_TRANSACTION,
713
+		));
714
+		$total_line_item = apply_filters(
715
+			'FHEE__EEH_Line_Item__create_total_line_item__total_line_item',
716
+			$total_line_item
717
+		);
718
+		self::set_TXN_ID($total_line_item, $transaction);
719
+		self::create_pre_tax_subtotal($total_line_item, $transaction);
720
+		self::create_taxes_subtotal($total_line_item, $transaction);
721
+		return $total_line_item;
722
+	}
723
+
724
+
725
+	/**
726
+	 * Creates a default items subtotal line item
727
+	 *
728
+	 * @param EE_Line_Item   $total_line_item
729
+	 * @param EE_Transaction $transaction
730
+	 * @return EE_Line_Item
731
+	 * @throws EE_Error
732
+	 * @throws InvalidArgumentException
733
+	 * @throws InvalidDataTypeException
734
+	 * @throws InvalidInterfaceException
735
+	 * @throws ReflectionException
736
+	 */
737
+	protected static function create_pre_tax_subtotal(EE_Line_Item $total_line_item, $transaction = null)
738
+	{
739
+		$pre_tax_line_item = EE_Line_Item::new_instance(array(
740
+			'LIN_code' => 'pre-tax-subtotal',
741
+			'LIN_name' => esc_html__('Pre-Tax Subtotal', 'event_espresso'),
742
+			'LIN_type' => EEM_Line_Item::type_sub_total,
743
+		));
744
+		$pre_tax_line_item = apply_filters(
745
+			'FHEE__EEH_Line_Item__create_pre_tax_subtotal__pre_tax_line_item',
746
+			$pre_tax_line_item
747
+		);
748
+		self::set_TXN_ID($pre_tax_line_item, $transaction);
749
+		$total_line_item->add_child_line_item($pre_tax_line_item);
750
+		self::create_event_subtotal($pre_tax_line_item, $transaction);
751
+		return $pre_tax_line_item;
752
+	}
753
+
754
+
755
+	/**
756
+	 * Creates a line item for the taxes subtotal and finds all the tax prices
757
+	 * and applies taxes to it
758
+	 *
759
+	 * @param EE_Line_Item   $total_line_item of type EEM_Line_Item::type_total
760
+	 * @param EE_Transaction $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_taxes_subtotal(EE_Line_Item $total_line_item, $transaction = null)
769
+	{
770
+		$tax_line_item = EE_Line_Item::new_instance(array(
771
+			'LIN_code'  => 'taxes',
772
+			'LIN_name'  => esc_html__('Taxes', 'event_espresso'),
773
+			'LIN_type'  => EEM_Line_Item::type_tax_sub_total,
774
+			'LIN_order' => 1000,// this should always come last
775
+		));
776
+		$tax_line_item = apply_filters(
777
+			'FHEE__EEH_Line_Item__create_taxes_subtotal__tax_line_item',
778
+			$tax_line_item
779
+		);
780
+		self::set_TXN_ID($tax_line_item, $transaction);
781
+		$total_line_item->add_child_line_item($tax_line_item);
782
+		// and lastly, add the actual taxes
783
+		self::apply_taxes($total_line_item);
784
+		return $tax_line_item;
785
+	}
786
+
787
+
788
+	/**
789
+	 * Creates a default items subtotal line item
790
+	 *
791
+	 * @param EE_Line_Item   $pre_tax_line_item
792
+	 * @param EE_Transaction $transaction
793
+	 * @param EE_Event       $event
794
+	 * @return EE_Line_Item
795
+	 * @throws EE_Error
796
+	 * @throws InvalidArgumentException
797
+	 * @throws InvalidDataTypeException
798
+	 * @throws InvalidInterfaceException
799
+	 * @throws ReflectionException
800
+	 */
801
+	public static function create_event_subtotal(EE_Line_Item $pre_tax_line_item, $transaction = null, $event = null)
802
+	{
803
+		$event_line_item = EE_Line_Item::new_instance(array(
804
+			'LIN_code' => self::get_event_code($event),
805
+			'LIN_name' => self::get_event_name($event),
806
+			'LIN_desc' => self::get_event_desc($event),
807
+			'LIN_type' => EEM_Line_Item::type_sub_total,
808
+			'OBJ_type' => EEM_Line_Item::OBJ_TYPE_EVENT,
809
+			'OBJ_ID'   => $event instanceof EE_Event ? $event->ID() : 0,
810
+		));
811
+		$event_line_item = apply_filters(
812
+			'FHEE__EEH_Line_Item__create_event_subtotal__event_line_item',
813
+			$event_line_item
814
+		);
815
+		self::set_TXN_ID($event_line_item, $transaction);
816
+		$pre_tax_line_item->add_child_line_item($event_line_item);
817
+		return $event_line_item;
818
+	}
819
+
820
+
821
+	/**
822
+	 * Gets what the event ticket's code SHOULD be
823
+	 *
824
+	 * @param EE_Event $event
825
+	 * @return string
826
+	 * @throws EE_Error
827
+	 */
828
+	public static function get_event_code($event)
829
+	{
830
+		return 'event-' . ($event instanceof EE_Event ? $event->ID() : '0');
831
+	}
832
+
833
+
834
+	/**
835
+	 * Gets the event name
836
+	 *
837
+	 * @param EE_Event $event
838
+	 * @return string
839
+	 * @throws EE_Error
840
+	 */
841
+	public static function get_event_name($event)
842
+	{
843
+		return $event instanceof EE_Event
844
+			? mb_substr($event->name(), 0, 245)
845
+			: esc_html__('Event', 'event_espresso');
846
+	}
847
+
848
+
849
+	/**
850
+	 * Gets the event excerpt
851
+	 *
852
+	 * @param EE_Event $event
853
+	 * @return string
854
+	 * @throws EE_Error
855
+	 */
856
+	public static function get_event_desc($event)
857
+	{
858
+		return $event instanceof EE_Event ? $event->short_description() : '';
859
+	}
860
+
861
+
862
+	/**
863
+	 * Given the grand total line item and a ticket, finds the event sub-total
864
+	 * line item the ticket's purchase should be added onto
865
+	 *
866
+	 * @access public
867
+	 * @param EE_Line_Item $grand_total the grand total line item
868
+	 * @param EE_Ticket    $ticket
869
+	 * @return EE_Line_Item
870
+	 * @throws EE_Error
871
+	 * @throws InvalidArgumentException
872
+	 * @throws InvalidDataTypeException
873
+	 * @throws InvalidInterfaceException
874
+	 * @throws ReflectionException
875
+	 */
876
+	public static function get_event_line_item_for_ticket(EE_Line_Item $grand_total, EE_Ticket $ticket)
877
+	{
878
+		$first_datetime = $ticket->first_datetime();
879
+		if (! $first_datetime instanceof EE_Datetime) {
880
+			throw new EE_Error(
881
+				sprintf(
882
+					esc_html__('The supplied ticket (ID %d) has no datetimes', 'event_espresso'),
883
+					$ticket->ID()
884
+				)
885
+			);
886
+		}
887
+		$event = $first_datetime->event();
888
+		if (! $event instanceof EE_Event) {
889
+			throw new EE_Error(
890
+				sprintf(
891
+					esc_html__(
892
+						'The supplied ticket (ID %d) has no event data associated with it.',
893
+						'event_espresso'
894
+					),
895
+					$ticket->ID()
896
+				)
897
+			);
898
+		}
899
+		$events_sub_total = EEH_Line_Item::get_event_line_item($grand_total, $event);
900
+		if (! $events_sub_total instanceof EE_Line_Item) {
901
+			throw new EE_Error(
902
+				sprintf(
903
+					esc_html__(
904
+						'There is no events sub-total for ticket %s on total line item %d',
905
+						'event_espresso'
906
+					),
907
+					$ticket->ID(),
908
+					$grand_total->ID()
909
+				)
910
+			);
911
+		}
912
+		return $events_sub_total;
913
+	}
914
+
915
+
916
+	/**
917
+	 * Gets the event line item
918
+	 *
919
+	 * @param EE_Line_Item $grand_total
920
+	 * @param EE_Event     $event
921
+	 * @return EE_Line_Item for the event subtotal which is a child of $grand_total
922
+	 * @throws EE_Error
923
+	 * @throws InvalidArgumentException
924
+	 * @throws InvalidDataTypeException
925
+	 * @throws InvalidInterfaceException
926
+	 * @throws ReflectionException
927
+	 */
928
+	public static function get_event_line_item(EE_Line_Item $grand_total, $event)
929
+	{
930
+		/** @type EE_Event $event */
931
+		$event = EEM_Event::instance()->ensure_is_obj($event, true);
932
+		$event_line_item = null;
933
+		$found = false;
934
+		foreach (EEH_Line_Item::get_event_subtotals($grand_total) as $event_line_item) {
935
+			// default event subtotal, we should only ever find this the first time this method is called
936
+			if (! $event_line_item->OBJ_ID()) {
937
+				// let's use this! but first... set the event details
938
+				EEH_Line_Item::set_event_subtotal_details($event_line_item, $event);
939
+				$found = true;
940
+				break;
941
+			}
942
+			if ($event_line_item->OBJ_ID() === $event->ID()) {
943
+				// found existing line item for this event in the cart, so break out of loop and use this one
944
+				$found = true;
945
+				break;
946
+			}
947
+		}
948
+		if (! $found) {
949
+			// there is no event sub-total yet, so add it
950
+			$pre_tax_subtotal = EEH_Line_Item::get_pre_tax_subtotal($grand_total);
951
+			// create a new "event" subtotal below that
952
+			$event_line_item = EEH_Line_Item::create_event_subtotal($pre_tax_subtotal, null, $event);
953
+			// and set the event details
954
+			EEH_Line_Item::set_event_subtotal_details($event_line_item, $event);
955
+		}
956
+		return $event_line_item;
957
+	}
958
+
959
+
960
+	/**
961
+	 * Creates a default items subtotal line item
962
+	 *
963
+	 * @param EE_Line_Item   $event_line_item
964
+	 * @param EE_Event       $event
965
+	 * @param EE_Transaction $transaction
966
+	 * @return void
967
+	 * @throws EE_Error
968
+	 * @throws InvalidArgumentException
969
+	 * @throws InvalidDataTypeException
970
+	 * @throws InvalidInterfaceException
971
+	 * @throws ReflectionException
972
+	 */
973
+	public static function set_event_subtotal_details(
974
+		EE_Line_Item $event_line_item,
975
+		EE_Event $event,
976
+		$transaction = null
977
+	) {
978
+		if ($event instanceof EE_Event) {
979
+			$event_line_item->set_code(self::get_event_code($event));
980
+			$event_line_item->set_name(self::get_event_name($event));
981
+			$event_line_item->set_desc(self::get_event_desc($event));
982
+			$event_line_item->set_OBJ_ID($event->ID());
983
+		}
984
+		self::set_TXN_ID($event_line_item, $transaction);
985
+	}
986
+
987
+
988
+	/**
989
+	 * Finds what taxes should apply, adds them as tax line items under the taxes sub-total,
990
+	 * and recalculates the taxes sub-total and the grand total. Resets the taxes, so
991
+	 * any old taxes are removed
992
+	 *
993
+	 * @param EE_Line_Item $total_line_item of type EEM_Line_Item::type_total
994
+	 * @param bool         $update_txn_status
995
+	 * @return bool
996
+	 * @throws EE_Error
997
+	 * @throws InvalidArgumentException
998
+	 * @throws InvalidDataTypeException
999
+	 * @throws InvalidInterfaceException
1000
+	 * @throws ReflectionException
1001
+	 * @throws RuntimeException
1002
+	 */
1003
+	public static function apply_taxes(EE_Line_Item $total_line_item, $update_txn_status = false)
1004
+	{
1005
+		$total_line_item = EEH_Line_Item::find_transaction_grand_total_for_line_item($total_line_item);
1006
+		$taxes_line_item = self::get_taxes_subtotal($total_line_item);
1007
+		$existing_global_taxes = $taxes_line_item->tax_descendants();
1008
+		$updates = false;
1009
+		// loop thru taxes
1010
+		$global_taxes = EEH_Line_Item::getGlobalTaxes();
1011
+		foreach ($global_taxes as $order => $taxes) {
1012
+			foreach ($taxes as $tax) {
1013
+				if ($tax instanceof EE_Price) {
1014
+					$found = false;
1015
+					// check if this is already an existing tax
1016
+					foreach ($existing_global_taxes as $existing_global_tax) {
1017
+						if ($tax->ID() === $existing_global_tax->OBJ_ID()) {
1018
+							// maybe update the tax rate in case it has changed
1019
+							if ($existing_global_tax->percent() !== $tax->amount()) {
1020
+								$existing_global_tax->set_percent($tax->amount());
1021
+								$existing_global_tax->save();
1022
+								$updates = true;
1023
+							}
1024
+							$found = true;
1025
+							break;
1026
+						}
1027
+					}
1028
+					if (! $found) {
1029
+						// add a new line item for this global tax
1030
+						$tax_line_item = apply_filters(
1031
+							'FHEE__EEH_Line_Item__apply_taxes__tax_line_item',
1032
+							EE_Line_Item::new_instance(
1033
+								[
1034
+									'LIN_name'       => $tax->name(),
1035
+									'LIN_desc'       => $tax->desc(),
1036
+									'LIN_percent'    => $tax->amount(),
1037
+									'LIN_is_taxable' => false,
1038
+									'LIN_order'      => $order,
1039
+									'LIN_total'      => 0,
1040
+									'LIN_type'       => EEM_Line_Item::type_tax,
1041
+									'OBJ_type'       => EEM_Line_Item::OBJ_TYPE_PRICE,
1042
+									'OBJ_ID'         => $tax->ID(),
1043
+								]
1044
+							)
1045
+						);
1046
+						$updates = $taxes_line_item->add_child_line_item($tax_line_item) ? true : $updates;
1047
+					}
1048
+				}
1049
+			}
1050
+		}
1051
+		// only recalculate totals if something changed
1052
+		if ($updates) {
1053
+			$total_line_item->recalculate_total_including_taxes($update_txn_status);
1054
+			return true;
1055
+		}
1056
+		return false;
1057
+	}
1058
+
1059
+
1060
+	/**
1061
+	 * Ensures that taxes have been applied to the order, if not applies them.
1062
+	 * Returns the total amount of tax
1063
+	 *
1064
+	 * @param EE_Line_Item $total_line_item of type EEM_Line_Item::type_total
1065
+	 * @return float
1066
+	 * @throws EE_Error
1067
+	 * @throws InvalidArgumentException
1068
+	 * @throws InvalidDataTypeException
1069
+	 * @throws InvalidInterfaceException
1070
+	 * @throws ReflectionException
1071
+	 */
1072
+	public static function ensure_taxes_applied($total_line_item)
1073
+	{
1074
+		$taxes_subtotal = self::get_taxes_subtotal($total_line_item);
1075
+		if (! $taxes_subtotal->children()) {
1076
+			self::apply_taxes($total_line_item);
1077
+		}
1078
+		return $taxes_subtotal->total();
1079
+	}
1080
+
1081
+
1082
+	/**
1083
+	 * Deletes ALL children of the passed line item
1084
+	 *
1085
+	 * @param EE_Line_Item $parent_line_item
1086
+	 * @return bool
1087
+	 * @throws EE_Error
1088
+	 * @throws InvalidArgumentException
1089
+	 * @throws InvalidDataTypeException
1090
+	 * @throws InvalidInterfaceException
1091
+	 * @throws ReflectionException
1092
+	 */
1093
+	public static function delete_all_child_items(EE_Line_Item $parent_line_item)
1094
+	{
1095
+		$deleted = 0;
1096
+		foreach ($parent_line_item->children() as $child_line_item) {
1097
+			if ($child_line_item instanceof EE_Line_Item) {
1098
+				$deleted += EEH_Line_Item::delete_all_child_items($child_line_item);
1099
+				if ($child_line_item->ID()) {
1100
+					$child_line_item->delete();
1101
+					unset($child_line_item);
1102
+				} else {
1103
+					$parent_line_item->delete_child_line_item($child_line_item->code());
1104
+				}
1105
+				$deleted++;
1106
+			}
1107
+		}
1108
+		return $deleted;
1109
+	}
1110
+
1111
+
1112
+	/**
1113
+	 * Deletes the line items as indicated by the line item code(s) provided,
1114
+	 * regardless of where they're found in the line item tree. Automatically
1115
+	 * re-calculates the line item totals and updates the related transaction. But
1116
+	 * DOES NOT automatically upgrade the transaction's registrations' final prices (which
1117
+	 * should probably change because of this).
1118
+	 * You should call EE_Registration_Processor::calculate_reg_final_prices_per_line_item()
1119
+	 * after using this, to keep the registration final prices in-sync with the transaction's total.
1120
+	 *
1121
+	 * @param EE_Line_Item      $total_line_item of type EEM_Line_Item::type_total
1122
+	 * @param array|bool|string $line_item_codes
1123
+	 * @return int number of items successfully removed
1124
+	 * @throws EE_Error
1125
+	 */
1126
+	public static function delete_items(EE_Line_Item $total_line_item, $line_item_codes = false)
1127
+	{
1128
+
1129
+		if ($total_line_item->type() !== EEM_Line_Item::type_total) {
1130
+			EE_Error::doing_it_wrong(
1131
+				'EEH_Line_Item::delete_items',
1132
+				esc_html__(
1133
+					'This static method should only be called with a TOTAL line item, otherwise we won\'t recalculate the totals correctly',
1134
+					'event_espresso'
1135
+				),
1136
+				'4.6.18'
1137
+			);
1138
+		}
1139
+		do_action('AHEE_log', __FILE__, __FUNCTION__, '');
1140
+
1141
+		// check if only a single line_item_id was passed
1142
+		if (! empty($line_item_codes) && ! is_array($line_item_codes)) {
1143
+			// place single line_item_id in an array to appear as multiple line_item_ids
1144
+			$line_item_codes = array($line_item_codes);
1145
+		}
1146
+		$removals = 0;
1147
+		// cycle thru line_item_ids
1148
+		foreach ($line_item_codes as $line_item_id) {
1149
+			$removals += $total_line_item->delete_child_line_item($line_item_id);
1150
+		}
1151
+
1152
+		if ($removals > 0) {
1153
+			$total_line_item->recalculate_taxes_and_tax_total();
1154
+			return $removals;
1155
+		} else {
1156
+			return false;
1157
+		}
1158
+	}
1159
+
1160
+
1161
+	/**
1162
+	 * Overwrites the previous tax by clearing out the old taxes, and creates a new
1163
+	 * tax and updates the total line item accordingly
1164
+	 *
1165
+	 * @param EE_Line_Item $total_line_item
1166
+	 * @param float        $amount
1167
+	 * @param string       $name
1168
+	 * @param string       $description
1169
+	 * @param string       $code
1170
+	 * @param boolean      $add_to_existing_line_item
1171
+	 *                          if true, and a duplicate line item with the same code is found,
1172
+	 *                          $amount will be added onto it; otherwise will simply set the taxes to match $amount
1173
+	 * @return EE_Line_Item the new tax line item created
1174
+	 * @throws EE_Error
1175
+	 * @throws InvalidArgumentException
1176
+	 * @throws InvalidDataTypeException
1177
+	 * @throws InvalidInterfaceException
1178
+	 * @throws ReflectionException
1179
+	 */
1180
+	public static function set_total_tax_to(
1181
+		EE_Line_Item $total_line_item,
1182
+		$amount,
1183
+		$name = null,
1184
+		$description = null,
1185
+		$code = null,
1186
+		$add_to_existing_line_item = false
1187
+	) {
1188
+		$tax_subtotal = self::get_taxes_subtotal($total_line_item);
1189
+		$taxable_total = $total_line_item->taxable_total();
1190
+
1191
+		if ($add_to_existing_line_item) {
1192
+			$new_tax = $tax_subtotal->get_child_line_item($code);
1193
+			EEM_Line_Item::instance()->delete(
1194
+				array(array('LIN_code' => array('!=', $code), 'LIN_parent' => $tax_subtotal->ID()))
1195
+			);
1196
+		} else {
1197
+			$new_tax = null;
1198
+			$tax_subtotal->delete_children_line_items();
1199
+		}
1200
+		if ($new_tax) {
1201
+			$new_tax->set_total($new_tax->total() + $amount);
1202
+			$new_tax->set_percent($taxable_total ? $new_tax->total() / $taxable_total * 100 : 0);
1203
+		} else {
1204
+			// no existing tax item. Create it
1205
+			$new_tax = EE_Line_Item::new_instance(array(
1206
+				'TXN_ID'      => $total_line_item->TXN_ID(),
1207
+				'LIN_name'    => $name ?: esc_html__('Tax', 'event_espresso'),
1208
+				'LIN_desc'    => $description ?: '',
1209
+				'LIN_percent' => $taxable_total ? ($amount / $taxable_total * 100) : 0,
1210
+				'LIN_total'   => $amount,
1211
+				'LIN_parent'  => $tax_subtotal->ID(),
1212
+				'LIN_type'    => EEM_Line_Item::type_tax,
1213
+				'LIN_code'    => $code,
1214
+			));
1215
+		}
1216
+
1217
+		$new_tax = apply_filters(
1218
+			'FHEE__EEH_Line_Item__set_total_tax_to__new_tax_subtotal',
1219
+			$new_tax,
1220
+			$total_line_item
1221
+		);
1222
+		$new_tax->save();
1223
+		$tax_subtotal->set_total($new_tax->total());
1224
+		$tax_subtotal->save();
1225
+		$total_line_item->recalculate_total_including_taxes();
1226
+		return $new_tax;
1227
+	}
1228
+
1229
+
1230
+	/**
1231
+	 * Makes all the line items which are children of $line_item taxable (or not).
1232
+	 * Does NOT save the line items
1233
+	 *
1234
+	 * @param EE_Line_Item $line_item
1235
+	 * @param boolean      $taxable
1236
+	 * @param string       $code_substring_for_whitelist if this string is part of the line item's code
1237
+	 *                                                   it will be whitelisted (ie, except from becoming taxable)
1238
+	 * @throws EE_Error
1239
+	 */
1240
+	public static function set_line_items_taxable(
1241
+		EE_Line_Item $line_item,
1242
+		$taxable = true,
1243
+		$code_substring_for_whitelist = null
1244
+	) {
1245
+		$whitelisted = false;
1246
+		if ($code_substring_for_whitelist !== null) {
1247
+			$whitelisted = strpos($line_item->code(), $code_substring_for_whitelist) !== false;
1248
+		}
1249
+		if (! $whitelisted && $line_item->is_line_item()) {
1250
+			$line_item->set_is_taxable($taxable);
1251
+		}
1252
+		foreach ($line_item->children() as $child_line_item) {
1253
+			EEH_Line_Item::set_line_items_taxable(
1254
+				$child_line_item,
1255
+				$taxable,
1256
+				$code_substring_for_whitelist
1257
+			);
1258
+		}
1259
+	}
1260
+
1261
+
1262
+	/**
1263
+	 * Gets all descendants that are event subtotals
1264
+	 *
1265
+	 * @uses  EEH_Line_Item::get_subtotals_of_object_type()
1266
+	 * @param EE_Line_Item $parent_line_item - the line item to find descendants of
1267
+	 * @return EE_Line_Item[]
1268
+	 * @throws EE_Error
1269
+	 */
1270
+	public static function get_event_subtotals(EE_Line_Item $parent_line_item)
1271
+	{
1272
+		return self::get_subtotals_of_object_type($parent_line_item, EEM_Line_Item::OBJ_TYPE_EVENT);
1273
+	}
1274
+
1275
+
1276
+	/**
1277
+	 * Gets all descendants subtotals that match the supplied object type
1278
+	 *
1279
+	 * @uses  EEH_Line_Item::_get_descendants_by_type_and_object_type()
1280
+	 * @param EE_Line_Item $parent_line_item - the line item to find descendants of
1281
+	 * @param string       $obj_type
1282
+	 * @return EE_Line_Item[]
1283
+	 * @throws EE_Error
1284
+	 */
1285
+	public static function get_subtotals_of_object_type(EE_Line_Item $parent_line_item, $obj_type = '')
1286
+	{
1287
+		return self::_get_descendants_by_type_and_object_type(
1288
+			$parent_line_item,
1289
+			EEM_Line_Item::type_sub_total,
1290
+			$obj_type
1291
+		);
1292
+	}
1293
+
1294
+
1295
+	/**
1296
+	 * Gets all descendants that are tickets
1297
+	 *
1298
+	 * @uses  EEH_Line_Item::get_line_items_of_object_type()
1299
+	 * @param EE_Line_Item $parent_line_item - the line item to find descendants of
1300
+	 * @return EE_Line_Item[]
1301
+	 * @throws EE_Error
1302
+	 */
1303
+	public static function get_ticket_line_items(EE_Line_Item $parent_line_item)
1304
+	{
1305
+		return self::get_line_items_of_object_type(
1306
+			$parent_line_item,
1307
+			EEM_Line_Item::OBJ_TYPE_TICKET
1308
+		);
1309
+	}
1310
+
1311
+
1312
+	/**
1313
+	 * Gets all descendants subtotals that match the supplied object type
1314
+	 *
1315
+	 * @uses  EEH_Line_Item::_get_descendants_by_type_and_object_type()
1316
+	 * @param EE_Line_Item $parent_line_item - the line item to find descendants of
1317
+	 * @param string       $obj_type
1318
+	 * @return EE_Line_Item[]
1319
+	 * @throws EE_Error
1320
+	 */
1321
+	public static function get_line_items_of_object_type(EE_Line_Item $parent_line_item, $obj_type = '')
1322
+	{
1323
+		return self::_get_descendants_by_type_and_object_type(
1324
+			$parent_line_item,
1325
+			EEM_Line_Item::type_line_item,
1326
+			$obj_type
1327
+		);
1328
+	}
1329
+
1330
+
1331
+	/**
1332
+	 * Gets all the descendants (ie, children or children of children etc) that are of the type 'tax'
1333
+	 *
1334
+	 * @uses  EEH_Line_Item::get_descendants_of_type()
1335
+	 * @param EE_Line_Item $parent_line_item - the line item to find descendants of
1336
+	 * @return EE_Line_Item[]
1337
+	 * @throws EE_Error
1338
+	 */
1339
+	public static function get_tax_descendants(EE_Line_Item $parent_line_item)
1340
+	{
1341
+		return EEH_Line_Item::get_descendants_of_type(
1342
+			$parent_line_item,
1343
+			EEM_Line_Item::type_tax
1344
+		);
1345
+	}
1346
+
1347
+
1348
+	/**
1349
+	 * Gets all the real items purchased which are children of this item
1350
+	 *
1351
+	 * @uses  EEH_Line_Item::get_descendants_of_type()
1352
+	 * @param EE_Line_Item $parent_line_item - the line item to find descendants of
1353
+	 * @return EE_Line_Item[]
1354
+	 * @throws EE_Error
1355
+	 */
1356
+	public static function get_line_item_descendants(EE_Line_Item $parent_line_item)
1357
+	{
1358
+		return EEH_Line_Item::get_descendants_of_type(
1359
+			$parent_line_item,
1360
+			EEM_Line_Item::type_line_item
1361
+		);
1362
+	}
1363
+
1364
+
1365
+	/**
1366
+	 * Gets all descendants of supplied line item that match the supplied line item type
1367
+	 *
1368
+	 * @uses  EEH_Line_Item::_get_descendants_by_type_and_object_type()
1369
+	 * @param EE_Line_Item $parent_line_item - the line item to find descendants of
1370
+	 * @param string       $line_item_type   one of the EEM_Line_Item constants
1371
+	 * @return EE_Line_Item[]
1372
+	 * @throws EE_Error
1373
+	 */
1374
+	public static function get_descendants_of_type(EE_Line_Item $parent_line_item, $line_item_type)
1375
+	{
1376
+		return self::_get_descendants_by_type_and_object_type(
1377
+			$parent_line_item,
1378
+			$line_item_type,
1379
+			null
1380
+		);
1381
+	}
1382
+
1383
+
1384
+	/**
1385
+	 * Gets all descendants of supplied line item that match the supplied line item type and possibly the object type
1386
+	 * as well
1387
+	 *
1388
+	 * @param EE_Line_Item  $parent_line_item - the line item to find descendants of
1389
+	 * @param string        $line_item_type   one of the EEM_Line_Item constants
1390
+	 * @param string | NULL $obj_type         object model class name (minus prefix) or NULL to ignore object type when
1391
+	 *                                        searching
1392
+	 * @return EE_Line_Item[]
1393
+	 * @throws EE_Error
1394
+	 */
1395
+	protected static function _get_descendants_by_type_and_object_type(
1396
+		EE_Line_Item $parent_line_item,
1397
+		$line_item_type,
1398
+		$obj_type = null
1399
+	) {
1400
+		$objects = array();
1401
+		foreach ($parent_line_item->children() as $child_line_item) {
1402
+			if ($child_line_item instanceof EE_Line_Item) {
1403
+				if (
1404
+					$child_line_item->type() === $line_item_type
1405
+					&& (
1406
+						$child_line_item->OBJ_type() === $obj_type || $obj_type === null
1407
+					)
1408
+				) {
1409
+					$objects[] = $child_line_item;
1410
+				} else {
1411
+					// go-through-all-its children looking for more matches
1412
+					$objects = array_merge(
1413
+						$objects,
1414
+						self::_get_descendants_by_type_and_object_type(
1415
+							$child_line_item,
1416
+							$line_item_type,
1417
+							$obj_type
1418
+						)
1419
+					);
1420
+				}
1421
+			}
1422
+		}
1423
+		return $objects;
1424
+	}
1425
+
1426
+
1427
+	/**
1428
+	 * Gets all descendants subtotals that match the supplied object type
1429
+	 *
1430
+	 * @uses  EEH_Line_Item::_get_descendants_by_type_and_object_type()
1431
+	 * @param EE_Line_Item $parent_line_item - the line item to find descendants of
1432
+	 * @param string       $OBJ_type         object type (like Event)
1433
+	 * @param array        $OBJ_IDs          array of OBJ_IDs
1434
+	 * @return EE_Line_Item[]
1435
+	 * @throws EE_Error
1436
+	 */
1437
+	public static function get_line_items_by_object_type_and_IDs(
1438
+		EE_Line_Item $parent_line_item,
1439
+		$OBJ_type = '',
1440
+		$OBJ_IDs = array()
1441
+	) {
1442
+		return self::_get_descendants_by_object_type_and_object_ID(
1443
+			$parent_line_item,
1444
+			$OBJ_type,
1445
+			$OBJ_IDs
1446
+		);
1447
+	}
1448
+
1449
+
1450
+	/**
1451
+	 * Gets all descendants of supplied line item that match the supplied line item type and possibly the object type
1452
+	 * as well
1453
+	 *
1454
+	 * @param EE_Line_Item $parent_line_item - the line item to find descendants of
1455
+	 * @param string       $OBJ_type         object type (like Event)
1456
+	 * @param array        $OBJ_IDs          array of OBJ_IDs
1457
+	 * @return EE_Line_Item[]
1458
+	 * @throws EE_Error
1459
+	 */
1460
+	protected static function _get_descendants_by_object_type_and_object_ID(
1461
+		EE_Line_Item $parent_line_item,
1462
+		$OBJ_type,
1463
+		$OBJ_IDs
1464
+	) {
1465
+		$objects = array();
1466
+		foreach ($parent_line_item->children() as $child_line_item) {
1467
+			if ($child_line_item instanceof EE_Line_Item) {
1468
+				if (
1469
+					$child_line_item->OBJ_type() === $OBJ_type
1470
+					&& is_array($OBJ_IDs)
1471
+					&& in_array($child_line_item->OBJ_ID(), $OBJ_IDs)
1472
+				) {
1473
+					$objects[] = $child_line_item;
1474
+				} else {
1475
+					// go-through-all-its children looking for more matches
1476
+					$objects = array_merge(
1477
+						$objects,
1478
+						self::_get_descendants_by_object_type_and_object_ID(
1479
+							$child_line_item,
1480
+							$OBJ_type,
1481
+							$OBJ_IDs
1482
+						)
1483
+					);
1484
+				}
1485
+			}
1486
+		}
1487
+		return $objects;
1488
+	}
1489
+
1490
+
1491
+	/**
1492
+	 * Uses a breadth-first-search in order to find the nearest descendant of
1493
+	 * the specified type and returns it, else NULL
1494
+	 *
1495
+	 * @uses  EEH_Line_Item::_get_nearest_descendant()
1496
+	 * @param EE_Line_Item $parent_line_item - the line item to find descendants of
1497
+	 * @param string       $type             like one of the EEM_Line_Item::type_*
1498
+	 * @return EE_Line_Item
1499
+	 * @throws EE_Error
1500
+	 * @throws InvalidArgumentException
1501
+	 * @throws InvalidDataTypeException
1502
+	 * @throws InvalidInterfaceException
1503
+	 * @throws ReflectionException
1504
+	 */
1505
+	public static function get_nearest_descendant_of_type(EE_Line_Item $parent_line_item, $type)
1506
+	{
1507
+		return self::_get_nearest_descendant($parent_line_item, 'LIN_type', $type);
1508
+	}
1509
+
1510
+
1511
+	/**
1512
+	 * Uses a breadth-first-search in order to find the nearest descendant
1513
+	 * having the specified LIN_code and returns it, else NULL
1514
+	 *
1515
+	 * @uses  EEH_Line_Item::_get_nearest_descendant()
1516
+	 * @param EE_Line_Item $parent_line_item - the line item to find descendants of
1517
+	 * @param string       $code             any value used for LIN_code
1518
+	 * @return EE_Line_Item
1519
+	 * @throws EE_Error
1520
+	 * @throws InvalidArgumentException
1521
+	 * @throws InvalidDataTypeException
1522
+	 * @throws InvalidInterfaceException
1523
+	 * @throws ReflectionException
1524
+	 */
1525
+	public static function get_nearest_descendant_having_code(EE_Line_Item $parent_line_item, $code)
1526
+	{
1527
+		return self::_get_nearest_descendant($parent_line_item, 'LIN_code', $code);
1528
+	}
1529
+
1530
+
1531
+	/**
1532
+	 * Uses a breadth-first-search in order to find the nearest descendant
1533
+	 * having the specified LIN_code and returns it, else NULL
1534
+	 *
1535
+	 * @param EE_Line_Item $parent_line_item - the line item to find descendants of
1536
+	 * @param string       $search_field     name of EE_Line_Item property
1537
+	 * @param string       $value            any value stored in $search_field
1538
+	 * @return EE_Line_Item
1539
+	 * @throws EE_Error
1540
+	 * @throws InvalidArgumentException
1541
+	 * @throws InvalidDataTypeException
1542
+	 * @throws InvalidInterfaceException
1543
+	 * @throws ReflectionException
1544
+	 */
1545
+	protected static function _get_nearest_descendant(EE_Line_Item $parent_line_item, $search_field, $value)
1546
+	{
1547
+		foreach ($parent_line_item->children() as $child) {
1548
+			if ($child->get($search_field) == $value) {
1549
+				return $child;
1550
+			}
1551
+		}
1552
+		foreach ($parent_line_item->children() as $child) {
1553
+			$descendant_found = self::_get_nearest_descendant(
1554
+				$child,
1555
+				$search_field,
1556
+				$value
1557
+			);
1558
+			if ($descendant_found) {
1559
+				return $descendant_found;
1560
+			}
1561
+		}
1562
+		return null;
1563
+	}
1564
+
1565
+
1566
+	/**
1567
+	 * if passed line item has a TXN ID, uses that to jump directly to the grand total line item for the transaction,
1568
+	 * else recursively walks up the line item tree until a parent of type total is found,
1569
+	 *
1570
+	 * @param EE_Line_Item $line_item
1571
+	 * @return EE_Line_Item
1572
+	 * @throws EE_Error
1573
+	 * @throws ReflectionException
1574
+	 */
1575
+	public static function find_transaction_grand_total_for_line_item(EE_Line_Item $line_item): EE_Line_Item
1576
+	{
1577
+		if ($line_item->is_total()) {
1578
+			return $line_item;
1579
+		}
1580
+		if ($line_item->TXN_ID()) {
1581
+			$total_line_item = $line_item->transaction()->total_line_item(false);
1582
+			if ($total_line_item instanceof EE_Line_Item) {
1583
+				return $total_line_item;
1584
+			}
1585
+		} else {
1586
+			$line_item_parent = $line_item->parent();
1587
+			if ($line_item_parent instanceof EE_Line_Item) {
1588
+				if ($line_item_parent->is_total()) {
1589
+					return $line_item_parent;
1590
+				}
1591
+				return EEH_Line_Item::find_transaction_grand_total_for_line_item($line_item_parent);
1592
+			}
1593
+		}
1594
+		throw new EE_Error(
1595
+			sprintf(
1596
+				esc_html__(
1597
+					'A valid grand total for line item %1$d was not found.',
1598
+					'event_espresso'
1599
+				),
1600
+				$line_item->ID()
1601
+			)
1602
+		);
1603
+	}
1604
+
1605
+
1606
+	/**
1607
+	 * Prints out a representation of the line item tree
1608
+	 *
1609
+	 * @param EE_Line_Item $line_item
1610
+	 * @param int          $indentation
1611
+	 * @return void
1612
+	 * @throws EE_Error
1613
+	 */
1614
+	public static function visualize(EE_Line_Item $line_item, $indentation = 0)
1615
+	{
1616
+		$new_line = defined('EE_TESTS_DIR') ? "\n" : '<br />';
1617
+		echo $new_line;
1618
+		if (! $indentation) {
1619
+			echo $new_line;
1620
+		}
1621
+		echo str_repeat('. ', $indentation);
1622
+		$breakdown = '';
1623
+		if ($line_item->is_line_item() || $line_item->is_sub_line_item() || $line_item->isSubTax()) {
1624
+			if ($line_item->is_percent()) {
1625
+				$breakdown = "{$line_item->percent()}%";
1626
+			} else {
1627
+				$breakdown = "\${$line_item->unit_price()} x {$line_item->quantity()}";
1628
+			}
1629
+		}
1630
+		echo wp_kses($line_item->name(), AllowedTags::getAllowedTags());
1631
+		echo " [ ID:{$line_item->ID()} | qty:{$line_item->quantity()} ] {$line_item->type()} : ";
1632
+		echo "\${$line_item->total()}";
1633
+		if ($breakdown) {
1634
+			echo " ( {$breakdown} )";
1635
+		}
1636
+		if ($line_item->is_taxable()) {
1637
+			echo '  * taxable';
1638
+		}
1639
+		if ($line_item->children()) {
1640
+			foreach ($line_item->children() as $child) {
1641
+				self::visualize($child, $indentation + 1);
1642
+			}
1643
+		}
1644
+		if (! $indentation) {
1645
+			echo $new_line . $new_line;
1646
+		}
1647
+	}
1648
+
1649
+
1650
+	/**
1651
+	 * Calculates the registration's final price, taking into account that they
1652
+	 * need to not only help pay for their OWN ticket, but also any transaction-wide surcharges and taxes,
1653
+	 * and receive a portion of any transaction-wide discounts.
1654
+	 * eg1, if I buy a $1 ticket and brent buys a $9 ticket, and we receive a $5 discount
1655
+	 * then I'll get 1/10 of that $5 discount, which is $0.50, and brent will get
1656
+	 * 9/10ths of that $5 discount, which is $4.50. So my final price should be $0.50
1657
+	 * and brent's final price should be $5.50.
1658
+	 * In order to do this, we basically need to traverse the line item tree calculating
1659
+	 * the running totals (just as if we were recalculating the total), but when we identify
1660
+	 * regular line items, we need to keep track of their share of the grand total.
1661
+	 * Also, we need to keep track of the TAXABLE total for each ticket purchase, so
1662
+	 * we can know how to apply taxes to it. (Note: "taxable total" does not equal the "pretax total"
1663
+	 * when there are non-taxable items; otherwise they would be the same)
1664
+	 *
1665
+	 * @param EE_Line_Item $line_item
1666
+	 * @param array        $billable_ticket_quantities  array of EE_Ticket IDs and their corresponding quantity that
1667
+	 *                                                  can be included in price calculations at this moment
1668
+	 * @return array        keys are line items for tickets IDs and values are their share of the running total,
1669
+	 *                                                  plus the key 'total', and 'taxable' which also has keys of all
1670
+	 *                                                  the ticket IDs.
1671
+	 *                                                  Eg array(
1672
+	 *                                                      12 => 4.3
1673
+	 *                                                      23 => 8.0
1674
+	 *                                                      'total' => 16.6,
1675
+	 *                                                      'taxable' => array(
1676
+	 *                                                          12 => 10,
1677
+	 *                                                          23 => 4
1678
+	 *                                                      ).
1679
+	 *                                                  So to find which registrations have which final price, we need
1680
+	 *                                                  to find which line item is theirs, which can be done with
1681
+	 *                                                  `EEM_Line_Item::instance()->get_line_item_for_registration(
1682
+	 *                                                  $registration );`
1683
+	 * @throws EE_Error
1684
+	 * @throws InvalidArgumentException
1685
+	 * @throws InvalidDataTypeException
1686
+	 * @throws InvalidInterfaceException
1687
+	 * @throws ReflectionException
1688
+	 */
1689
+	public static function calculate_reg_final_prices_per_line_item(
1690
+		EE_Line_Item $line_item,
1691
+		$billable_ticket_quantities = array()
1692
+	) {
1693
+		$running_totals = [
1694
+			'total'   => 0,
1695
+			'taxable' => ['total' => 0]
1696
+		];
1697
+		foreach ($line_item->children() as $child_line_item) {
1698
+			switch ($child_line_item->type()) {
1699
+				case EEM_Line_Item::type_sub_total:
1700
+					$running_totals_from_subtotal = EEH_Line_Item::calculate_reg_final_prices_per_line_item(
1701
+						$child_line_item,
1702
+						$billable_ticket_quantities
1703
+					);
1704
+					// combine arrays but preserve numeric keys
1705
+					$running_totals = array_replace_recursive($running_totals_from_subtotal, $running_totals);
1706
+					$running_totals['total'] += $running_totals_from_subtotal['total'];
1707
+					$running_totals['taxable']['total'] += $running_totals_from_subtotal['taxable']['total'];
1708
+					break;
1709
+
1710
+				case EEM_Line_Item::type_tax_sub_total:
1711
+					// find how much the taxes percentage is
1712
+					if ($child_line_item->percent() !== 0) {
1713
+						$tax_percent_decimal = $child_line_item->percent() / 100;
1714
+					} else {
1715
+						$tax_percent_decimal = EE_Taxes::get_total_taxes_percentage() / 100;
1716
+					}
1717
+					// and apply to all the taxable totals, and add to the pretax totals
1718
+					foreach ($running_totals as $line_item_id => $this_running_total) {
1719
+						// "total" and "taxable" array key is an exception
1720
+						if ($line_item_id === 'taxable') {
1721
+							continue;
1722
+						}
1723
+						$taxable_total = $running_totals['taxable'][ $line_item_id ];
1724
+						$running_totals[ $line_item_id ] += ($taxable_total * $tax_percent_decimal);
1725
+					}
1726
+					break;
1727
+
1728
+				case EEM_Line_Item::type_line_item:
1729
+					// ticket line items or ????
1730
+					if ($child_line_item->OBJ_type() === EEM_Line_Item::OBJ_TYPE_TICKET) {
1731
+						// kk it's a ticket
1732
+						if (isset($running_totals[ $child_line_item->ID() ])) {
1733
+							// huh? that shouldn't happen.
1734
+							$running_totals['total'] += $child_line_item->total();
1735
+						} else {
1736
+							// its not in our running totals yet. great.
1737
+							if ($child_line_item->is_taxable()) {
1738
+								$taxable_amount = $child_line_item->unit_price();
1739
+							} else {
1740
+								$taxable_amount = 0;
1741
+							}
1742
+							// are we only calculating totals for some tickets?
1743
+							if (isset($billable_ticket_quantities[ $child_line_item->OBJ_ID() ])) {
1744
+								$quantity = $billable_ticket_quantities[ $child_line_item->OBJ_ID() ];
1745
+								$running_totals[ $child_line_item->ID() ] = $quantity
1746
+									? $child_line_item->unit_price()
1747
+									: 0;
1748
+								$running_totals['taxable'][ $child_line_item->ID() ] = $quantity
1749
+									? $taxable_amount
1750
+									: 0;
1751
+							} else {
1752
+								$quantity = $child_line_item->quantity();
1753
+								$running_totals[ $child_line_item->ID() ] = $child_line_item->unit_price();
1754
+								$running_totals['taxable'][ $child_line_item->ID() ] = $taxable_amount;
1755
+							}
1756
+							$running_totals['taxable']['total'] += $taxable_amount * $quantity;
1757
+							$running_totals['total'] += $child_line_item->unit_price() * $quantity;
1758
+						}
1759
+					} else {
1760
+						// it's some other type of item added to the cart
1761
+						// it should affect the running totals
1762
+						// basically we want to convert it into a PERCENT modifier. Because
1763
+						// more clearly affect all registration's final price equally
1764
+						$line_items_percent_of_running_total = $running_totals['total'] > 0
1765
+							? ($child_line_item->total() / $running_totals['total']) + 1
1766
+							: 1;
1767
+						foreach ($running_totals as $line_item_id => $this_running_total) {
1768
+							// the "taxable" array key is an exception
1769
+							if ($line_item_id === 'taxable') {
1770
+								continue;
1771
+							}
1772
+							// update the running totals
1773
+							// yes this actually even works for the running grand total!
1774
+							$running_totals[ $line_item_id ] =
1775
+								$line_items_percent_of_running_total * $this_running_total;
1776
+
1777
+							if ($child_line_item->is_taxable()) {
1778
+								$running_totals['taxable'][ $line_item_id ] =
1779
+									$line_items_percent_of_running_total * $running_totals['taxable'][ $line_item_id ];
1780
+							}
1781
+						}
1782
+					}
1783
+					break;
1784
+			}
1785
+		}
1786
+		return $running_totals;
1787
+	}
1788
+
1789
+
1790
+	/**
1791
+	 * @param EE_Line_Item $total_line_item
1792
+	 * @param EE_Line_Item $ticket_line_item
1793
+	 * @return float | null
1794
+	 * @throws EE_Error
1795
+	 * @throws InvalidArgumentException
1796
+	 * @throws InvalidDataTypeException
1797
+	 * @throws InvalidInterfaceException
1798
+	 * @throws OutOfRangeException
1799
+	 * @throws ReflectionException
1800
+	 */
1801
+	public static function calculate_final_price_for_ticket_line_item(
1802
+		EE_Line_Item $total_line_item,
1803
+		EE_Line_Item $ticket_line_item
1804
+	) {
1805
+		static $final_prices_per_ticket_line_item = array();
1806
+		if (empty($final_prices_per_ticket_line_item) || empty($final_prices_per_ticket_line_item[ $total_line_item->ID() ])) {
1807
+			$final_prices_per_ticket_line_item[ $total_line_item->ID() ] = EEH_Line_Item::calculate_reg_final_prices_per_line_item(
1808
+				$total_line_item
1809
+			);
1810
+		}
1811
+		// ok now find this new registration's final price
1812
+		if (isset($final_prices_per_ticket_line_item[ $total_line_item->ID() ][ $ticket_line_item->ID() ])) {
1813
+			return $final_prices_per_ticket_line_item[ $total_line_item->ID() ][ $ticket_line_item->ID() ];
1814
+		}
1815
+		$message = sprintf(
1816
+			esc_html__(
1817
+				'The final price for the ticket line item (ID:%1$d) on the total line item (ID:%2$d) could not be calculated.',
1818
+				'event_espresso'
1819
+			),
1820
+			$ticket_line_item->ID(),
1821
+			$total_line_item->ID()
1822
+		);
1823
+		if (WP_DEBUG) {
1824
+			$message .= '<br>' . print_r($final_prices_per_ticket_line_item, true);
1825
+			throw new OutOfRangeException($message);
1826
+		}
1827
+		EE_Log::instance()->log(__CLASS__, __FUNCTION__, $message);
1828
+		return null;
1829
+	}
1830
+
1831
+
1832
+	/**
1833
+	 * Creates a duplicate of the line item tree, except only includes billable items
1834
+	 * and the portion of line items attributed to billable things
1835
+	 *
1836
+	 * @param EE_Line_Item      $line_item
1837
+	 * @param EE_Registration[] $registrations
1838
+	 * @return EE_Line_Item
1839
+	 * @throws EE_Error
1840
+	 * @throws InvalidArgumentException
1841
+	 * @throws InvalidDataTypeException
1842
+	 * @throws InvalidInterfaceException
1843
+	 * @throws ReflectionException
1844
+	 */
1845
+	public static function billable_line_item_tree(EE_Line_Item $line_item, $registrations)
1846
+	{
1847
+		$copy_li = EEH_Line_Item::billable_line_item($line_item, $registrations);
1848
+		foreach ($line_item->children() as $child_li) {
1849
+			$copy_li->add_child_line_item(
1850
+				EEH_Line_Item::billable_line_item_tree($child_li, $registrations)
1851
+			);
1852
+		}
1853
+		// if this is the grand total line item, make sure the totals all add up
1854
+		// (we could have duplicated this logic AS we copied the line items, but
1855
+		// it seems DRYer this way)
1856
+		if ($copy_li->type() === EEM_Line_Item::type_total) {
1857
+			$copy_li->recalculate_total_including_taxes();
1858
+		}
1859
+		return $copy_li;
1860
+	}
1861
+
1862
+
1863
+	/**
1864
+	 * Creates a new, unsaved line item from $line_item that factors in the
1865
+	 * number of billable registrations on $registrations.
1866
+	 *
1867
+	 * @param EE_Line_Item      $line_item
1868
+	 * @param EE_Registration[] $registrations
1869
+	 * @return EE_Line_Item
1870
+	 * @throws EE_Error
1871
+	 * @throws InvalidArgumentException
1872
+	 * @throws InvalidDataTypeException
1873
+	 * @throws InvalidInterfaceException
1874
+	 * @throws ReflectionException
1875
+	 */
1876
+	public static function billable_line_item(EE_Line_Item $line_item, $registrations)
1877
+	{
1878
+		$new_li_fields = $line_item->model_field_array();
1879
+		if (
1880
+			$line_item->type() === EEM_Line_Item::type_line_item &&
1881
+			$line_item->OBJ_type() === EEM_Line_Item::OBJ_TYPE_TICKET
1882
+		) {
1883
+			$count = 0;
1884
+			foreach ($registrations as $registration) {
1885
+				if (
1886
+					$line_item->OBJ_ID() === $registration->ticket_ID() &&
1887
+					in_array(
1888
+						$registration->status_ID(),
1889
+						EEM_Registration::reg_statuses_that_allow_payment(),
1890
+						true
1891
+					)
1892
+				) {
1893
+					$count++;
1894
+				}
1895
+			}
1896
+			$new_li_fields['LIN_quantity'] = $count;
1897
+		}
1898
+		// don't set the total. We'll leave that up to the code that calculates it
1899
+		unset($new_li_fields['LIN_ID'], $new_li_fields['LIN_parent'], $new_li_fields['LIN_total']);
1900
+		return EE_Line_Item::new_instance($new_li_fields);
1901
+	}
1902
+
1903
+
1904
+	/**
1905
+	 * Returns a modified line item tree where all the subtotals which have a total of 0
1906
+	 * are removed, and line items with a quantity of 0
1907
+	 *
1908
+	 * @param EE_Line_Item $line_item |null
1909
+	 * @return EE_Line_Item|null
1910
+	 * @throws EE_Error
1911
+	 * @throws InvalidArgumentException
1912
+	 * @throws InvalidDataTypeException
1913
+	 * @throws InvalidInterfaceException
1914
+	 * @throws ReflectionException
1915
+	 */
1916
+	public static function non_empty_line_items(EE_Line_Item $line_item)
1917
+	{
1918
+		$copied_li = EEH_Line_Item::non_empty_line_item($line_item);
1919
+		if ($copied_li === null) {
1920
+			return null;
1921
+		}
1922
+		// if this is an event subtotal, we want to only include it if it
1923
+		// has a non-zero total and at least one ticket line item child
1924
+		$ticket_children = 0;
1925
+		foreach ($line_item->children() as $child_li) {
1926
+			$child_li_copy = EEH_Line_Item::non_empty_line_items($child_li);
1927
+			if ($child_li_copy !== null) {
1928
+				$copied_li->add_child_line_item($child_li_copy);
1929
+				if (
1930
+					$child_li_copy->type() === EEM_Line_Item::type_line_item &&
1931
+					$child_li_copy->OBJ_type() === EEM_Line_Item::OBJ_TYPE_TICKET
1932
+				) {
1933
+					$ticket_children++;
1934
+				}
1935
+			}
1936
+		}
1937
+		// if this is an event subtotal with NO ticket children
1938
+		// we basically want to ignore it
1939
+		if (
1940
+			$ticket_children === 0
1941
+			&& $line_item->type() === EEM_Line_Item::type_sub_total
1942
+			&& $line_item->OBJ_type() === EEM_Line_Item::OBJ_TYPE_EVENT
1943
+			&& $line_item->total() === 0
1944
+		) {
1945
+			return null;
1946
+		}
1947
+		return $copied_li;
1948
+	}
1949
+
1950
+
1951
+	/**
1952
+	 * Creates a new, unsaved line item, but if it's a ticket line item
1953
+	 * with a total of 0, or a subtotal of 0, returns null instead
1954
+	 *
1955
+	 * @param EE_Line_Item $line_item
1956
+	 * @return EE_Line_Item
1957
+	 * @throws EE_Error
1958
+	 * @throws InvalidArgumentException
1959
+	 * @throws InvalidDataTypeException
1960
+	 * @throws InvalidInterfaceException
1961
+	 * @throws ReflectionException
1962
+	 */
1963
+	public static function non_empty_line_item(EE_Line_Item $line_item)
1964
+	{
1965
+		if (
1966
+			$line_item->type() === EEM_Line_Item::type_line_item
1967
+			&& $line_item->OBJ_type() === EEM_Line_Item::OBJ_TYPE_TICKET
1968
+			&& $line_item->quantity() === 0
1969
+		) {
1970
+			return null;
1971
+		}
1972
+		$new_li_fields = $line_item->model_field_array();
1973
+		// don't set the total. We'll leave that up to the code that calculates it
1974
+		unset($new_li_fields['LIN_ID'], $new_li_fields['LIN_parent']);
1975
+		return EE_Line_Item::new_instance($new_li_fields);
1976
+	}
1977
+
1978
+
1979
+	/**
1980
+	 * Cycles through all of the ticket line items for the supplied total line item
1981
+	 * and ensures that the line item's "is_taxable" field matches that of its corresponding ticket
1982
+	 *
1983
+	 * @param EE_Line_Item $total_line_item
1984
+	 * @since 4.9.79.p
1985
+	 * @throws EE_Error
1986
+	 * @throws InvalidArgumentException
1987
+	 * @throws InvalidDataTypeException
1988
+	 * @throws InvalidInterfaceException
1989
+	 * @throws ReflectionException
1990
+	 */
1991
+	public static function resetIsTaxableForTickets(EE_Line_Item $total_line_item)
1992
+	{
1993
+		$ticket_line_items = self::get_ticket_line_items($total_line_item);
1994
+		foreach ($ticket_line_items as $ticket_line_item) {
1995
+			if (
1996
+				$ticket_line_item instanceof EE_Line_Item
1997
+				&& $ticket_line_item->OBJ_type() === EEM_Line_Item::OBJ_TYPE_TICKET
1998
+			) {
1999
+				$ticket = $ticket_line_item->ticket();
2000
+				if ($ticket instanceof EE_Ticket && $ticket->taxable() !== $ticket_line_item->is_taxable()) {
2001
+					$ticket_line_item->set_is_taxable($ticket->taxable());
2002
+					$ticket_line_item->save();
2003
+				}
2004
+			}
2005
+		}
2006
+	}
2007
+
2008
+
2009
+	/**
2010
+	 * @return EE_Line_Item[]
2011
+	 * @throws EE_Error
2012
+	 * @throws ReflectionException
2013
+	 * @since   $VID:$
2014
+	 */
2015
+	private static function getGlobalTaxes(): array
2016
+	{
2017
+		if (EEH_Line_Item::$global_taxes === null) {
2018
+
2019
+			/** @type EEM_Price $EEM_Price */
2020
+			$EEM_Price = EE_Registry::instance()->load_model('Price');
2021
+			// get array of taxes via Price Model
2022
+			EEH_Line_Item::$global_taxes = $EEM_Price->get_all_prices_that_are_taxes();
2023
+			ksort(EEH_Line_Item::$global_taxes);
2024
+		}
2025
+		return EEH_Line_Item::$global_taxes;
2026
+	}
2027
+
2028
+
2029
+
2030
+	/**************************************** @DEPRECATED METHODS *************************************** */
2031
+	/**
2032
+	 * @deprecated
2033
+	 * @param EE_Line_Item $total_line_item
2034
+	 * @return EE_Line_Item
2035
+	 * @throws EE_Error
2036
+	 * @throws InvalidArgumentException
2037
+	 * @throws InvalidDataTypeException
2038
+	 * @throws InvalidInterfaceException
2039
+	 * @throws ReflectionException
2040
+	 */
2041
+	public static function get_items_subtotal(EE_Line_Item $total_line_item)
2042
+	{
2043
+		EE_Error::doing_it_wrong(
2044
+			'EEH_Line_Item::get_items_subtotal()',
2045
+			sprintf(
2046
+				esc_html__('Method replaced with %1$s', 'event_espresso'),
2047
+				'EEH_Line_Item::get_pre_tax_subtotal()'
2048
+			),
2049
+			'4.6.0'
2050
+		);
2051
+		return self::get_pre_tax_subtotal($total_line_item);
2052
+	}
2053
+
2054
+
2055
+	/**
2056
+	 * @deprecated
2057
+	 * @param EE_Transaction $transaction
2058
+	 * @return EE_Line_Item
2059
+	 * @throws EE_Error
2060
+	 * @throws InvalidArgumentException
2061
+	 * @throws InvalidDataTypeException
2062
+	 * @throws InvalidInterfaceException
2063
+	 * @throws ReflectionException
2064
+	 */
2065
+	public static function create_default_total_line_item($transaction = null)
2066
+	{
2067
+		EE_Error::doing_it_wrong(
2068
+			'EEH_Line_Item::create_default_total_line_item()',
2069
+			sprintf(
2070
+				esc_html__('Method replaced with %1$s', 'event_espresso'),
2071
+				'EEH_Line_Item::create_total_line_item()'
2072
+			),
2073
+			'4.6.0'
2074
+		);
2075
+		return self::create_total_line_item($transaction);
2076
+	}
2077
+
2078
+
2079
+	/**
2080
+	 * @deprecated
2081
+	 * @param EE_Line_Item   $total_line_item
2082
+	 * @param EE_Transaction $transaction
2083
+	 * @return EE_Line_Item
2084
+	 * @throws EE_Error
2085
+	 * @throws InvalidArgumentException
2086
+	 * @throws InvalidDataTypeException
2087
+	 * @throws InvalidInterfaceException
2088
+	 * @throws ReflectionException
2089
+	 */
2090
+	public static function create_default_tickets_subtotal(EE_Line_Item $total_line_item, $transaction = null)
2091
+	{
2092
+		EE_Error::doing_it_wrong(
2093
+			'EEH_Line_Item::create_default_tickets_subtotal()',
2094
+			sprintf(
2095
+				esc_html__('Method replaced with %1$s', 'event_espresso'),
2096
+				'EEH_Line_Item::create_pre_tax_subtotal()'
2097
+			),
2098
+			'4.6.0'
2099
+		);
2100
+		return self::create_pre_tax_subtotal($total_line_item, $transaction);
2101
+	}
2102
+
2103
+
2104
+	/**
2105
+	 * @deprecated
2106
+	 * @param EE_Line_Item   $total_line_item
2107
+	 * @param EE_Transaction $transaction
2108
+	 * @return EE_Line_Item
2109
+	 * @throws EE_Error
2110
+	 * @throws InvalidArgumentException
2111
+	 * @throws InvalidDataTypeException
2112
+	 * @throws InvalidInterfaceException
2113
+	 * @throws ReflectionException
2114
+	 */
2115
+	public static function create_default_taxes_subtotal(EE_Line_Item $total_line_item, $transaction = null)
2116
+	{
2117
+		EE_Error::doing_it_wrong(
2118
+			'EEH_Line_Item::create_default_taxes_subtotal()',
2119
+			sprintf(
2120
+				esc_html__('Method replaced with %1$s', 'event_espresso'),
2121
+				'EEH_Line_Item::create_taxes_subtotal()'
2122
+			),
2123
+			'4.6.0'
2124
+		);
2125
+		return self::create_taxes_subtotal($total_line_item, $transaction);
2126
+	}
2127
+
2128
+
2129
+	/**
2130
+	 * @deprecated
2131
+	 * @param EE_Line_Item   $total_line_item
2132
+	 * @param EE_Transaction $transaction
2133
+	 * @return EE_Line_Item
2134
+	 * @throws EE_Error
2135
+	 * @throws InvalidArgumentException
2136
+	 * @throws InvalidDataTypeException
2137
+	 * @throws InvalidInterfaceException
2138
+	 * @throws ReflectionException
2139
+	 */
2140
+	public static function create_default_event_subtotal(EE_Line_Item $total_line_item, $transaction = null)
2141
+	{
2142
+		EE_Error::doing_it_wrong(
2143
+			'EEH_Line_Item::create_default_event_subtotal()',
2144
+			sprintf(
2145
+				esc_html__('Method replaced with %1$s', 'event_espresso'),
2146
+				'EEH_Line_Item::create_event_subtotal()'
2147
+			),
2148
+			'4.6.0'
2149
+		);
2150
+		return self::create_event_subtotal($total_line_item, $transaction);
2151
+	}
2152 2152
 }
Please login to merge, or discard this patch.