Completed
Branch BUG/dont-reuse-DMS-scripts-dur... (079350)
by
unknown
02:59 queued 28s
created
core/services/request/sanitizers/AllowedTags.php 1 patch
Indentation   +279 added lines, -279 removed lines patch added patch discarded remove patch
@@ -13,283 +13,283 @@
 block discarded – undo
13 13
 class AllowedTags
14 14
 {
15 15
 
16
-    /**
17
-     * @var array[]
18
-     */
19
-    private static $attributes = [
20
-        'accept-charset'    => 1,
21
-        'action'            => 1,
22
-        'alt'               => 1,
23
-        'allow'             => 1,
24
-        'allowfullscreen'   => 1,
25
-        'align'             => 1,
26
-        'aria-*'            => 1,
27
-        'autocomplete'      => 1,
28
-        'checked'           => 1,
29
-        'class'             => 1,
30
-        'cols'              => 1,
31
-        'content'           => 1,
32
-        'data-*'            => 1,
33
-        'dir'               => 1,
34
-        'disabled'          => 1,
35
-        'enctype'           => 1,
36
-        'for'               => 1,
37
-        'frameborder'       => 1,
38
-        'height'            => 1,
39
-        'href'              => 1,
40
-        'id'                => 1,
41
-        'itemprop'          => 1,
42
-        'itemscope'         => 1,
43
-        'itemtype'          => 1,
44
-        'label'             => 1,
45
-        'lang'              => 1,
46
-        'max'               => 1,
47
-        'maxlength'         => 1,
48
-        'method'            => 1,
49
-        'min'               => 1,
50
-        'multiple'          => 1,
51
-        'name'              => 1,
52
-        'novalidate'        => 1,
53
-        'placeholder'       => 1,
54
-        'readonly'          => 1,
55
-        'rel'               => 1,
56
-        'required'          => 1,
57
-        'rows'              => 1,
58
-        'selected'          => 1,
59
-        'src'               => 1,
60
-        'size'              => 1,
61
-        'style'             => 1,
62
-        'step'              => 1,
63
-        'tabindex'          => 1,
64
-        'target'            => 1,
65
-        'title'             => 1,
66
-        'type'              => 1,
67
-        'value'             => 1,
68
-        'width'             => 1,
69
-        'topmargin'         => 1,
70
-        'leftmargin'        => 1,
71
-        'marginheight'      => 1,
72
-        'marginwidth'       => 1,
73
-        'property'          => 1,
74
-        'bgcolor'           => 1,
75
-        'media'             => 1,
76
-        'cellpadding'       => 1,
77
-        'cellspacing'       => 1,
78
-        'border'            => 1,
79
-    ];
80
-
81
-
82
-    /**
83
-     * @var array
84
-     */
85
-    private static $tags = [
86
-        'a',
87
-        'abbr',
88
-        'b',
89
-        'br',
90
-        'code',
91
-        'div',
92
-        'em',
93
-        'h1',
94
-        'h2',
95
-        'h3',
96
-        'h4',
97
-        'h5',
98
-        'h6',
99
-        'hr',
100
-        'i',
101
-        'img',
102
-        'li',
103
-        'ol',
104
-        'p',
105
-        'pre',
106
-        'small',
107
-        'span',
108
-        'strong',
109
-        'table',
110
-        'td',
111
-        'tr',
112
-        'ul',
113
-    ];
114
-
115
-
116
-    /**
117
-     * @var array
118
-     */
119
-    private static $allowed_tags;
120
-
121
-
122
-    /**
123
-     * @var array
124
-     */
125
-    private static $allowed_with_embed_tags;
126
-
127
-
128
-    /**
129
-     * @var array
130
-     */
131
-    private static $allowed_with_form_tags;
132
-
133
-
134
-    /**
135
-     * @var array
136
-     */
137
-    private static $allowed_with_script_and_style_tags;
138
-
139
-    /**
140
-     * @var array
141
-     */
142
-    private static $allowed_with_full_tags;
143
-
144
-
145
-    /**
146
-     * merges additional tags and attributes into the WP post tags
147
-     */
148
-    private static function initializeAllowedTags()
149
-    {
150
-        $allowed_post_tags = wp_kses_allowed_html('post');
151
-        $allowed_tags = [];
152
-        foreach (AllowedTags::$tags as $tag) {
153
-            $allowed_tags[ $tag ] = AllowedTags::$attributes;
154
-        }
155
-        AllowedTags::$allowed_tags = array_merge_recursive($allowed_post_tags, $allowed_tags);
156
-    }
157
-
158
-
159
-    /**
160
-     * merges embed tags and attributes into the EE all tags
161
-     */
162
-    private static function initializeWithEmbedTags()
163
-    {
164
-        $all_tags = AllowedTags::getAllowedTags();
165
-        $embed_tags = [
166
-            'iframe' => AllowedTags::$attributes
167
-        ];
168
-        AllowedTags::$allowed_with_embed_tags = array_merge_recursive($all_tags, $embed_tags);
169
-    }
170
-
171
-
172
-    /**
173
-     * merges form tags and attributes into the EE all tags
174
-     */
175
-    private static function initializeWithFormTags()
176
-    {
177
-        $all_tags = AllowedTags::getAllowedTags();
178
-        $form_tags = [
179
-            'form'     => AllowedTags::$attributes,
180
-            'label'    => AllowedTags::$attributes,
181
-            'input'    => AllowedTags::$attributes,
182
-            'select'   => AllowedTags::$attributes,
183
-            'option'   => AllowedTags::$attributes,
184
-            'optgroup' => AllowedTags::$attributes,
185
-            'textarea' => AllowedTags::$attributes,
186
-            'button'   => AllowedTags::$attributes,
187
-            'fieldset' => AllowedTags::$attributes,
188
-            'output'   => AllowedTags::$attributes,
189
-        ];
190
-        AllowedTags::$allowed_with_form_tags = array_merge_recursive($all_tags, $form_tags);
191
-    }
192
-
193
-
194
-    /**
195
-     * merges form script and style tags and attributes into the EE all tags
196
-     */
197
-    private static function initializeWithScriptAndStyleTags()
198
-    {
199
-        $all_tags = AllowedTags::getAllowedTags();
200
-        $script_and_style_tags = [
201
-            'script'   => AllowedTags::$attributes,
202
-            'style'    => AllowedTags::$attributes,
203
-            'link'     => AllowedTags::$attributes,
204
-            'noscript' => AllowedTags::$attributes,
205
-        ];
206
-        AllowedTags::$allowed_with_script_and_style_tags = array_merge_recursive($all_tags, $script_and_style_tags);
207
-    }
208
-
209
-    /**
210
-     * merges all head and body tags and attributes into the EE all tags
211
-     */
212
-    private static function initializeWithFullTags()
213
-    {
214
-        $all_tags = AllowedTags::getAllowedTags();
215
-        $full_tags = [
216
-            'script'    => AllowedTags::$attributes,
217
-            'style'     => AllowedTags::$attributes,
218
-            'link'      => AllowedTags::$attributes,
219
-            'title'     => AllowedTags::$attributes,
220
-            'meta'      => AllowedTags::$attributes,
221
-            'iframe'    => AllowedTags::$attributes,
222
-            'form'      => AllowedTags::$attributes,
223
-            'label'     => AllowedTags::$attributes,
224
-            'input'     => AllowedTags::$attributes,
225
-            'select'    => AllowedTags::$attributes,
226
-            'option'    => AllowedTags::$attributes,
227
-            'optgroup'  => AllowedTags::$attributes,
228
-            'textarea'  => AllowedTags::$attributes,
229
-            'button'    => AllowedTags::$attributes,
230
-            'fieldset'  => AllowedTags::$attributes,
231
-            'output'    => AllowedTags::$attributes,
232
-            'noscript'  => AllowedTags::$attributes,
233
-        ];
234
-        AllowedTags::$allowed_with_full_tags = array_merge_recursive($all_tags, $full_tags);
235
-    }
236
-
237
-
238
-    /**
239
-     * @return array[]
240
-     */
241
-    public static function getAllowedTags()
242
-    {
243
-        if (empty(AllowedTags::$allowed_tags)) {
244
-            AllowedTags::initializeAllowedTags();
245
-        }
246
-        return AllowedTags::$allowed_tags;
247
-    }
248
-
249
-
250
-    /**
251
-     * @return array[]
252
-     */
253
-    public static function getWithEmbedTags()
254
-    {
255
-        if (empty(AllowedTags::$allowed_with_embed_tags)) {
256
-            AllowedTags::initializeWithEmbedTags();
257
-        }
258
-        return AllowedTags::$allowed_with_embed_tags;
259
-    }
260
-
261
-
262
-    /**
263
-     * @return array[]
264
-     */
265
-    public static function getWithFormTags()
266
-    {
267
-        if (empty(AllowedTags::$allowed_with_form_tags)) {
268
-            AllowedTags::initializeWithFormTags();
269
-        }
270
-        return AllowedTags::$allowed_with_form_tags;
271
-    }
272
-
273
-
274
-    /**
275
-     * @return array[]
276
-     */
277
-    public static function getWithScriptAndStyleTags()
278
-    {
279
-        if (empty(AllowedTags::$allowed_with_script_and_style_tags)) {
280
-            AllowedTags::initializeWithScriptAndStyleTags();
281
-        }
282
-        return AllowedTags::$allowed_with_script_and_style_tags;
283
-    }
284
-
285
-    /**
286
-     * @return array[]
287
-     */
288
-    public static function getWithFullTags()
289
-    {
290
-        if (empty(AllowedTags::$allowed_with_full_tags)) {
291
-            AllowedTags::initializeWithFullTags();
292
-        }
293
-        return AllowedTags::$allowed_with_full_tags;
294
-    }
16
+	/**
17
+	 * @var array[]
18
+	 */
19
+	private static $attributes = [
20
+		'accept-charset'    => 1,
21
+		'action'            => 1,
22
+		'alt'               => 1,
23
+		'allow'             => 1,
24
+		'allowfullscreen'   => 1,
25
+		'align'             => 1,
26
+		'aria-*'            => 1,
27
+		'autocomplete'      => 1,
28
+		'checked'           => 1,
29
+		'class'             => 1,
30
+		'cols'              => 1,
31
+		'content'           => 1,
32
+		'data-*'            => 1,
33
+		'dir'               => 1,
34
+		'disabled'          => 1,
35
+		'enctype'           => 1,
36
+		'for'               => 1,
37
+		'frameborder'       => 1,
38
+		'height'            => 1,
39
+		'href'              => 1,
40
+		'id'                => 1,
41
+		'itemprop'          => 1,
42
+		'itemscope'         => 1,
43
+		'itemtype'          => 1,
44
+		'label'             => 1,
45
+		'lang'              => 1,
46
+		'max'               => 1,
47
+		'maxlength'         => 1,
48
+		'method'            => 1,
49
+		'min'               => 1,
50
+		'multiple'          => 1,
51
+		'name'              => 1,
52
+		'novalidate'        => 1,
53
+		'placeholder'       => 1,
54
+		'readonly'          => 1,
55
+		'rel'               => 1,
56
+		'required'          => 1,
57
+		'rows'              => 1,
58
+		'selected'          => 1,
59
+		'src'               => 1,
60
+		'size'              => 1,
61
+		'style'             => 1,
62
+		'step'              => 1,
63
+		'tabindex'          => 1,
64
+		'target'            => 1,
65
+		'title'             => 1,
66
+		'type'              => 1,
67
+		'value'             => 1,
68
+		'width'             => 1,
69
+		'topmargin'         => 1,
70
+		'leftmargin'        => 1,
71
+		'marginheight'      => 1,
72
+		'marginwidth'       => 1,
73
+		'property'          => 1,
74
+		'bgcolor'           => 1,
75
+		'media'             => 1,
76
+		'cellpadding'       => 1,
77
+		'cellspacing'       => 1,
78
+		'border'            => 1,
79
+	];
80
+
81
+
82
+	/**
83
+	 * @var array
84
+	 */
85
+	private static $tags = [
86
+		'a',
87
+		'abbr',
88
+		'b',
89
+		'br',
90
+		'code',
91
+		'div',
92
+		'em',
93
+		'h1',
94
+		'h2',
95
+		'h3',
96
+		'h4',
97
+		'h5',
98
+		'h6',
99
+		'hr',
100
+		'i',
101
+		'img',
102
+		'li',
103
+		'ol',
104
+		'p',
105
+		'pre',
106
+		'small',
107
+		'span',
108
+		'strong',
109
+		'table',
110
+		'td',
111
+		'tr',
112
+		'ul',
113
+	];
114
+
115
+
116
+	/**
117
+	 * @var array
118
+	 */
119
+	private static $allowed_tags;
120
+
121
+
122
+	/**
123
+	 * @var array
124
+	 */
125
+	private static $allowed_with_embed_tags;
126
+
127
+
128
+	/**
129
+	 * @var array
130
+	 */
131
+	private static $allowed_with_form_tags;
132
+
133
+
134
+	/**
135
+	 * @var array
136
+	 */
137
+	private static $allowed_with_script_and_style_tags;
138
+
139
+	/**
140
+	 * @var array
141
+	 */
142
+	private static $allowed_with_full_tags;
143
+
144
+
145
+	/**
146
+	 * merges additional tags and attributes into the WP post tags
147
+	 */
148
+	private static function initializeAllowedTags()
149
+	{
150
+		$allowed_post_tags = wp_kses_allowed_html('post');
151
+		$allowed_tags = [];
152
+		foreach (AllowedTags::$tags as $tag) {
153
+			$allowed_tags[ $tag ] = AllowedTags::$attributes;
154
+		}
155
+		AllowedTags::$allowed_tags = array_merge_recursive($allowed_post_tags, $allowed_tags);
156
+	}
157
+
158
+
159
+	/**
160
+	 * merges embed tags and attributes into the EE all tags
161
+	 */
162
+	private static function initializeWithEmbedTags()
163
+	{
164
+		$all_tags = AllowedTags::getAllowedTags();
165
+		$embed_tags = [
166
+			'iframe' => AllowedTags::$attributes
167
+		];
168
+		AllowedTags::$allowed_with_embed_tags = array_merge_recursive($all_tags, $embed_tags);
169
+	}
170
+
171
+
172
+	/**
173
+	 * merges form tags and attributes into the EE all tags
174
+	 */
175
+	private static function initializeWithFormTags()
176
+	{
177
+		$all_tags = AllowedTags::getAllowedTags();
178
+		$form_tags = [
179
+			'form'     => AllowedTags::$attributes,
180
+			'label'    => AllowedTags::$attributes,
181
+			'input'    => AllowedTags::$attributes,
182
+			'select'   => AllowedTags::$attributes,
183
+			'option'   => AllowedTags::$attributes,
184
+			'optgroup' => AllowedTags::$attributes,
185
+			'textarea' => AllowedTags::$attributes,
186
+			'button'   => AllowedTags::$attributes,
187
+			'fieldset' => AllowedTags::$attributes,
188
+			'output'   => AllowedTags::$attributes,
189
+		];
190
+		AllowedTags::$allowed_with_form_tags = array_merge_recursive($all_tags, $form_tags);
191
+	}
192
+
193
+
194
+	/**
195
+	 * merges form script and style tags and attributes into the EE all tags
196
+	 */
197
+	private static function initializeWithScriptAndStyleTags()
198
+	{
199
+		$all_tags = AllowedTags::getAllowedTags();
200
+		$script_and_style_tags = [
201
+			'script'   => AllowedTags::$attributes,
202
+			'style'    => AllowedTags::$attributes,
203
+			'link'     => AllowedTags::$attributes,
204
+			'noscript' => AllowedTags::$attributes,
205
+		];
206
+		AllowedTags::$allowed_with_script_and_style_tags = array_merge_recursive($all_tags, $script_and_style_tags);
207
+	}
208
+
209
+	/**
210
+	 * merges all head and body tags and attributes into the EE all tags
211
+	 */
212
+	private static function initializeWithFullTags()
213
+	{
214
+		$all_tags = AllowedTags::getAllowedTags();
215
+		$full_tags = [
216
+			'script'    => AllowedTags::$attributes,
217
+			'style'     => AllowedTags::$attributes,
218
+			'link'      => AllowedTags::$attributes,
219
+			'title'     => AllowedTags::$attributes,
220
+			'meta'      => AllowedTags::$attributes,
221
+			'iframe'    => AllowedTags::$attributes,
222
+			'form'      => AllowedTags::$attributes,
223
+			'label'     => AllowedTags::$attributes,
224
+			'input'     => AllowedTags::$attributes,
225
+			'select'    => AllowedTags::$attributes,
226
+			'option'    => AllowedTags::$attributes,
227
+			'optgroup'  => AllowedTags::$attributes,
228
+			'textarea'  => AllowedTags::$attributes,
229
+			'button'    => AllowedTags::$attributes,
230
+			'fieldset'  => AllowedTags::$attributes,
231
+			'output'    => AllowedTags::$attributes,
232
+			'noscript'  => AllowedTags::$attributes,
233
+		];
234
+		AllowedTags::$allowed_with_full_tags = array_merge_recursive($all_tags, $full_tags);
235
+	}
236
+
237
+
238
+	/**
239
+	 * @return array[]
240
+	 */
241
+	public static function getAllowedTags()
242
+	{
243
+		if (empty(AllowedTags::$allowed_tags)) {
244
+			AllowedTags::initializeAllowedTags();
245
+		}
246
+		return AllowedTags::$allowed_tags;
247
+	}
248
+
249
+
250
+	/**
251
+	 * @return array[]
252
+	 */
253
+	public static function getWithEmbedTags()
254
+	{
255
+		if (empty(AllowedTags::$allowed_with_embed_tags)) {
256
+			AllowedTags::initializeWithEmbedTags();
257
+		}
258
+		return AllowedTags::$allowed_with_embed_tags;
259
+	}
260
+
261
+
262
+	/**
263
+	 * @return array[]
264
+	 */
265
+	public static function getWithFormTags()
266
+	{
267
+		if (empty(AllowedTags::$allowed_with_form_tags)) {
268
+			AllowedTags::initializeWithFormTags();
269
+		}
270
+		return AllowedTags::$allowed_with_form_tags;
271
+	}
272
+
273
+
274
+	/**
275
+	 * @return array[]
276
+	 */
277
+	public static function getWithScriptAndStyleTags()
278
+	{
279
+		if (empty(AllowedTags::$allowed_with_script_and_style_tags)) {
280
+			AllowedTags::initializeWithScriptAndStyleTags();
281
+		}
282
+		return AllowedTags::$allowed_with_script_and_style_tags;
283
+	}
284
+
285
+	/**
286
+	 * @return array[]
287
+	 */
288
+	public static function getWithFullTags()
289
+	{
290
+		if (empty(AllowedTags::$allowed_with_full_tags)) {
291
+			AllowedTags::initializeWithFullTags();
292
+		}
293
+		return AllowedTags::$allowed_with_full_tags;
294
+	}
295 295
 }
Please login to merge, or discard this patch.
core/EE_System.core.php 2 patches
Indentation   +1353 added lines, -1353 removed lines patch added patch discarded remove patch
@@ -27,1357 +27,1357 @@
 block discarded – undo
27 27
 final class EE_System implements ResettableInterface
28 28
 {
29 29
 
30
-    /**
31
-     * indicates this is a 'normal' request. Ie, not activation, nor upgrade, nor activation.
32
-     * So examples of this would be a normal GET request on the frontend or backend, or a POST, etc
33
-     */
34
-    const req_type_normal = 0;
35
-
36
-    /**
37
-     * Indicates this is a brand new installation of EE so we should install
38
-     * tables and default data etc
39
-     */
40
-    const req_type_new_activation = 1;
41
-
42
-    /**
43
-     * we've detected that EE has been reactivated (or EE was activated during maintenance mode,
44
-     * and we just exited maintenance mode). We MUST check the database is setup properly
45
-     * and that default data is setup too
46
-     */
47
-    const req_type_reactivation = 2;
48
-
49
-    /**
50
-     * indicates that EE has been upgraded since its previous request.
51
-     * We may have data migration scripts to call and will want to trigger maintenance mode
52
-     */
53
-    const req_type_upgrade = 3;
54
-
55
-    /**
56
-     * TODO  will detect that EE has been DOWNGRADED. We probably don't want to run in this case...
57
-     */
58
-    const req_type_downgrade = 4;
59
-
60
-    /**
61
-     * @deprecated since version 4.6.0.dev.006
62
-     * Now whenever a new_activation is detected the request type is still just
63
-     * new_activation (same for reactivation, upgrade, downgrade etc), but if we'r ein maintenance mode
64
-     * EE_System::initialize_db_if_no_migrations_required and EE_Addon::initialize_db_if_no_migrations_required
65
-     * will instead enqueue that EE plugin's db initialization for when we're taken out of maintenance mode.
66
-     * (Specifically, when the migration manager indicates migrations are finished
67
-     * EE_Data_Migration_Manager::initialize_db_for_enqueued_ee_plugins() will be called)
68
-     */
69
-    const req_type_activation_but_not_installed = 5;
70
-
71
-    /**
72
-     * option prefix for recording the activation history (like core's "espresso_db_update") of addons
73
-     */
74
-    const addon_activation_history_option_prefix = 'ee_addon_activation_history_';
75
-
76
-    /**
77
-     * @var EE_System $_instance
78
-     */
79
-    private static $_instance;
80
-
81
-    /**
82
-     * @var EE_Registry $registry
83
-     */
84
-    private $registry;
85
-
86
-    /**
87
-     * @var LoaderInterface $loader
88
-     */
89
-    private $loader;
90
-
91
-    /**
92
-     * @var EE_Capabilities $capabilities
93
-     */
94
-    private $capabilities;
95
-
96
-    /**
97
-     * @var RequestInterface $request
98
-     */
99
-    private $request;
100
-
101
-    /**
102
-     * @var EE_Maintenance_Mode $maintenance_mode
103
-     */
104
-    private $maintenance_mode;
105
-
106
-    /**
107
-     * Stores which type of request this is, options being one of the constants on EE_System starting with req_type_*.
108
-     * It can be a brand-new activation, a reactivation, an upgrade, a downgrade, or a normal request.
109
-     *
110
-     * @var int $_req_type
111
-     */
112
-    private $_req_type;
113
-
114
-    /**
115
-     * Whether or not there was a non-micro version change in EE core version during this request
116
-     *
117
-     * @var boolean $_major_version_change
118
-     */
119
-    private $_major_version_change = false;
120
-
121
-    /**
122
-     * A Context DTO dedicated solely to identifying the current request type.
123
-     *
124
-     * @var RequestTypeContextCheckerInterface $request_type
125
-     */
126
-    private $request_type;
127
-
128
-    /**
129
-     * @param EventEspresso\core\domain\services\custom_post_types\RegisterCustomPostTypes
130
-     */
131
-    private $register_custom_post_types;
132
-
133
-    /**
134
-     * @param EventEspresso\core\domain\services\custom_post_types\RegisterCustomTaxonomies
135
-     */
136
-    private $register_custom_taxonomies;
137
-
138
-    /**
139
-     * @param EventEspresso\core\domain\services\custom_post_types\RegisterCustomTaxonomyTerms
140
-     */
141
-    private $register_custom_taxonomy_terms;
142
-
143
-    /**
144
-     * @singleton method used to instantiate class object
145
-     * @param EE_Registry|null         $registry
146
-     * @param LoaderInterface|null     $loader
147
-     * @param RequestInterface|null    $request
148
-     * @param EE_Maintenance_Mode|null $maintenance_mode
149
-     * @return EE_System
150
-     */
151
-    public static function instance(
152
-        EE_Registry $registry = null,
153
-        LoaderInterface $loader = null,
154
-        RequestInterface $request = null,
155
-        EE_Maintenance_Mode $maintenance_mode = null
156
-    ) {
157
-        // check if class object is instantiated
158
-        if (! self::$_instance instanceof EE_System) {
159
-            self::$_instance = new self($registry, $loader, $request, $maintenance_mode);
160
-        }
161
-        return self::$_instance;
162
-    }
163
-
164
-
165
-    /**
166
-     * resets the instance and returns it
167
-     *
168
-     * @return EE_System
169
-     */
170
-    public static function reset()
171
-    {
172
-        self::$_instance->_req_type = null;
173
-        // make sure none of the old hooks are left hanging around
174
-        remove_all_actions('AHEE__EE_System__perform_activations_upgrades_and_migrations');
175
-        // we need to reset the migration manager in order for it to detect DMSs properly
176
-        EE_Data_Migration_Manager::reset();
177
-        self::instance()->detect_activations_or_upgrades();
178
-        self::instance()->perform_activations_upgrades_and_migrations();
179
-        return self::instance();
180
-    }
181
-
182
-
183
-    /**
184
-     * sets hooks for running rest of system
185
-     * provides "AHEE__EE_System__construct__complete" hook for EE Addons to use as their starting point
186
-     * starting EE Addons from any other point may lead to problems
187
-     *
188
-     * @param EE_Registry         $registry
189
-     * @param LoaderInterface     $loader
190
-     * @param RequestInterface    $request
191
-     * @param EE_Maintenance_Mode $maintenance_mode
192
-     */
193
-    private function __construct(
194
-        EE_Registry $registry,
195
-        LoaderInterface $loader,
196
-        RequestInterface $request,
197
-        EE_Maintenance_Mode $maintenance_mode
198
-    ) {
199
-        $this->registry = $registry;
200
-        $this->loader = $loader;
201
-        $this->request = $request;
202
-        $this->maintenance_mode = $maintenance_mode;
203
-        do_action('AHEE__EE_System__construct__begin', $this);
204
-        add_action(
205
-            'AHEE__EE_Bootstrap__load_espresso_addons',
206
-            array($this, 'loadCapabilities'),
207
-            5
208
-        );
209
-        add_action(
210
-            'AHEE__EE_Bootstrap__load_espresso_addons',
211
-            array($this, 'loadCommandBus'),
212
-            7
213
-        );
214
-        add_action(
215
-            'AHEE__EE_Bootstrap__load_espresso_addons',
216
-            array($this, 'loadPluginApi'),
217
-            9
218
-        );
219
-        // allow addons to load first so that they can register autoloaders, set hooks for running DMS's, etc
220
-        add_action(
221
-            'AHEE__EE_Bootstrap__load_espresso_addons',
222
-            array($this, 'load_espresso_addons')
223
-        );
224
-        // when an ee addon is activated, we want to call the core hook(s) again
225
-        // because the newly-activated addon didn't get a chance to run at all
226
-        add_action('activate_plugin', array($this, 'load_espresso_addons'), 1);
227
-        // detect whether install or upgrade
228
-        add_action(
229
-            'AHEE__EE_Bootstrap__detect_activations_or_upgrades',
230
-            array($this, 'detect_activations_or_upgrades'),
231
-            3
232
-        );
233
-        // load EE_Config, EE_Textdomain, etc
234
-        add_action(
235
-            'AHEE__EE_Bootstrap__load_core_configuration',
236
-            array($this, 'load_core_configuration'),
237
-            5
238
-        );
239
-        // load specifications for matching routes to current request
240
-        add_action(
241
-            'AHEE__EE_Bootstrap__load_core_configuration',
242
-            array($this, 'loadRouteMatchSpecifications')
243
-        );
244
-        // load specifications for custom post types
245
-        add_action(
246
-            'AHEE__EE_Bootstrap__load_core_configuration',
247
-            array($this, 'loadCustomPostTypes')
248
-        );
249
-        // load EE_Config, EE_Textdomain, etc
250
-        add_action(
251
-            'AHEE__EE_Bootstrap__register_shortcodes_modules_and_widgets',
252
-            array($this, 'register_shortcodes_modules_and_widgets'),
253
-            7
254
-        );
255
-        // you wanna get going? I wanna get going... let's get going!
256
-        add_action(
257
-            'AHEE__EE_Bootstrap__brew_espresso',
258
-            array($this, 'brew_espresso'),
259
-            9
260
-        );
261
-        // other housekeeping
262
-        // exclude EE critical pages from wp_list_pages
263
-        add_filter(
264
-            'wp_list_pages_excludes',
265
-            array($this, 'remove_pages_from_wp_list_pages'),
266
-            10
267
-        );
268
-        // ALL EE Addons should use the following hook point to attach their initial setup too
269
-        // it's extremely important for EE Addons to register any class autoloaders so that they can be available when the EE_Config loads
270
-        do_action('AHEE__EE_System__construct__complete', $this);
271
-    }
272
-
273
-
274
-    /**
275
-     * load and setup EE_Capabilities
276
-     *
277
-     * @return void
278
-     * @throws EE_Error
279
-     */
280
-    public function loadCapabilities()
281
-    {
282
-        $this->capabilities = $this->loader->getShared('EE_Capabilities');
283
-        add_action(
284
-            'AHEE__EE_Capabilities__init_caps__before_initialization',
285
-            function () {
286
-                LoaderFactory::getLoader()->getShared('EE_Payment_Method_Manager');
287
-            }
288
-        );
289
-    }
290
-
291
-
292
-    /**
293
-     * create and cache the CommandBus, and also add middleware
294
-     * The CapChecker middleware requires the use of EE_Capabilities
295
-     * which is why we need to load the CommandBus after Caps are set up
296
-     *
297
-     * @return void
298
-     * @throws EE_Error
299
-     */
300
-    public function loadCommandBus()
301
-    {
302
-        $this->loader->getShared(
303
-            'CommandBusInterface',
304
-            array(
305
-                null,
306
-                apply_filters(
307
-                    'FHEE__EE_Load_Espresso_Core__handle_request__CommandBus_middleware',
308
-                    array(
309
-                        $this->loader->getShared('EventEspresso\core\services\commands\middleware\CapChecker'),
310
-                        $this->loader->getShared('EventEspresso\core\services\commands\middleware\AddActionHook'),
311
-                    )
312
-                ),
313
-            )
314
-        );
315
-    }
316
-
317
-
318
-    /**
319
-     * @return void
320
-     * @throws EE_Error
321
-     */
322
-    public function loadPluginApi()
323
-    {
324
-        // set autoloaders for all of the classes implementing EEI_Plugin_API
325
-        // which provide helpers for EE plugin authors to more easily register certain components with EE.
326
-        EEH_Autoloader::instance()->register_autoloaders_for_each_file_in_folder(EE_LIBRARIES . 'plugin_api');
327
-    }
328
-
329
-
330
-    /**
331
-     * @param string $addon_name
332
-     * @param string $version_constant
333
-     * @param string $min_version_required
334
-     * @param string $load_callback
335
-     * @param string $plugin_file_constant
336
-     * @return void
337
-     */
338
-    private function deactivateIncompatibleAddon(
339
-        $addon_name,
340
-        $version_constant,
341
-        $min_version_required,
342
-        $load_callback,
343
-        $plugin_file_constant
344
-    ) {
345
-        if (! defined($version_constant)) {
346
-            return;
347
-        }
348
-        $addon_version = constant($version_constant);
349
-        if ($addon_version && version_compare($addon_version, $min_version_required, '<')) {
350
-            remove_action('AHEE__EE_System__load_espresso_addons', $load_callback);
351
-            if (! function_exists('deactivate_plugins')) {
352
-                require_once ABSPATH . 'wp-admin/includes/plugin.php';
353
-            }
354
-            deactivate_plugins(plugin_basename(constant($plugin_file_constant)));
355
-            $this->request->unSetRequestParams(['activate', 'activate-multi'], true);
356
-            EE_Error::add_error(
357
-                sprintf(
358
-                    esc_html__(
359
-                        'We\'re sorry, but the Event Espresso %1$s addon was deactivated because version %2$s or higher is required with this version of Event Espresso core.',
360
-                        'event_espresso'
361
-                    ),
362
-                    $addon_name,
363
-                    $min_version_required
364
-                ),
365
-                __FILE__,
366
-                __FUNCTION__ . "({$addon_name})",
367
-                __LINE__
368
-            );
369
-            EE_Error::get_notices(false, true);
370
-        }
371
-    }
372
-
373
-
374
-    /**
375
-     * load_espresso_addons
376
-     * allow addons to load first so that they can set hooks for running DMS's, etc
377
-     * this is hooked into both:
378
-     *    'AHEE__EE_Bootstrap__load_core_configuration'
379
-     *        which runs during the WP 'plugins_loaded' action at priority 5
380
-     *    and the WP 'activate_plugin' hook point
381
-     *
382
-     * @access public
383
-     * @return void
384
-     */
385
-    public function load_espresso_addons()
386
-    {
387
-        $this->deactivateIncompatibleAddon(
388
-            'Wait Lists',
389
-            'EE_WAIT_LISTS_VERSION',
390
-            '1.0.0.beta.074',
391
-            'load_espresso_wait_lists',
392
-            'EE_WAIT_LISTS_PLUGIN_FILE'
393
-        );
394
-        $this->deactivateIncompatibleAddon(
395
-            'Automated Upcoming Event Notifications',
396
-            'EE_AUTOMATED_UPCOMING_EVENT_NOTIFICATION_VERSION',
397
-            '1.0.0.beta.091',
398
-            'load_espresso_automated_upcoming_event_notification',
399
-            'EE_AUTOMATED_UPCOMING_EVENT_NOTIFICATION_PLUGIN_FILE'
400
-        );
401
-        do_action('AHEE__EE_System__load_espresso_addons');
402
-        // if the WP API basic auth plugin isn't already loaded, load it now.
403
-        // We want it for mobile apps. Just include the entire plugin
404
-        // also, don't load the basic auth when a plugin is getting activated, because
405
-        // it could be the basic auth plugin, and it doesn't check if its methods are already defined
406
-        // and causes a fatal error
407
-        if (
408
-            ($this->request->isWordPressApi() || $this->request->isApi())
409
-            && $this->request->getRequestParam('activate') !== 'true'
410
-            && ! function_exists('json_basic_auth_handler')
411
-            && ! function_exists('json_basic_auth_error')
412
-            && ! in_array(
413
-                $this->request->getRequestParam('action'),
414
-                array('activate', 'activate-selected'),
415
-                true
416
-            )
417
-        ) {
418
-            include_once EE_THIRD_PARTY . 'wp-api-basic-auth/basic-auth.php';
419
-        }
420
-        do_action('AHEE__EE_System__load_espresso_addons__complete');
421
-    }
422
-
423
-
424
-    /**
425
-     * detect_activations_or_upgrades
426
-     * Checks for activation or upgrade of core first;
427
-     * then also checks if any registered addons have been activated or upgraded
428
-     * This is hooked into 'AHEE__EE_Bootstrap__detect_activations_or_upgrades'
429
-     * which runs during the WP 'plugins_loaded' action at priority 3
430
-     *
431
-     * @access public
432
-     * @return void
433
-     */
434
-    public function detect_activations_or_upgrades()
435
-    {
436
-        // first off: let's make sure to handle core
437
-        $this->detect_if_activation_or_upgrade();
438
-        foreach ($this->registry->addons as $addon) {
439
-            if ($addon instanceof EE_Addon) {
440
-                // detect teh request type for that addon
441
-                $addon->detect_req_type();
442
-            }
443
-        }
444
-    }
445
-
446
-
447
-    /**
448
-     * detect_if_activation_or_upgrade
449
-     * Takes care of detecting whether this is a brand new install or code upgrade,
450
-     * and either setting up the DB or setting up maintenance mode etc.
451
-     *
452
-     * @access public
453
-     * @return void
454
-     */
455
-    public function detect_if_activation_or_upgrade()
456
-    {
457
-        do_action('AHEE__EE_System___detect_if_activation_or_upgrade__begin');
458
-        // check if db has been updated, or if its a brand-new installation
459
-        $espresso_db_update = $this->fix_espresso_db_upgrade_option();
460
-        $request_type = $this->detect_req_type($espresso_db_update);
461
-        // EEH_Debug_Tools::printr( $request_type, '$request_type', __FILE__, __LINE__ );
462
-        switch ($request_type) {
463
-            case EE_System::req_type_new_activation:
464
-                do_action('AHEE__EE_System__detect_if_activation_or_upgrade__new_activation');
465
-                $this->_handle_core_version_change($espresso_db_update);
466
-                break;
467
-            case EE_System::req_type_reactivation:
468
-                do_action('AHEE__EE_System__detect_if_activation_or_upgrade__reactivation');
469
-                $this->_handle_core_version_change($espresso_db_update);
470
-                break;
471
-            case EE_System::req_type_upgrade:
472
-                do_action('AHEE__EE_System__detect_if_activation_or_upgrade__upgrade');
473
-                // migrations may be required now that we've upgraded
474
-                $this->maintenance_mode->set_maintenance_mode_if_db_old();
475
-                $this->_handle_core_version_change($espresso_db_update);
476
-                break;
477
-            case EE_System::req_type_downgrade:
478
-                do_action('AHEE__EE_System__detect_if_activation_or_upgrade__downgrade');
479
-                // its possible migrations are no longer required
480
-                $this->maintenance_mode->set_maintenance_mode_if_db_old();
481
-                $this->_handle_core_version_change($espresso_db_update);
482
-                break;
483
-            case EE_System::req_type_normal:
484
-            default:
485
-                break;
486
-        }
487
-        do_action('AHEE__EE_System__detect_if_activation_or_upgrade__complete');
488
-    }
489
-
490
-
491
-    /**
492
-     * Updates the list of installed versions and sets hooks for
493
-     * initializing the database later during the request
494
-     *
495
-     * @param array $espresso_db_update
496
-     */
497
-    private function _handle_core_version_change($espresso_db_update)
498
-    {
499
-        $this->update_list_of_installed_versions($espresso_db_update);
500
-        // get ready to verify the DB is ok (provided we aren't in maintenance mode, of course)
501
-        add_action(
502
-            'AHEE__EE_System__perform_activations_upgrades_and_migrations',
503
-            array($this, 'initialize_db_if_no_migrations_required')
504
-        );
505
-    }
506
-
507
-
508
-    /**
509
-     * standardizes the wp option 'espresso_db_upgrade' which actually stores
510
-     * information about what versions of EE have been installed and activated,
511
-     * NOT necessarily the state of the database
512
-     *
513
-     * @param mixed $espresso_db_update           the value of the WordPress option.
514
-     *                                            If not supplied, fetches it from the options table
515
-     * @return array the correct value of 'espresso_db_upgrade', after saving it, if it needed correction
516
-     */
517
-    private function fix_espresso_db_upgrade_option($espresso_db_update = null)
518
-    {
519
-        do_action('FHEE__EE_System__manage_fix_espresso_db_upgrade_option__begin', $espresso_db_update);
520
-        if (! $espresso_db_update) {
521
-            $espresso_db_update = get_option('espresso_db_update');
522
-        }
523
-        // check that option is an array
524
-        if (! is_array($espresso_db_update)) {
525
-            // if option is FALSE, then it never existed
526
-            if ($espresso_db_update === false) {
527
-                // make $espresso_db_update an array and save option with autoload OFF
528
-                $espresso_db_update = array();
529
-                add_option('espresso_db_update', $espresso_db_update, '', 'no');
530
-            } else {
531
-                // option is NOT FALSE but also is NOT an array, so make it an array and save it
532
-                $espresso_db_update = array($espresso_db_update => array());
533
-                update_option('espresso_db_update', $espresso_db_update);
534
-            }
535
-        } else {
536
-            $corrected_db_update = array();
537
-            // if IS an array, but is it an array where KEYS are version numbers, and values are arrays?
538
-            foreach ($espresso_db_update as $should_be_version_string => $should_be_array) {
539
-                if (is_int($should_be_version_string) && ! is_array($should_be_array)) {
540
-                    // the key is an int, and the value IS NOT an array
541
-                    // so it must be numerically-indexed, where values are versions installed...
542
-                    // fix it!
543
-                    $version_string = $should_be_array;
544
-                    $corrected_db_update[ $version_string ] = array('unknown-date');
545
-                } else {
546
-                    // ok it checks out
547
-                    $corrected_db_update[ $should_be_version_string ] = $should_be_array;
548
-                }
549
-            }
550
-            $espresso_db_update = $corrected_db_update;
551
-            update_option('espresso_db_update', $espresso_db_update);
552
-        }
553
-        do_action('FHEE__EE_System__manage_fix_espresso_db_upgrade_option__complete', $espresso_db_update);
554
-        return $espresso_db_update;
555
-    }
556
-
557
-
558
-    /**
559
-     * Does the traditional work of setting up the plugin's database and adding default data.
560
-     * If migration script/process did not exist, this is what would happen on every activation/reactivation/upgrade.
561
-     * NOTE: if we're in maintenance mode (which would be the case if we detect there are data
562
-     * migration scripts that need to be run and a version change happens), enqueues core for database initialization,
563
-     * so that it will be done when migrations are finished
564
-     *
565
-     * @param boolean $initialize_addons_too if true, we double-check addons' database tables etc too;
566
-     * @param boolean $verify_schema         if true will re-check the database tables have the correct schema.
567
-     *                                       This is a resource-intensive job
568
-     *                                       so we prefer to only do it when necessary
569
-     * @return void
570
-     * @throws EE_Error
571
-     */
572
-    public function initialize_db_if_no_migrations_required($initialize_addons_too = false, $verify_schema = true)
573
-    {
574
-        $request_type = $this->detect_req_type();
575
-        // only initialize system if we're not in maintenance mode.
576
-        if ($this->maintenance_mode->level() !== EE_Maintenance_Mode::level_2_complete_maintenance) {
577
-            /** @var EventEspresso\core\domain\services\custom_post_types\RewriteRules $rewrite_rules */
578
-            $rewrite_rules = $this->loader->getShared(
579
-                'EventEspresso\core\domain\services\custom_post_types\RewriteRules'
580
-            );
581
-            $rewrite_rules->flush();
582
-            if ($verify_schema) {
583
-                EEH_Activation::initialize_db_and_folders();
584
-            }
585
-            EEH_Activation::initialize_db_content();
586
-            EEH_Activation::system_initialization();
587
-            if ($initialize_addons_too) {
588
-                $this->initialize_addons();
589
-            }
590
-        } else {
591
-            EE_Data_Migration_Manager::instance()->enqueue_db_initialization_for('Core');
592
-        }
593
-        if (
594
-            $request_type === EE_System::req_type_new_activation
595
-            || $request_type === EE_System::req_type_reactivation
596
-            || (
597
-                $request_type === EE_System::req_type_upgrade
598
-                && $this->is_major_version_change()
599
-            )
600
-        ) {
601
-            add_action('AHEE__EE_System__initialize_last', array($this, 'redirect_to_about_ee'), 9);
602
-        }
603
-    }
604
-
605
-
606
-    /**
607
-     * Initializes the db for all registered addons
608
-     *
609
-     * @throws EE_Error
610
-     */
611
-    public function initialize_addons()
612
-    {
613
-        // foreach registered addon, make sure its db is up-to-date too
614
-        foreach ($this->registry->addons as $addon) {
615
-            if ($addon instanceof EE_Addon) {
616
-                $addon->initialize_db_if_no_migrations_required();
617
-            }
618
-        }
619
-    }
620
-
621
-
622
-    /**
623
-     * Adds the current code version to the saved wp option which stores a list of all ee versions ever installed.
624
-     *
625
-     * @param    array  $version_history
626
-     * @param    string $current_version_to_add version to be added to the version history
627
-     * @return    boolean success as to whether or not this option was changed
628
-     */
629
-    public function update_list_of_installed_versions($version_history = null, $current_version_to_add = null)
630
-    {
631
-        if (! $version_history) {
632
-            $version_history = $this->fix_espresso_db_upgrade_option($version_history);
633
-        }
634
-        if ($current_version_to_add === null) {
635
-            $current_version_to_add = espresso_version();
636
-        }
637
-        $version_history[ $current_version_to_add ][] = date('Y-m-d H:i:s', time());
638
-        // re-save
639
-        return update_option('espresso_db_update', $version_history);
640
-    }
641
-
642
-
643
-    /**
644
-     * Detects if the current version indicated in the has existed in the list of
645
-     * previously-installed versions of EE (espresso_db_update). Does NOT modify it (ie, no side-effect)
646
-     *
647
-     * @param array $espresso_db_update array from the wp option stored under the name 'espresso_db_update'.
648
-     *                                  If not supplied, fetches it from the options table.
649
-     *                                  Also, caches its result so later parts of the code can also know whether
650
-     *                                  there's been an update or not. This way we can add the current version to
651
-     *                                  espresso_db_update, but still know if this is a new install or not
652
-     * @return int one of the constants on EE_System::req_type_
653
-     */
654
-    public function detect_req_type($espresso_db_update = null)
655
-    {
656
-        if ($this->_req_type === null) {
657
-            $espresso_db_update = ! empty($espresso_db_update)
658
-                ? $espresso_db_update
659
-                : $this->fix_espresso_db_upgrade_option();
660
-            $this->_req_type = EE_System::detect_req_type_given_activation_history(
661
-                $espresso_db_update,
662
-                'ee_espresso_activation',
663
-                espresso_version()
664
-            );
665
-            $this->_major_version_change = $this->_detect_major_version_change($espresso_db_update);
666
-            $this->request->setIsActivation($this->_req_type !== EE_System::req_type_normal);
667
-        }
668
-        return $this->_req_type;
669
-    }
670
-
671
-
672
-    /**
673
-     * Returns whether or not there was a non-micro version change (ie, change in either
674
-     * the first or second number in the version. Eg 4.9.0.rc.001 to 4.10.0.rc.000,
675
-     * but not 4.9.0.rc.0001 to 4.9.1.rc.0001
676
-     *
677
-     * @param $activation_history
678
-     * @return bool
679
-     */
680
-    private function _detect_major_version_change($activation_history)
681
-    {
682
-        $previous_version = EE_System::_get_most_recently_active_version_from_activation_history($activation_history);
683
-        $previous_version_parts = explode('.', $previous_version);
684
-        $current_version_parts = explode('.', espresso_version());
685
-        return isset($previous_version_parts[0], $previous_version_parts[1], $current_version_parts[0], $current_version_parts[1])
686
-               && ($previous_version_parts[0] !== $current_version_parts[0]
687
-                   || $previous_version_parts[1] !== $current_version_parts[1]
688
-               );
689
-    }
690
-
691
-
692
-    /**
693
-     * Returns true if either the major or minor version of EE changed during this request.
694
-     * Eg 4.9.0.rc.001 to 4.10.0.rc.000, but not 4.9.0.rc.0001 to 4.9.1.rc.0001
695
-     *
696
-     * @return bool
697
-     */
698
-    public function is_major_version_change()
699
-    {
700
-        return $this->_major_version_change;
701
-    }
702
-
703
-
704
-    /**
705
-     * Determines the request type for any ee addon, given three piece of info: the current array of activation
706
-     * histories (for core that' 'espresso_db_update' wp option); the name of the WordPress option which is temporarily
707
-     * set upon activation of the plugin (for core it's 'ee_espresso_activation'); and the version that this plugin was
708
-     * just activated to (for core that will always be espresso_version())
709
-     *
710
-     * @param array  $activation_history_for_addon     the option's value which stores the activation history for this
711
-     *                                                 ee plugin. for core that's 'espresso_db_update'
712
-     * @param string $activation_indicator_option_name the name of the WordPress option that is temporarily set to
713
-     *                                                 indicate that this plugin was just activated
714
-     * @param string $version_to_upgrade_to            the version that was just upgraded to (for core that will be
715
-     *                                                 espresso_version())
716
-     * @return int one of the constants on EE_System::req_type_*
717
-     */
718
-    public static function detect_req_type_given_activation_history(
719
-        $activation_history_for_addon,
720
-        $activation_indicator_option_name,
721
-        $version_to_upgrade_to
722
-    ) {
723
-        $version_is_higher = self::_new_version_is_higher($activation_history_for_addon, $version_to_upgrade_to);
724
-        if ($activation_history_for_addon) {
725
-            // it exists, so this isn't a completely new install
726
-            // check if this version already in that list of previously installed versions
727
-            if (! isset($activation_history_for_addon[ $version_to_upgrade_to ])) {
728
-                // it a version we haven't seen before
729
-                if ($version_is_higher === 1) {
730
-                    $req_type = EE_System::req_type_upgrade;
731
-                } else {
732
-                    $req_type = EE_System::req_type_downgrade;
733
-                }
734
-                delete_option($activation_indicator_option_name);
735
-            } else {
736
-                // its not an update. maybe a reactivation?
737
-                if (get_option($activation_indicator_option_name, false)) {
738
-                    if ($version_is_higher === -1) {
739
-                        $req_type = EE_System::req_type_downgrade;
740
-                    } elseif ($version_is_higher === 0) {
741
-                        // we've seen this version before, but it's an activation. must be a reactivation
742
-                        $req_type = EE_System::req_type_reactivation;
743
-                    } else {// $version_is_higher === 1
744
-                        $req_type = EE_System::req_type_upgrade;
745
-                    }
746
-                    delete_option($activation_indicator_option_name);
747
-                } else {
748
-                    // we've seen this version before and the activation indicate doesn't show it was just activated
749
-                    if ($version_is_higher === -1) {
750
-                        $req_type = EE_System::req_type_downgrade;
751
-                    } elseif ($version_is_higher === 0) {
752
-                        // we've seen this version before and it's not an activation. its normal request
753
-                        $req_type = EE_System::req_type_normal;
754
-                    } else {// $version_is_higher === 1
755
-                        $req_type = EE_System::req_type_upgrade;
756
-                    }
757
-                }
758
-            }
759
-        } else {
760
-            // brand new install
761
-            $req_type = EE_System::req_type_new_activation;
762
-            delete_option($activation_indicator_option_name);
763
-        }
764
-        return $req_type;
765
-    }
766
-
767
-
768
-    /**
769
-     * Detects if the $version_to_upgrade_to is higher than the most recent version in
770
-     * the $activation_history_for_addon
771
-     *
772
-     * @param array  $activation_history_for_addon (keys are versions, values are arrays of times activated,
773
-     *                                             sometimes containing 'unknown-date'
774
-     * @param string $version_to_upgrade_to        (current version)
775
-     * @return int results of version_compare( $version_to_upgrade_to, $most_recently_active_version ).
776
-     *                                             ie, -1 if $version_to_upgrade_to is LOWER (downgrade);
777
-     *                                             0 if $version_to_upgrade_to MATCHES (reactivation or normal request);
778
-     *                                             1 if $version_to_upgrade_to is HIGHER (upgrade) ;
779
-     */
780
-    private static function _new_version_is_higher($activation_history_for_addon, $version_to_upgrade_to)
781
-    {
782
-        // find the most recently-activated version
783
-        $most_recently_active_version =
784
-            EE_System::_get_most_recently_active_version_from_activation_history($activation_history_for_addon);
785
-        return version_compare($version_to_upgrade_to, $most_recently_active_version);
786
-    }
787
-
788
-
789
-    /**
790
-     * Gets the most recently active version listed in the activation history,
791
-     * and if none are found (ie, it's a brand new install) returns '0.0.0.dev.000'.
792
-     *
793
-     * @param array $activation_history  (keys are versions, values are arrays of times activated,
794
-     *                                   sometimes containing 'unknown-date'
795
-     * @return string
796
-     */
797
-    private static function _get_most_recently_active_version_from_activation_history($activation_history)
798
-    {
799
-        $most_recently_active_version_activation = '1970-01-01 00:00:00';
800
-        $most_recently_active_version = '0.0.0.dev.000';
801
-        if (is_array($activation_history)) {
802
-            foreach ($activation_history as $version => $times_activated) {
803
-                // check there is a record of when this version was activated. Otherwise,
804
-                // mark it as unknown
805
-                if (! $times_activated) {
806
-                    $times_activated = array('unknown-date');
807
-                }
808
-                if (is_string($times_activated)) {
809
-                    $times_activated = array($times_activated);
810
-                }
811
-                foreach ($times_activated as $an_activation) {
812
-                    if (
813
-                        $an_activation !== 'unknown-date'
814
-                        && $an_activation
815
-                           > $most_recently_active_version_activation
816
-                    ) {
817
-                        $most_recently_active_version = $version;
818
-                        $most_recently_active_version_activation = $an_activation === 'unknown-date'
819
-                            ? '1970-01-01 00:00:00'
820
-                            : $an_activation;
821
-                    }
822
-                }
823
-            }
824
-        }
825
-        return $most_recently_active_version;
826
-    }
827
-
828
-
829
-    /**
830
-     * This redirects to the about EE page after activation
831
-     *
832
-     * @return void
833
-     */
834
-    public function redirect_to_about_ee()
835
-    {
836
-        $notices = EE_Error::get_notices(false);
837
-        // if current user is an admin and it's not an ajax or rest request
838
-        if (
839
-            ! isset($notices['errors'])
840
-            && $this->request->isAdmin()
841
-            && apply_filters(
842
-                'FHEE__EE_System__redirect_to_about_ee__do_redirect',
843
-                $this->capabilities->current_user_can('manage_options', 'espresso_about_default')
844
-            )
845
-        ) {
846
-            $query_params = array('page' => 'espresso_about');
847
-            if (EE_System::instance()->detect_req_type() === EE_System::req_type_new_activation) {
848
-                $query_params['new_activation'] = true;
849
-            }
850
-            if (EE_System::instance()->detect_req_type() === EE_System::req_type_reactivation) {
851
-                $query_params['reactivation'] = true;
852
-            }
853
-            $url = add_query_arg($query_params, admin_url('admin.php'));
854
-            wp_safe_redirect($url);
855
-            exit();
856
-        }
857
-    }
858
-
859
-
860
-    /**
861
-     * load_core_configuration
862
-     * this is hooked into 'AHEE__EE_Bootstrap__load_core_configuration'
863
-     * which runs during the WP 'plugins_loaded' action at priority 5
864
-     *
865
-     * @return void
866
-     * @throws ReflectionException
867
-     * @throws Exception
868
-     */
869
-    public function load_core_configuration()
870
-    {
871
-        do_action('AHEE__EE_System__load_core_configuration__begin', $this);
872
-        $this->loader->getShared('EE_Load_Textdomain');
873
-        // load textdomain
874
-        EE_Load_Textdomain::load_textdomain();
875
-        // load caf stuff a chance to play during the activation process too.
876
-        $this->_maybe_brew_regular();
877
-        // load and setup EE_Config and EE_Network_Config
878
-        $config = $this->loader->getShared('EE_Config');
879
-        $this->loader->getShared('EE_Network_Config');
880
-        // setup autoloaders
881
-        // enable logging?
882
-        if ($config->admin->use_remote_logging) {
883
-            $this->loader->getShared('EE_Log');
884
-        }
885
-        // check for activation errors
886
-        $activation_errors = get_option('ee_plugin_activation_errors', false);
887
-        if ($activation_errors) {
888
-            EE_Error::add_error($activation_errors, __FILE__, __FUNCTION__, __LINE__);
889
-            update_option('ee_plugin_activation_errors', false);
890
-        }
891
-        // get model names
892
-        $this->_parse_model_names();
893
-        // configure custom post type definitions
894
-        $this->loader->getShared('EventEspresso\core\domain\entities\custom_post_types\CustomTaxonomyDefinitions');
895
-        $this->loader->getShared('EventEspresso\core\domain\entities\custom_post_types\CustomPostTypeDefinitions');
896
-        do_action('AHEE__EE_System__load_core_configuration__complete', $this);
897
-    }
898
-
899
-
900
-    /**
901
-     * cycles through all of the models/*.model.php files, and assembles an array of model names
902
-     *
903
-     * @return void
904
-     * @throws ReflectionException
905
-     */
906
-    private function _parse_model_names()
907
-    {
908
-        // get all the files in the EE_MODELS folder that end in .model.php
909
-        $models = glob(EE_MODELS . '*.model.php');
910
-        $model_names = array();
911
-        $non_abstract_db_models = array();
912
-        foreach ($models as $model) {
913
-            // get model classname
914
-            $classname = EEH_File::get_classname_from_filepath_with_standard_filename($model);
915
-            $short_name = str_replace('EEM_', '', $classname);
916
-            $reflectionClass = new ReflectionClass($classname);
917
-            if ($reflectionClass->isSubclassOf('EEM_Base') && ! $reflectionClass->isAbstract()) {
918
-                $non_abstract_db_models[ $short_name ] = $classname;
919
-            }
920
-            $model_names[ $short_name ] = $classname;
921
-        }
922
-        $this->registry->models = apply_filters('FHEE__EE_System__parse_model_names', $model_names);
923
-        $this->registry->non_abstract_db_models = apply_filters(
924
-            'FHEE__EE_System__parse_implemented_model_names',
925
-            $non_abstract_db_models
926
-        );
927
-    }
928
-
929
-
930
-    /**
931
-     * The purpose of this method is to simply check for a file named "caffeinated/brewing_regular.php" for any hooks
932
-     * that need to be setup before our EE_System launches.
933
-     *
934
-     * @return void
935
-     * @throws DomainException
936
-     * @throws InvalidArgumentException
937
-     * @throws InvalidDataTypeException
938
-     * @throws InvalidInterfaceException
939
-     * @throws InvalidClassException
940
-     * @throws InvalidFilePathException
941
-     */
942
-    private function _maybe_brew_regular()
943
-    {
944
-        /** @var Domain $domain */
945
-        $domain = DomainFactory::getShared(
946
-            new FullyQualifiedName(
947
-                'EventEspresso\core\domain\Domain'
948
-            ),
949
-            array(
950
-                new FilePath(EVENT_ESPRESSO_MAIN_FILE),
951
-                Version::fromString(espresso_version()),
952
-            )
953
-        );
954
-        if ($domain->isCaffeinated()) {
955
-            require_once EE_CAFF_PATH . 'brewing_regular.php';
956
-        }
957
-    }
958
-
959
-
960
-    /**
961
-     * @since 4.9.71.p
962
-     * @throws Exception
963
-     */
964
-    public function loadRouteMatchSpecifications()
965
-    {
966
-        try {
967
-            $this->loader->getShared(
968
-                'EventEspresso\core\services\route_match\RouteMatchSpecificationManager'
969
-            );
970
-        } catch (Exception $exception) {
971
-            new ExceptionStackTraceDisplay($exception);
972
-        }
973
-        do_action('AHEE__EE_System__loadRouteMatchSpecifications');
974
-    }
975
-
976
-
977
-    /**
978
-     * loading CPT related classes earlier so that their definitions are available
979
-     * but not performing any actual registration with WP core until load_CPTs_and_session() is called
980
-     *
981
-     * @since   4.10.21.p
982
-     */
983
-    public function loadCustomPostTypes()
984
-    {
985
-        $this->register_custom_taxonomies = $this->loader->getShared(
986
-            'EventEspresso\core\domain\services\custom_post_types\RegisterCustomTaxonomies'
987
-        );
988
-        $this->register_custom_post_types = $this->loader->getShared(
989
-            'EventEspresso\core\domain\services\custom_post_types\RegisterCustomPostTypes'
990
-        );
991
-        $this->register_custom_taxonomy_terms = $this->loader->getShared(
992
-            'EventEspresso\core\domain\services\custom_post_types\RegisterCustomTaxonomyTerms'
993
-        );
994
-        // integrate WP_Query with the EE models
995
-        $this->loader->getShared('EE_CPT_Strategy');
996
-        // load legacy EE_Request_Handler in case add-ons still need it
997
-        $this->loader->getShared('EE_Request_Handler');
998
-    }
999
-
1000
-
1001
-    /**
1002
-     * register_shortcodes_modules_and_widgets
1003
-     * generate lists of shortcodes and modules, then verify paths and classes
1004
-     * This is hooked into 'AHEE__EE_Bootstrap__register_shortcodes_modules_and_widgets'
1005
-     * which runs during the WP 'plugins_loaded' action at priority 7
1006
-     *
1007
-     * @access public
1008
-     * @return void
1009
-     * @throws Exception
1010
-     */
1011
-    public function register_shortcodes_modules_and_widgets()
1012
-    {
1013
-        if ($this->request->isFrontend() || $this->request->isIframe() || $this->request->isAjax()) {
1014
-            // load, register, and add shortcodes the new way
1015
-            $this->loader->getShared('EventEspresso\core\services\shortcodes\ShortcodesManager');
1016
-        }
1017
-        do_action('AHEE__EE_System__register_shortcodes_modules_and_widgets');
1018
-        // check for addons using old hook point
1019
-        if (has_action('AHEE__EE_System__register_shortcodes_modules_and_addons')) {
1020
-            $this->_incompatible_addon_error();
1021
-        }
1022
-    }
1023
-
1024
-
1025
-    /**
1026
-     * _incompatible_addon_error
1027
-     *
1028
-     * @access public
1029
-     * @return void
1030
-     */
1031
-    private function _incompatible_addon_error()
1032
-    {
1033
-        // get array of classes hooking into here
1034
-        $class_names = EEH_Class_Tools::get_class_names_for_all_callbacks_on_hook(
1035
-            'AHEE__EE_System__register_shortcodes_modules_and_addons'
1036
-        );
1037
-        if (! empty($class_names)) {
1038
-            $msg = esc_html__(
1039
-                'The following plugins, addons, or modules appear to be incompatible with this version of Event Espresso and were automatically deactivated to avoid fatal errors:',
1040
-                'event_espresso'
1041
-            );
1042
-            $msg .= '<ul>';
1043
-            foreach ($class_names as $class_name) {
1044
-                $msg .= '<li><b>Event Espresso - '
1045
-                        . str_replace(
1046
-                            array('EE_', 'EEM_', 'EED_', 'EES_', 'EEW_'),
1047
-                            '',
1048
-                            $class_name
1049
-                        ) . '</b></li>';
1050
-            }
1051
-            $msg .= '</ul>';
1052
-            $msg .= esc_html__(
1053
-                'Compatibility issues can be avoided and/or resolved by keeping addons and plugins updated to the latest version.',
1054
-                'event_espresso'
1055
-            );
1056
-            // save list of incompatible addons to wp-options for later use
1057
-            add_option('ee_incompatible_addons', $class_names, '', 'no');
1058
-            if (is_admin()) {
1059
-                EE_Error::add_error($msg, __FILE__, __FUNCTION__, __LINE__);
1060
-            }
1061
-        }
1062
-    }
1063
-
1064
-
1065
-    /**
1066
-     * brew_espresso
1067
-     * begins the process of setting hooks for initializing EE in the correct order
1068
-     * This is happening on the 'AHEE__EE_Bootstrap__brew_espresso' hook point
1069
-     * which runs during the WP 'plugins_loaded' action at priority 9
1070
-     *
1071
-     * @return void
1072
-     */
1073
-    public function brew_espresso()
1074
-    {
1075
-        do_action('AHEE__EE_System__brew_espresso__begin', $this);
1076
-        // load some final core systems
1077
-        add_action('init', array($this, 'set_hooks_for_core'), 1);
1078
-        add_action('init', array($this, 'perform_activations_upgrades_and_migrations'), 3);
1079
-        add_action('init', array($this, 'load_CPTs_and_session'), 5);
1080
-        add_action('init', array($this, 'load_controllers'), 7);
1081
-        add_action('init', array($this, 'core_loaded_and_ready'), 9);
1082
-        add_action('init', array($this, 'initialize'), 10);
1083
-        add_action('init', array($this, 'initialize_last'), 100);
1084
-        if (is_admin() && apply_filters('FHEE__EE_System__brew_espresso__load_pue', true)) {
1085
-            // pew pew pew
1086
-            $this->loader->getShared('EventEspresso\core\services\licensing\LicenseService');
1087
-            do_action('AHEE__EE_System__brew_espresso__after_pue_init');
1088
-        }
1089
-        do_action('AHEE__EE_System__brew_espresso__complete', $this);
1090
-    }
1091
-
1092
-
1093
-    /**
1094
-     *    set_hooks_for_core
1095
-     *
1096
-     * @access public
1097
-     * @return    void
1098
-     * @throws EE_Error
1099
-     */
1100
-    public function set_hooks_for_core()
1101
-    {
1102
-        $this->_deactivate_incompatible_addons();
1103
-        do_action('AHEE__EE_System__set_hooks_for_core');
1104
-        $this->loader->getShared('EventEspresso\core\domain\values\session\SessionLifespan');
1105
-        // caps need to be initialized on every request so that capability maps are set.
1106
-        // @see https://events.codebasehq.com/projects/event-espresso/tickets/8674
1107
-        $this->registry->CAP->init_caps();
1108
-    }
1109
-
1110
-
1111
-    /**
1112
-     * Using the information gathered in EE_System::_incompatible_addon_error,
1113
-     * deactivates any addons considered incompatible with the current version of EE
1114
-     */
1115
-    private function _deactivate_incompatible_addons()
1116
-    {
1117
-        $incompatible_addons = get_option('ee_incompatible_addons', array());
1118
-        if (! empty($incompatible_addons)) {
1119
-            $active_plugins = get_option('active_plugins', array());
1120
-            foreach ($active_plugins as $active_plugin) {
1121
-                foreach ($incompatible_addons as $incompatible_addon) {
1122
-                    if (strpos($active_plugin, $incompatible_addon) !== false) {
1123
-                        $this->request->unSetRequestParams(['activate'], true);
1124
-                        espresso_deactivate_plugin($active_plugin);
1125
-                    }
1126
-                }
1127
-            }
1128
-        }
1129
-    }
1130
-
1131
-
1132
-    /**
1133
-     *    perform_activations_upgrades_and_migrations
1134
-     *
1135
-     * @access public
1136
-     * @return    void
1137
-     */
1138
-    public function perform_activations_upgrades_and_migrations()
1139
-    {
1140
-        do_action('AHEE__EE_System__perform_activations_upgrades_and_migrations');
1141
-    }
1142
-
1143
-
1144
-    /**
1145
-     * @return void
1146
-     * @throws DomainException
1147
-     */
1148
-    public function load_CPTs_and_session()
1149
-    {
1150
-        do_action('AHEE__EE_System__load_CPTs_and_session__start');
1151
-        $this->register_custom_taxonomies->registerCustomTaxonomies();
1152
-        $this->register_custom_post_types->registerCustomPostTypes();
1153
-        $this->register_custom_taxonomy_terms->registerCustomTaxonomyTerms();
1154
-        // load legacy Custom Post Types and Taxonomies
1155
-        $this->loader->getShared('EE_Register_CPTs');
1156
-        do_action('AHEE__EE_System__load_CPTs_and_session__complete');
1157
-    }
1158
-
1159
-
1160
-    /**
1161
-     * load_controllers
1162
-     * this is the best place to load any additional controllers that needs access to EE core.
1163
-     * it is expected that all basic core EE systems, that are not dependant on the current request are loaded at this
1164
-     * time
1165
-     *
1166
-     * @access public
1167
-     * @return void
1168
-     */
1169
-    public function load_controllers()
1170
-    {
1171
-        do_action('AHEE__EE_System__load_controllers__start');
1172
-        // let's get it started
1173
-        if (
1174
-            ! $this->maintenance_mode->level()
1175
-            && ($this->request->isFrontend() || $this->request->isFrontAjax())
1176
-        ) {
1177
-            do_action('AHEE__EE_System__load_controllers__load_front_controllers');
1178
-            $this->loader->getShared('EE_Front_Controller');
1179
-        } elseif ($this->request->isAdmin() || $this->request->isAdminAjax()) {
1180
-            do_action('AHEE__EE_System__load_controllers__load_admin_controllers');
1181
-            $this->loader->getShared('EE_Admin');
1182
-        } elseif ($this->request->isWordPressHeartbeat()) {
1183
-            $this->loader->getShared('EventEspresso\core\domain\services\admin\ajax\WordpressHeartbeat');
1184
-        }
1185
-        do_action('AHEE__EE_System__load_controllers__complete');
1186
-    }
1187
-
1188
-
1189
-    /**
1190
-     * core_loaded_and_ready
1191
-     * all of the basic EE core should be loaded at this point and available regardless of M-Mode
1192
-     *
1193
-     * @access public
1194
-     * @return void
1195
-     * @throws Exception
1196
-     */
1197
-    public function core_loaded_and_ready()
1198
-    {
1199
-        if (
1200
-            $this->request->isAdmin()
1201
-            || $this->request->isFrontend()
1202
-            || $this->request->isIframe()
1203
-            || $this->request->isWordPressApi()
1204
-        ) {
1205
-            try {
1206
-                $this->loader->getShared('EventEspresso\core\services\assets\Registry');
1207
-                $this->loader->getShared('EventEspresso\core\domain\services\assets\CoreAssetManager');
1208
-                if ($this->canLoadBlocks()) {
1209
-                    $this->loader->getShared(
1210
-                        'EventEspresso\core\services\editor\BlockRegistrationManager'
1211
-                    );
1212
-                }
1213
-            } catch (Exception $exception) {
1214
-                new ExceptionStackTraceDisplay($exception);
1215
-            }
1216
-        }
1217
-        if (
1218
-            $this->request->isAdmin()
1219
-            || $this->request->isEeAjax()
1220
-            || $this->request->isFrontend()
1221
-        ) {
1222
-            $this->loader->getShared('EE_Session');
1223
-        }
1224
-        do_action('AHEE__EE_System__core_loaded_and_ready');
1225
-        // always load template tags, because it's faster than checking if it's a front-end request, and many page
1226
-        // builders require these even on the front-end
1227
-        require_once EE_PUBLIC . 'template_tags.php';
1228
-        do_action('AHEE__EE_System__set_hooks_for_shortcodes_modules_and_addons');
1229
-    }
1230
-
1231
-
1232
-    /**
1233
-     * initialize
1234
-     * this is the best place to begin initializing client code
1235
-     *
1236
-     * @access public
1237
-     * @return void
1238
-     */
1239
-    public function initialize()
1240
-    {
1241
-        do_action('AHEE__EE_System__initialize');
1242
-        add_filter(
1243
-            'safe_style_css',
1244
-            function ($styles) {
1245
-                $styles[] = 'display';
1246
-                $styles[] = 'visibility';
1247
-                $styles[] = 'position';
1248
-                $styles[] = 'top';
1249
-                $styles[] = 'right';
1250
-                $styles[] = 'bottom';
1251
-                $styles[] = 'left';
1252
-                $styles[] = 'resize';
1253
-                $styles[] = 'max-width';
1254
-                $styles[] = 'max-height';
1255
-                return $styles;
1256
-            }
1257
-        );
1258
-    }
1259
-
1260
-
1261
-    /**
1262
-     * initialize_last
1263
-     * this is run really late during the WP init hook point, and ensures that mostly everything else that needs to
1264
-     * initialize has done so
1265
-     *
1266
-     * @access public
1267
-     * @return void
1268
-     */
1269
-    public function initialize_last()
1270
-    {
1271
-        do_action('AHEE__EE_System__initialize_last');
1272
-        /** @var EventEspresso\core\domain\services\custom_post_types\RewriteRules $rewrite_rules */
1273
-        $rewrite_rules = $this->loader->getShared(
1274
-            'EventEspresso\core\domain\services\custom_post_types\RewriteRules'
1275
-        );
1276
-        $rewrite_rules->flushRewriteRules();
1277
-        add_action('admin_bar_init', array($this, 'addEspressoToolbar'));
1278
-        if (
1279
-            ($this->request->isAjax() || $this->request->isAdmin())
1280
-            && $this->maintenance_mode->models_can_query()
1281
-        ) {
1282
-            $this->loader->getShared('EventEspresso\core\services\privacy\export\PersonalDataExporterManager');
1283
-            $this->loader->getShared('EventEspresso\core\services\privacy\erasure\PersonalDataEraserManager');
1284
-        }
1285
-    }
1286
-
1287
-
1288
-    /**
1289
-     * @return void
1290
-     * @throws EE_Error
1291
-     */
1292
-    public function addEspressoToolbar()
1293
-    {
1294
-        $this->loader->getShared(
1295
-            'EventEspresso\core\domain\services\admin\AdminToolBar',
1296
-            array($this->registry->CAP)
1297
-        );
1298
-    }
1299
-
1300
-
1301
-    /**
1302
-     * do_not_cache
1303
-     * sets no cache headers and defines no cache constants for WP plugins
1304
-     *
1305
-     * @access public
1306
-     * @return void
1307
-     */
1308
-    public static function do_not_cache()
1309
-    {
1310
-        // set no cache constants
1311
-        if (! defined('DONOTCACHEPAGE')) {
1312
-            define('DONOTCACHEPAGE', true);
1313
-        }
1314
-        if (! defined('DONOTCACHCEOBJECT')) {
1315
-            define('DONOTCACHCEOBJECT', true);
1316
-        }
1317
-        if (! defined('DONOTCACHEDB')) {
1318
-            define('DONOTCACHEDB', true);
1319
-        }
1320
-        // add no cache headers
1321
-        add_action('send_headers', array('EE_System', 'nocache_headers'), 10);
1322
-        // plus a little extra for nginx and Google Chrome
1323
-        add_filter('nocache_headers', array('EE_System', 'extra_nocache_headers'), 10, 1);
1324
-        // prevent browsers from prefetching of the rel='next' link, because it may contain content that interferes with the registration process
1325
-        remove_action('wp_head', 'adjacent_posts_rel_link_wp_head');
1326
-    }
1327
-
1328
-
1329
-    /**
1330
-     *    extra_nocache_headers
1331
-     *
1332
-     * @access    public
1333
-     * @param $headers
1334
-     * @return    array
1335
-     */
1336
-    public static function extra_nocache_headers($headers)
1337
-    {
1338
-        // for NGINX
1339
-        $headers['X-Accel-Expires'] = 0;
1340
-        // plus extra for Google Chrome since it doesn't seem to respect "no-cache", but WILL respect "no-store"
1341
-        $headers['Cache-Control'] = 'no-store, no-cache, must-revalidate, max-age=0';
1342
-        return $headers;
1343
-    }
1344
-
1345
-
1346
-    /**
1347
-     *    nocache_headers
1348
-     *
1349
-     * @access    public
1350
-     * @return    void
1351
-     */
1352
-    public static function nocache_headers()
1353
-    {
1354
-        nocache_headers();
1355
-    }
1356
-
1357
-
1358
-    /**
1359
-     * simply hooks into "wp_list_pages_exclude" filter (for wp_list_pages method) and makes sure EE critical pages are
1360
-     * never returned with the function.
1361
-     *
1362
-     * @param  array $exclude_array any existing pages being excluded are in this array.
1363
-     * @return array
1364
-     */
1365
-    public function remove_pages_from_wp_list_pages($exclude_array)
1366
-    {
1367
-        return array_merge($exclude_array, $this->registry->CFG->core->get_critical_pages_array());
1368
-    }
1369
-
1370
-
1371
-    /**
1372
-     * Return whether blocks can be registered/loaded or not.
1373
-     * @return bool
1374
-     */
1375
-    private function canLoadBlocks()
1376
-    {
1377
-        return apply_filters('FHEE__EE_System__canLoadBlocks', true)
1378
-               && function_exists('register_block_type')
1379
-               // don't load blocks if in the Divi page builder editor context
1380
-               // @see https://github.com/eventespresso/event-espresso-core/issues/814
1381
-               && ! $this->request->getRequestParam('et_fb', false);
1382
-    }
30
+	/**
31
+	 * indicates this is a 'normal' request. Ie, not activation, nor upgrade, nor activation.
32
+	 * So examples of this would be a normal GET request on the frontend or backend, or a POST, etc
33
+	 */
34
+	const req_type_normal = 0;
35
+
36
+	/**
37
+	 * Indicates this is a brand new installation of EE so we should install
38
+	 * tables and default data etc
39
+	 */
40
+	const req_type_new_activation = 1;
41
+
42
+	/**
43
+	 * we've detected that EE has been reactivated (or EE was activated during maintenance mode,
44
+	 * and we just exited maintenance mode). We MUST check the database is setup properly
45
+	 * and that default data is setup too
46
+	 */
47
+	const req_type_reactivation = 2;
48
+
49
+	/**
50
+	 * indicates that EE has been upgraded since its previous request.
51
+	 * We may have data migration scripts to call and will want to trigger maintenance mode
52
+	 */
53
+	const req_type_upgrade = 3;
54
+
55
+	/**
56
+	 * TODO  will detect that EE has been DOWNGRADED. We probably don't want to run in this case...
57
+	 */
58
+	const req_type_downgrade = 4;
59
+
60
+	/**
61
+	 * @deprecated since version 4.6.0.dev.006
62
+	 * Now whenever a new_activation is detected the request type is still just
63
+	 * new_activation (same for reactivation, upgrade, downgrade etc), but if we'r ein maintenance mode
64
+	 * EE_System::initialize_db_if_no_migrations_required and EE_Addon::initialize_db_if_no_migrations_required
65
+	 * will instead enqueue that EE plugin's db initialization for when we're taken out of maintenance mode.
66
+	 * (Specifically, when the migration manager indicates migrations are finished
67
+	 * EE_Data_Migration_Manager::initialize_db_for_enqueued_ee_plugins() will be called)
68
+	 */
69
+	const req_type_activation_but_not_installed = 5;
70
+
71
+	/**
72
+	 * option prefix for recording the activation history (like core's "espresso_db_update") of addons
73
+	 */
74
+	const addon_activation_history_option_prefix = 'ee_addon_activation_history_';
75
+
76
+	/**
77
+	 * @var EE_System $_instance
78
+	 */
79
+	private static $_instance;
80
+
81
+	/**
82
+	 * @var EE_Registry $registry
83
+	 */
84
+	private $registry;
85
+
86
+	/**
87
+	 * @var LoaderInterface $loader
88
+	 */
89
+	private $loader;
90
+
91
+	/**
92
+	 * @var EE_Capabilities $capabilities
93
+	 */
94
+	private $capabilities;
95
+
96
+	/**
97
+	 * @var RequestInterface $request
98
+	 */
99
+	private $request;
100
+
101
+	/**
102
+	 * @var EE_Maintenance_Mode $maintenance_mode
103
+	 */
104
+	private $maintenance_mode;
105
+
106
+	/**
107
+	 * Stores which type of request this is, options being one of the constants on EE_System starting with req_type_*.
108
+	 * It can be a brand-new activation, a reactivation, an upgrade, a downgrade, or a normal request.
109
+	 *
110
+	 * @var int $_req_type
111
+	 */
112
+	private $_req_type;
113
+
114
+	/**
115
+	 * Whether or not there was a non-micro version change in EE core version during this request
116
+	 *
117
+	 * @var boolean $_major_version_change
118
+	 */
119
+	private $_major_version_change = false;
120
+
121
+	/**
122
+	 * A Context DTO dedicated solely to identifying the current request type.
123
+	 *
124
+	 * @var RequestTypeContextCheckerInterface $request_type
125
+	 */
126
+	private $request_type;
127
+
128
+	/**
129
+	 * @param EventEspresso\core\domain\services\custom_post_types\RegisterCustomPostTypes
130
+	 */
131
+	private $register_custom_post_types;
132
+
133
+	/**
134
+	 * @param EventEspresso\core\domain\services\custom_post_types\RegisterCustomTaxonomies
135
+	 */
136
+	private $register_custom_taxonomies;
137
+
138
+	/**
139
+	 * @param EventEspresso\core\domain\services\custom_post_types\RegisterCustomTaxonomyTerms
140
+	 */
141
+	private $register_custom_taxonomy_terms;
142
+
143
+	/**
144
+	 * @singleton method used to instantiate class object
145
+	 * @param EE_Registry|null         $registry
146
+	 * @param LoaderInterface|null     $loader
147
+	 * @param RequestInterface|null    $request
148
+	 * @param EE_Maintenance_Mode|null $maintenance_mode
149
+	 * @return EE_System
150
+	 */
151
+	public static function instance(
152
+		EE_Registry $registry = null,
153
+		LoaderInterface $loader = null,
154
+		RequestInterface $request = null,
155
+		EE_Maintenance_Mode $maintenance_mode = null
156
+	) {
157
+		// check if class object is instantiated
158
+		if (! self::$_instance instanceof EE_System) {
159
+			self::$_instance = new self($registry, $loader, $request, $maintenance_mode);
160
+		}
161
+		return self::$_instance;
162
+	}
163
+
164
+
165
+	/**
166
+	 * resets the instance and returns it
167
+	 *
168
+	 * @return EE_System
169
+	 */
170
+	public static function reset()
171
+	{
172
+		self::$_instance->_req_type = null;
173
+		// make sure none of the old hooks are left hanging around
174
+		remove_all_actions('AHEE__EE_System__perform_activations_upgrades_and_migrations');
175
+		// we need to reset the migration manager in order for it to detect DMSs properly
176
+		EE_Data_Migration_Manager::reset();
177
+		self::instance()->detect_activations_or_upgrades();
178
+		self::instance()->perform_activations_upgrades_and_migrations();
179
+		return self::instance();
180
+	}
181
+
182
+
183
+	/**
184
+	 * sets hooks for running rest of system
185
+	 * provides "AHEE__EE_System__construct__complete" hook for EE Addons to use as their starting point
186
+	 * starting EE Addons from any other point may lead to problems
187
+	 *
188
+	 * @param EE_Registry         $registry
189
+	 * @param LoaderInterface     $loader
190
+	 * @param RequestInterface    $request
191
+	 * @param EE_Maintenance_Mode $maintenance_mode
192
+	 */
193
+	private function __construct(
194
+		EE_Registry $registry,
195
+		LoaderInterface $loader,
196
+		RequestInterface $request,
197
+		EE_Maintenance_Mode $maintenance_mode
198
+	) {
199
+		$this->registry = $registry;
200
+		$this->loader = $loader;
201
+		$this->request = $request;
202
+		$this->maintenance_mode = $maintenance_mode;
203
+		do_action('AHEE__EE_System__construct__begin', $this);
204
+		add_action(
205
+			'AHEE__EE_Bootstrap__load_espresso_addons',
206
+			array($this, 'loadCapabilities'),
207
+			5
208
+		);
209
+		add_action(
210
+			'AHEE__EE_Bootstrap__load_espresso_addons',
211
+			array($this, 'loadCommandBus'),
212
+			7
213
+		);
214
+		add_action(
215
+			'AHEE__EE_Bootstrap__load_espresso_addons',
216
+			array($this, 'loadPluginApi'),
217
+			9
218
+		);
219
+		// allow addons to load first so that they can register autoloaders, set hooks for running DMS's, etc
220
+		add_action(
221
+			'AHEE__EE_Bootstrap__load_espresso_addons',
222
+			array($this, 'load_espresso_addons')
223
+		);
224
+		// when an ee addon is activated, we want to call the core hook(s) again
225
+		// because the newly-activated addon didn't get a chance to run at all
226
+		add_action('activate_plugin', array($this, 'load_espresso_addons'), 1);
227
+		// detect whether install or upgrade
228
+		add_action(
229
+			'AHEE__EE_Bootstrap__detect_activations_or_upgrades',
230
+			array($this, 'detect_activations_or_upgrades'),
231
+			3
232
+		);
233
+		// load EE_Config, EE_Textdomain, etc
234
+		add_action(
235
+			'AHEE__EE_Bootstrap__load_core_configuration',
236
+			array($this, 'load_core_configuration'),
237
+			5
238
+		);
239
+		// load specifications for matching routes to current request
240
+		add_action(
241
+			'AHEE__EE_Bootstrap__load_core_configuration',
242
+			array($this, 'loadRouteMatchSpecifications')
243
+		);
244
+		// load specifications for custom post types
245
+		add_action(
246
+			'AHEE__EE_Bootstrap__load_core_configuration',
247
+			array($this, 'loadCustomPostTypes')
248
+		);
249
+		// load EE_Config, EE_Textdomain, etc
250
+		add_action(
251
+			'AHEE__EE_Bootstrap__register_shortcodes_modules_and_widgets',
252
+			array($this, 'register_shortcodes_modules_and_widgets'),
253
+			7
254
+		);
255
+		// you wanna get going? I wanna get going... let's get going!
256
+		add_action(
257
+			'AHEE__EE_Bootstrap__brew_espresso',
258
+			array($this, 'brew_espresso'),
259
+			9
260
+		);
261
+		// other housekeeping
262
+		// exclude EE critical pages from wp_list_pages
263
+		add_filter(
264
+			'wp_list_pages_excludes',
265
+			array($this, 'remove_pages_from_wp_list_pages'),
266
+			10
267
+		);
268
+		// ALL EE Addons should use the following hook point to attach their initial setup too
269
+		// it's extremely important for EE Addons to register any class autoloaders so that they can be available when the EE_Config loads
270
+		do_action('AHEE__EE_System__construct__complete', $this);
271
+	}
272
+
273
+
274
+	/**
275
+	 * load and setup EE_Capabilities
276
+	 *
277
+	 * @return void
278
+	 * @throws EE_Error
279
+	 */
280
+	public function loadCapabilities()
281
+	{
282
+		$this->capabilities = $this->loader->getShared('EE_Capabilities');
283
+		add_action(
284
+			'AHEE__EE_Capabilities__init_caps__before_initialization',
285
+			function () {
286
+				LoaderFactory::getLoader()->getShared('EE_Payment_Method_Manager');
287
+			}
288
+		);
289
+	}
290
+
291
+
292
+	/**
293
+	 * create and cache the CommandBus, and also add middleware
294
+	 * The CapChecker middleware requires the use of EE_Capabilities
295
+	 * which is why we need to load the CommandBus after Caps are set up
296
+	 *
297
+	 * @return void
298
+	 * @throws EE_Error
299
+	 */
300
+	public function loadCommandBus()
301
+	{
302
+		$this->loader->getShared(
303
+			'CommandBusInterface',
304
+			array(
305
+				null,
306
+				apply_filters(
307
+					'FHEE__EE_Load_Espresso_Core__handle_request__CommandBus_middleware',
308
+					array(
309
+						$this->loader->getShared('EventEspresso\core\services\commands\middleware\CapChecker'),
310
+						$this->loader->getShared('EventEspresso\core\services\commands\middleware\AddActionHook'),
311
+					)
312
+				),
313
+			)
314
+		);
315
+	}
316
+
317
+
318
+	/**
319
+	 * @return void
320
+	 * @throws EE_Error
321
+	 */
322
+	public function loadPluginApi()
323
+	{
324
+		// set autoloaders for all of the classes implementing EEI_Plugin_API
325
+		// which provide helpers for EE plugin authors to more easily register certain components with EE.
326
+		EEH_Autoloader::instance()->register_autoloaders_for_each_file_in_folder(EE_LIBRARIES . 'plugin_api');
327
+	}
328
+
329
+
330
+	/**
331
+	 * @param string $addon_name
332
+	 * @param string $version_constant
333
+	 * @param string $min_version_required
334
+	 * @param string $load_callback
335
+	 * @param string $plugin_file_constant
336
+	 * @return void
337
+	 */
338
+	private function deactivateIncompatibleAddon(
339
+		$addon_name,
340
+		$version_constant,
341
+		$min_version_required,
342
+		$load_callback,
343
+		$plugin_file_constant
344
+	) {
345
+		if (! defined($version_constant)) {
346
+			return;
347
+		}
348
+		$addon_version = constant($version_constant);
349
+		if ($addon_version && version_compare($addon_version, $min_version_required, '<')) {
350
+			remove_action('AHEE__EE_System__load_espresso_addons', $load_callback);
351
+			if (! function_exists('deactivate_plugins')) {
352
+				require_once ABSPATH . 'wp-admin/includes/plugin.php';
353
+			}
354
+			deactivate_plugins(plugin_basename(constant($plugin_file_constant)));
355
+			$this->request->unSetRequestParams(['activate', 'activate-multi'], true);
356
+			EE_Error::add_error(
357
+				sprintf(
358
+					esc_html__(
359
+						'We\'re sorry, but the Event Espresso %1$s addon was deactivated because version %2$s or higher is required with this version of Event Espresso core.',
360
+						'event_espresso'
361
+					),
362
+					$addon_name,
363
+					$min_version_required
364
+				),
365
+				__FILE__,
366
+				__FUNCTION__ . "({$addon_name})",
367
+				__LINE__
368
+			);
369
+			EE_Error::get_notices(false, true);
370
+		}
371
+	}
372
+
373
+
374
+	/**
375
+	 * load_espresso_addons
376
+	 * allow addons to load first so that they can set hooks for running DMS's, etc
377
+	 * this is hooked into both:
378
+	 *    'AHEE__EE_Bootstrap__load_core_configuration'
379
+	 *        which runs during the WP 'plugins_loaded' action at priority 5
380
+	 *    and the WP 'activate_plugin' hook point
381
+	 *
382
+	 * @access public
383
+	 * @return void
384
+	 */
385
+	public function load_espresso_addons()
386
+	{
387
+		$this->deactivateIncompatibleAddon(
388
+			'Wait Lists',
389
+			'EE_WAIT_LISTS_VERSION',
390
+			'1.0.0.beta.074',
391
+			'load_espresso_wait_lists',
392
+			'EE_WAIT_LISTS_PLUGIN_FILE'
393
+		);
394
+		$this->deactivateIncompatibleAddon(
395
+			'Automated Upcoming Event Notifications',
396
+			'EE_AUTOMATED_UPCOMING_EVENT_NOTIFICATION_VERSION',
397
+			'1.0.0.beta.091',
398
+			'load_espresso_automated_upcoming_event_notification',
399
+			'EE_AUTOMATED_UPCOMING_EVENT_NOTIFICATION_PLUGIN_FILE'
400
+		);
401
+		do_action('AHEE__EE_System__load_espresso_addons');
402
+		// if the WP API basic auth plugin isn't already loaded, load it now.
403
+		// We want it for mobile apps. Just include the entire plugin
404
+		// also, don't load the basic auth when a plugin is getting activated, because
405
+		// it could be the basic auth plugin, and it doesn't check if its methods are already defined
406
+		// and causes a fatal error
407
+		if (
408
+			($this->request->isWordPressApi() || $this->request->isApi())
409
+			&& $this->request->getRequestParam('activate') !== 'true'
410
+			&& ! function_exists('json_basic_auth_handler')
411
+			&& ! function_exists('json_basic_auth_error')
412
+			&& ! in_array(
413
+				$this->request->getRequestParam('action'),
414
+				array('activate', 'activate-selected'),
415
+				true
416
+			)
417
+		) {
418
+			include_once EE_THIRD_PARTY . 'wp-api-basic-auth/basic-auth.php';
419
+		}
420
+		do_action('AHEE__EE_System__load_espresso_addons__complete');
421
+	}
422
+
423
+
424
+	/**
425
+	 * detect_activations_or_upgrades
426
+	 * Checks for activation or upgrade of core first;
427
+	 * then also checks if any registered addons have been activated or upgraded
428
+	 * This is hooked into 'AHEE__EE_Bootstrap__detect_activations_or_upgrades'
429
+	 * which runs during the WP 'plugins_loaded' action at priority 3
430
+	 *
431
+	 * @access public
432
+	 * @return void
433
+	 */
434
+	public function detect_activations_or_upgrades()
435
+	{
436
+		// first off: let's make sure to handle core
437
+		$this->detect_if_activation_or_upgrade();
438
+		foreach ($this->registry->addons as $addon) {
439
+			if ($addon instanceof EE_Addon) {
440
+				// detect teh request type for that addon
441
+				$addon->detect_req_type();
442
+			}
443
+		}
444
+	}
445
+
446
+
447
+	/**
448
+	 * detect_if_activation_or_upgrade
449
+	 * Takes care of detecting whether this is a brand new install or code upgrade,
450
+	 * and either setting up the DB or setting up maintenance mode etc.
451
+	 *
452
+	 * @access public
453
+	 * @return void
454
+	 */
455
+	public function detect_if_activation_or_upgrade()
456
+	{
457
+		do_action('AHEE__EE_System___detect_if_activation_or_upgrade__begin');
458
+		// check if db has been updated, or if its a brand-new installation
459
+		$espresso_db_update = $this->fix_espresso_db_upgrade_option();
460
+		$request_type = $this->detect_req_type($espresso_db_update);
461
+		// EEH_Debug_Tools::printr( $request_type, '$request_type', __FILE__, __LINE__ );
462
+		switch ($request_type) {
463
+			case EE_System::req_type_new_activation:
464
+				do_action('AHEE__EE_System__detect_if_activation_or_upgrade__new_activation');
465
+				$this->_handle_core_version_change($espresso_db_update);
466
+				break;
467
+			case EE_System::req_type_reactivation:
468
+				do_action('AHEE__EE_System__detect_if_activation_or_upgrade__reactivation');
469
+				$this->_handle_core_version_change($espresso_db_update);
470
+				break;
471
+			case EE_System::req_type_upgrade:
472
+				do_action('AHEE__EE_System__detect_if_activation_or_upgrade__upgrade');
473
+				// migrations may be required now that we've upgraded
474
+				$this->maintenance_mode->set_maintenance_mode_if_db_old();
475
+				$this->_handle_core_version_change($espresso_db_update);
476
+				break;
477
+			case EE_System::req_type_downgrade:
478
+				do_action('AHEE__EE_System__detect_if_activation_or_upgrade__downgrade');
479
+				// its possible migrations are no longer required
480
+				$this->maintenance_mode->set_maintenance_mode_if_db_old();
481
+				$this->_handle_core_version_change($espresso_db_update);
482
+				break;
483
+			case EE_System::req_type_normal:
484
+			default:
485
+				break;
486
+		}
487
+		do_action('AHEE__EE_System__detect_if_activation_or_upgrade__complete');
488
+	}
489
+
490
+
491
+	/**
492
+	 * Updates the list of installed versions and sets hooks for
493
+	 * initializing the database later during the request
494
+	 *
495
+	 * @param array $espresso_db_update
496
+	 */
497
+	private function _handle_core_version_change($espresso_db_update)
498
+	{
499
+		$this->update_list_of_installed_versions($espresso_db_update);
500
+		// get ready to verify the DB is ok (provided we aren't in maintenance mode, of course)
501
+		add_action(
502
+			'AHEE__EE_System__perform_activations_upgrades_and_migrations',
503
+			array($this, 'initialize_db_if_no_migrations_required')
504
+		);
505
+	}
506
+
507
+
508
+	/**
509
+	 * standardizes the wp option 'espresso_db_upgrade' which actually stores
510
+	 * information about what versions of EE have been installed and activated,
511
+	 * NOT necessarily the state of the database
512
+	 *
513
+	 * @param mixed $espresso_db_update           the value of the WordPress option.
514
+	 *                                            If not supplied, fetches it from the options table
515
+	 * @return array the correct value of 'espresso_db_upgrade', after saving it, if it needed correction
516
+	 */
517
+	private function fix_espresso_db_upgrade_option($espresso_db_update = null)
518
+	{
519
+		do_action('FHEE__EE_System__manage_fix_espresso_db_upgrade_option__begin', $espresso_db_update);
520
+		if (! $espresso_db_update) {
521
+			$espresso_db_update = get_option('espresso_db_update');
522
+		}
523
+		// check that option is an array
524
+		if (! is_array($espresso_db_update)) {
525
+			// if option is FALSE, then it never existed
526
+			if ($espresso_db_update === false) {
527
+				// make $espresso_db_update an array and save option with autoload OFF
528
+				$espresso_db_update = array();
529
+				add_option('espresso_db_update', $espresso_db_update, '', 'no');
530
+			} else {
531
+				// option is NOT FALSE but also is NOT an array, so make it an array and save it
532
+				$espresso_db_update = array($espresso_db_update => array());
533
+				update_option('espresso_db_update', $espresso_db_update);
534
+			}
535
+		} else {
536
+			$corrected_db_update = array();
537
+			// if IS an array, but is it an array where KEYS are version numbers, and values are arrays?
538
+			foreach ($espresso_db_update as $should_be_version_string => $should_be_array) {
539
+				if (is_int($should_be_version_string) && ! is_array($should_be_array)) {
540
+					// the key is an int, and the value IS NOT an array
541
+					// so it must be numerically-indexed, where values are versions installed...
542
+					// fix it!
543
+					$version_string = $should_be_array;
544
+					$corrected_db_update[ $version_string ] = array('unknown-date');
545
+				} else {
546
+					// ok it checks out
547
+					$corrected_db_update[ $should_be_version_string ] = $should_be_array;
548
+				}
549
+			}
550
+			$espresso_db_update = $corrected_db_update;
551
+			update_option('espresso_db_update', $espresso_db_update);
552
+		}
553
+		do_action('FHEE__EE_System__manage_fix_espresso_db_upgrade_option__complete', $espresso_db_update);
554
+		return $espresso_db_update;
555
+	}
556
+
557
+
558
+	/**
559
+	 * Does the traditional work of setting up the plugin's database and adding default data.
560
+	 * If migration script/process did not exist, this is what would happen on every activation/reactivation/upgrade.
561
+	 * NOTE: if we're in maintenance mode (which would be the case if we detect there are data
562
+	 * migration scripts that need to be run and a version change happens), enqueues core for database initialization,
563
+	 * so that it will be done when migrations are finished
564
+	 *
565
+	 * @param boolean $initialize_addons_too if true, we double-check addons' database tables etc too;
566
+	 * @param boolean $verify_schema         if true will re-check the database tables have the correct schema.
567
+	 *                                       This is a resource-intensive job
568
+	 *                                       so we prefer to only do it when necessary
569
+	 * @return void
570
+	 * @throws EE_Error
571
+	 */
572
+	public function initialize_db_if_no_migrations_required($initialize_addons_too = false, $verify_schema = true)
573
+	{
574
+		$request_type = $this->detect_req_type();
575
+		// only initialize system if we're not in maintenance mode.
576
+		if ($this->maintenance_mode->level() !== EE_Maintenance_Mode::level_2_complete_maintenance) {
577
+			/** @var EventEspresso\core\domain\services\custom_post_types\RewriteRules $rewrite_rules */
578
+			$rewrite_rules = $this->loader->getShared(
579
+				'EventEspresso\core\domain\services\custom_post_types\RewriteRules'
580
+			);
581
+			$rewrite_rules->flush();
582
+			if ($verify_schema) {
583
+				EEH_Activation::initialize_db_and_folders();
584
+			}
585
+			EEH_Activation::initialize_db_content();
586
+			EEH_Activation::system_initialization();
587
+			if ($initialize_addons_too) {
588
+				$this->initialize_addons();
589
+			}
590
+		} else {
591
+			EE_Data_Migration_Manager::instance()->enqueue_db_initialization_for('Core');
592
+		}
593
+		if (
594
+			$request_type === EE_System::req_type_new_activation
595
+			|| $request_type === EE_System::req_type_reactivation
596
+			|| (
597
+				$request_type === EE_System::req_type_upgrade
598
+				&& $this->is_major_version_change()
599
+			)
600
+		) {
601
+			add_action('AHEE__EE_System__initialize_last', array($this, 'redirect_to_about_ee'), 9);
602
+		}
603
+	}
604
+
605
+
606
+	/**
607
+	 * Initializes the db for all registered addons
608
+	 *
609
+	 * @throws EE_Error
610
+	 */
611
+	public function initialize_addons()
612
+	{
613
+		// foreach registered addon, make sure its db is up-to-date too
614
+		foreach ($this->registry->addons as $addon) {
615
+			if ($addon instanceof EE_Addon) {
616
+				$addon->initialize_db_if_no_migrations_required();
617
+			}
618
+		}
619
+	}
620
+
621
+
622
+	/**
623
+	 * Adds the current code version to the saved wp option which stores a list of all ee versions ever installed.
624
+	 *
625
+	 * @param    array  $version_history
626
+	 * @param    string $current_version_to_add version to be added to the version history
627
+	 * @return    boolean success as to whether or not this option was changed
628
+	 */
629
+	public function update_list_of_installed_versions($version_history = null, $current_version_to_add = null)
630
+	{
631
+		if (! $version_history) {
632
+			$version_history = $this->fix_espresso_db_upgrade_option($version_history);
633
+		}
634
+		if ($current_version_to_add === null) {
635
+			$current_version_to_add = espresso_version();
636
+		}
637
+		$version_history[ $current_version_to_add ][] = date('Y-m-d H:i:s', time());
638
+		// re-save
639
+		return update_option('espresso_db_update', $version_history);
640
+	}
641
+
642
+
643
+	/**
644
+	 * Detects if the current version indicated in the has existed in the list of
645
+	 * previously-installed versions of EE (espresso_db_update). Does NOT modify it (ie, no side-effect)
646
+	 *
647
+	 * @param array $espresso_db_update array from the wp option stored under the name 'espresso_db_update'.
648
+	 *                                  If not supplied, fetches it from the options table.
649
+	 *                                  Also, caches its result so later parts of the code can also know whether
650
+	 *                                  there's been an update or not. This way we can add the current version to
651
+	 *                                  espresso_db_update, but still know if this is a new install or not
652
+	 * @return int one of the constants on EE_System::req_type_
653
+	 */
654
+	public function detect_req_type($espresso_db_update = null)
655
+	{
656
+		if ($this->_req_type === null) {
657
+			$espresso_db_update = ! empty($espresso_db_update)
658
+				? $espresso_db_update
659
+				: $this->fix_espresso_db_upgrade_option();
660
+			$this->_req_type = EE_System::detect_req_type_given_activation_history(
661
+				$espresso_db_update,
662
+				'ee_espresso_activation',
663
+				espresso_version()
664
+			);
665
+			$this->_major_version_change = $this->_detect_major_version_change($espresso_db_update);
666
+			$this->request->setIsActivation($this->_req_type !== EE_System::req_type_normal);
667
+		}
668
+		return $this->_req_type;
669
+	}
670
+
671
+
672
+	/**
673
+	 * Returns whether or not there was a non-micro version change (ie, change in either
674
+	 * the first or second number in the version. Eg 4.9.0.rc.001 to 4.10.0.rc.000,
675
+	 * but not 4.9.0.rc.0001 to 4.9.1.rc.0001
676
+	 *
677
+	 * @param $activation_history
678
+	 * @return bool
679
+	 */
680
+	private function _detect_major_version_change($activation_history)
681
+	{
682
+		$previous_version = EE_System::_get_most_recently_active_version_from_activation_history($activation_history);
683
+		$previous_version_parts = explode('.', $previous_version);
684
+		$current_version_parts = explode('.', espresso_version());
685
+		return isset($previous_version_parts[0], $previous_version_parts[1], $current_version_parts[0], $current_version_parts[1])
686
+			   && ($previous_version_parts[0] !== $current_version_parts[0]
687
+				   || $previous_version_parts[1] !== $current_version_parts[1]
688
+			   );
689
+	}
690
+
691
+
692
+	/**
693
+	 * Returns true if either the major or minor version of EE changed during this request.
694
+	 * Eg 4.9.0.rc.001 to 4.10.0.rc.000, but not 4.9.0.rc.0001 to 4.9.1.rc.0001
695
+	 *
696
+	 * @return bool
697
+	 */
698
+	public function is_major_version_change()
699
+	{
700
+		return $this->_major_version_change;
701
+	}
702
+
703
+
704
+	/**
705
+	 * Determines the request type for any ee addon, given three piece of info: the current array of activation
706
+	 * histories (for core that' 'espresso_db_update' wp option); the name of the WordPress option which is temporarily
707
+	 * set upon activation of the plugin (for core it's 'ee_espresso_activation'); and the version that this plugin was
708
+	 * just activated to (for core that will always be espresso_version())
709
+	 *
710
+	 * @param array  $activation_history_for_addon     the option's value which stores the activation history for this
711
+	 *                                                 ee plugin. for core that's 'espresso_db_update'
712
+	 * @param string $activation_indicator_option_name the name of the WordPress option that is temporarily set to
713
+	 *                                                 indicate that this plugin was just activated
714
+	 * @param string $version_to_upgrade_to            the version that was just upgraded to (for core that will be
715
+	 *                                                 espresso_version())
716
+	 * @return int one of the constants on EE_System::req_type_*
717
+	 */
718
+	public static function detect_req_type_given_activation_history(
719
+		$activation_history_for_addon,
720
+		$activation_indicator_option_name,
721
+		$version_to_upgrade_to
722
+	) {
723
+		$version_is_higher = self::_new_version_is_higher($activation_history_for_addon, $version_to_upgrade_to);
724
+		if ($activation_history_for_addon) {
725
+			// it exists, so this isn't a completely new install
726
+			// check if this version already in that list of previously installed versions
727
+			if (! isset($activation_history_for_addon[ $version_to_upgrade_to ])) {
728
+				// it a version we haven't seen before
729
+				if ($version_is_higher === 1) {
730
+					$req_type = EE_System::req_type_upgrade;
731
+				} else {
732
+					$req_type = EE_System::req_type_downgrade;
733
+				}
734
+				delete_option($activation_indicator_option_name);
735
+			} else {
736
+				// its not an update. maybe a reactivation?
737
+				if (get_option($activation_indicator_option_name, false)) {
738
+					if ($version_is_higher === -1) {
739
+						$req_type = EE_System::req_type_downgrade;
740
+					} elseif ($version_is_higher === 0) {
741
+						// we've seen this version before, but it's an activation. must be a reactivation
742
+						$req_type = EE_System::req_type_reactivation;
743
+					} else {// $version_is_higher === 1
744
+						$req_type = EE_System::req_type_upgrade;
745
+					}
746
+					delete_option($activation_indicator_option_name);
747
+				} else {
748
+					// we've seen this version before and the activation indicate doesn't show it was just activated
749
+					if ($version_is_higher === -1) {
750
+						$req_type = EE_System::req_type_downgrade;
751
+					} elseif ($version_is_higher === 0) {
752
+						// we've seen this version before and it's not an activation. its normal request
753
+						$req_type = EE_System::req_type_normal;
754
+					} else {// $version_is_higher === 1
755
+						$req_type = EE_System::req_type_upgrade;
756
+					}
757
+				}
758
+			}
759
+		} else {
760
+			// brand new install
761
+			$req_type = EE_System::req_type_new_activation;
762
+			delete_option($activation_indicator_option_name);
763
+		}
764
+		return $req_type;
765
+	}
766
+
767
+
768
+	/**
769
+	 * Detects if the $version_to_upgrade_to is higher than the most recent version in
770
+	 * the $activation_history_for_addon
771
+	 *
772
+	 * @param array  $activation_history_for_addon (keys are versions, values are arrays of times activated,
773
+	 *                                             sometimes containing 'unknown-date'
774
+	 * @param string $version_to_upgrade_to        (current version)
775
+	 * @return int results of version_compare( $version_to_upgrade_to, $most_recently_active_version ).
776
+	 *                                             ie, -1 if $version_to_upgrade_to is LOWER (downgrade);
777
+	 *                                             0 if $version_to_upgrade_to MATCHES (reactivation or normal request);
778
+	 *                                             1 if $version_to_upgrade_to is HIGHER (upgrade) ;
779
+	 */
780
+	private static function _new_version_is_higher($activation_history_for_addon, $version_to_upgrade_to)
781
+	{
782
+		// find the most recently-activated version
783
+		$most_recently_active_version =
784
+			EE_System::_get_most_recently_active_version_from_activation_history($activation_history_for_addon);
785
+		return version_compare($version_to_upgrade_to, $most_recently_active_version);
786
+	}
787
+
788
+
789
+	/**
790
+	 * Gets the most recently active version listed in the activation history,
791
+	 * and if none are found (ie, it's a brand new install) returns '0.0.0.dev.000'.
792
+	 *
793
+	 * @param array $activation_history  (keys are versions, values are arrays of times activated,
794
+	 *                                   sometimes containing 'unknown-date'
795
+	 * @return string
796
+	 */
797
+	private static function _get_most_recently_active_version_from_activation_history($activation_history)
798
+	{
799
+		$most_recently_active_version_activation = '1970-01-01 00:00:00';
800
+		$most_recently_active_version = '0.0.0.dev.000';
801
+		if (is_array($activation_history)) {
802
+			foreach ($activation_history as $version => $times_activated) {
803
+				// check there is a record of when this version was activated. Otherwise,
804
+				// mark it as unknown
805
+				if (! $times_activated) {
806
+					$times_activated = array('unknown-date');
807
+				}
808
+				if (is_string($times_activated)) {
809
+					$times_activated = array($times_activated);
810
+				}
811
+				foreach ($times_activated as $an_activation) {
812
+					if (
813
+						$an_activation !== 'unknown-date'
814
+						&& $an_activation
815
+						   > $most_recently_active_version_activation
816
+					) {
817
+						$most_recently_active_version = $version;
818
+						$most_recently_active_version_activation = $an_activation === 'unknown-date'
819
+							? '1970-01-01 00:00:00'
820
+							: $an_activation;
821
+					}
822
+				}
823
+			}
824
+		}
825
+		return $most_recently_active_version;
826
+	}
827
+
828
+
829
+	/**
830
+	 * This redirects to the about EE page after activation
831
+	 *
832
+	 * @return void
833
+	 */
834
+	public function redirect_to_about_ee()
835
+	{
836
+		$notices = EE_Error::get_notices(false);
837
+		// if current user is an admin and it's not an ajax or rest request
838
+		if (
839
+			! isset($notices['errors'])
840
+			&& $this->request->isAdmin()
841
+			&& apply_filters(
842
+				'FHEE__EE_System__redirect_to_about_ee__do_redirect',
843
+				$this->capabilities->current_user_can('manage_options', 'espresso_about_default')
844
+			)
845
+		) {
846
+			$query_params = array('page' => 'espresso_about');
847
+			if (EE_System::instance()->detect_req_type() === EE_System::req_type_new_activation) {
848
+				$query_params['new_activation'] = true;
849
+			}
850
+			if (EE_System::instance()->detect_req_type() === EE_System::req_type_reactivation) {
851
+				$query_params['reactivation'] = true;
852
+			}
853
+			$url = add_query_arg($query_params, admin_url('admin.php'));
854
+			wp_safe_redirect($url);
855
+			exit();
856
+		}
857
+	}
858
+
859
+
860
+	/**
861
+	 * load_core_configuration
862
+	 * this is hooked into 'AHEE__EE_Bootstrap__load_core_configuration'
863
+	 * which runs during the WP 'plugins_loaded' action at priority 5
864
+	 *
865
+	 * @return void
866
+	 * @throws ReflectionException
867
+	 * @throws Exception
868
+	 */
869
+	public function load_core_configuration()
870
+	{
871
+		do_action('AHEE__EE_System__load_core_configuration__begin', $this);
872
+		$this->loader->getShared('EE_Load_Textdomain');
873
+		// load textdomain
874
+		EE_Load_Textdomain::load_textdomain();
875
+		// load caf stuff a chance to play during the activation process too.
876
+		$this->_maybe_brew_regular();
877
+		// load and setup EE_Config and EE_Network_Config
878
+		$config = $this->loader->getShared('EE_Config');
879
+		$this->loader->getShared('EE_Network_Config');
880
+		// setup autoloaders
881
+		// enable logging?
882
+		if ($config->admin->use_remote_logging) {
883
+			$this->loader->getShared('EE_Log');
884
+		}
885
+		// check for activation errors
886
+		$activation_errors = get_option('ee_plugin_activation_errors', false);
887
+		if ($activation_errors) {
888
+			EE_Error::add_error($activation_errors, __FILE__, __FUNCTION__, __LINE__);
889
+			update_option('ee_plugin_activation_errors', false);
890
+		}
891
+		// get model names
892
+		$this->_parse_model_names();
893
+		// configure custom post type definitions
894
+		$this->loader->getShared('EventEspresso\core\domain\entities\custom_post_types\CustomTaxonomyDefinitions');
895
+		$this->loader->getShared('EventEspresso\core\domain\entities\custom_post_types\CustomPostTypeDefinitions');
896
+		do_action('AHEE__EE_System__load_core_configuration__complete', $this);
897
+	}
898
+
899
+
900
+	/**
901
+	 * cycles through all of the models/*.model.php files, and assembles an array of model names
902
+	 *
903
+	 * @return void
904
+	 * @throws ReflectionException
905
+	 */
906
+	private function _parse_model_names()
907
+	{
908
+		// get all the files in the EE_MODELS folder that end in .model.php
909
+		$models = glob(EE_MODELS . '*.model.php');
910
+		$model_names = array();
911
+		$non_abstract_db_models = array();
912
+		foreach ($models as $model) {
913
+			// get model classname
914
+			$classname = EEH_File::get_classname_from_filepath_with_standard_filename($model);
915
+			$short_name = str_replace('EEM_', '', $classname);
916
+			$reflectionClass = new ReflectionClass($classname);
917
+			if ($reflectionClass->isSubclassOf('EEM_Base') && ! $reflectionClass->isAbstract()) {
918
+				$non_abstract_db_models[ $short_name ] = $classname;
919
+			}
920
+			$model_names[ $short_name ] = $classname;
921
+		}
922
+		$this->registry->models = apply_filters('FHEE__EE_System__parse_model_names', $model_names);
923
+		$this->registry->non_abstract_db_models = apply_filters(
924
+			'FHEE__EE_System__parse_implemented_model_names',
925
+			$non_abstract_db_models
926
+		);
927
+	}
928
+
929
+
930
+	/**
931
+	 * The purpose of this method is to simply check for a file named "caffeinated/brewing_regular.php" for any hooks
932
+	 * that need to be setup before our EE_System launches.
933
+	 *
934
+	 * @return void
935
+	 * @throws DomainException
936
+	 * @throws InvalidArgumentException
937
+	 * @throws InvalidDataTypeException
938
+	 * @throws InvalidInterfaceException
939
+	 * @throws InvalidClassException
940
+	 * @throws InvalidFilePathException
941
+	 */
942
+	private function _maybe_brew_regular()
943
+	{
944
+		/** @var Domain $domain */
945
+		$domain = DomainFactory::getShared(
946
+			new FullyQualifiedName(
947
+				'EventEspresso\core\domain\Domain'
948
+			),
949
+			array(
950
+				new FilePath(EVENT_ESPRESSO_MAIN_FILE),
951
+				Version::fromString(espresso_version()),
952
+			)
953
+		);
954
+		if ($domain->isCaffeinated()) {
955
+			require_once EE_CAFF_PATH . 'brewing_regular.php';
956
+		}
957
+	}
958
+
959
+
960
+	/**
961
+	 * @since 4.9.71.p
962
+	 * @throws Exception
963
+	 */
964
+	public function loadRouteMatchSpecifications()
965
+	{
966
+		try {
967
+			$this->loader->getShared(
968
+				'EventEspresso\core\services\route_match\RouteMatchSpecificationManager'
969
+			);
970
+		} catch (Exception $exception) {
971
+			new ExceptionStackTraceDisplay($exception);
972
+		}
973
+		do_action('AHEE__EE_System__loadRouteMatchSpecifications');
974
+	}
975
+
976
+
977
+	/**
978
+	 * loading CPT related classes earlier so that their definitions are available
979
+	 * but not performing any actual registration with WP core until load_CPTs_and_session() is called
980
+	 *
981
+	 * @since   4.10.21.p
982
+	 */
983
+	public function loadCustomPostTypes()
984
+	{
985
+		$this->register_custom_taxonomies = $this->loader->getShared(
986
+			'EventEspresso\core\domain\services\custom_post_types\RegisterCustomTaxonomies'
987
+		);
988
+		$this->register_custom_post_types = $this->loader->getShared(
989
+			'EventEspresso\core\domain\services\custom_post_types\RegisterCustomPostTypes'
990
+		);
991
+		$this->register_custom_taxonomy_terms = $this->loader->getShared(
992
+			'EventEspresso\core\domain\services\custom_post_types\RegisterCustomTaxonomyTerms'
993
+		);
994
+		// integrate WP_Query with the EE models
995
+		$this->loader->getShared('EE_CPT_Strategy');
996
+		// load legacy EE_Request_Handler in case add-ons still need it
997
+		$this->loader->getShared('EE_Request_Handler');
998
+	}
999
+
1000
+
1001
+	/**
1002
+	 * register_shortcodes_modules_and_widgets
1003
+	 * generate lists of shortcodes and modules, then verify paths and classes
1004
+	 * This is hooked into 'AHEE__EE_Bootstrap__register_shortcodes_modules_and_widgets'
1005
+	 * which runs during the WP 'plugins_loaded' action at priority 7
1006
+	 *
1007
+	 * @access public
1008
+	 * @return void
1009
+	 * @throws Exception
1010
+	 */
1011
+	public function register_shortcodes_modules_and_widgets()
1012
+	{
1013
+		if ($this->request->isFrontend() || $this->request->isIframe() || $this->request->isAjax()) {
1014
+			// load, register, and add shortcodes the new way
1015
+			$this->loader->getShared('EventEspresso\core\services\shortcodes\ShortcodesManager');
1016
+		}
1017
+		do_action('AHEE__EE_System__register_shortcodes_modules_and_widgets');
1018
+		// check for addons using old hook point
1019
+		if (has_action('AHEE__EE_System__register_shortcodes_modules_and_addons')) {
1020
+			$this->_incompatible_addon_error();
1021
+		}
1022
+	}
1023
+
1024
+
1025
+	/**
1026
+	 * _incompatible_addon_error
1027
+	 *
1028
+	 * @access public
1029
+	 * @return void
1030
+	 */
1031
+	private function _incompatible_addon_error()
1032
+	{
1033
+		// get array of classes hooking into here
1034
+		$class_names = EEH_Class_Tools::get_class_names_for_all_callbacks_on_hook(
1035
+			'AHEE__EE_System__register_shortcodes_modules_and_addons'
1036
+		);
1037
+		if (! empty($class_names)) {
1038
+			$msg = esc_html__(
1039
+				'The following plugins, addons, or modules appear to be incompatible with this version of Event Espresso and were automatically deactivated to avoid fatal errors:',
1040
+				'event_espresso'
1041
+			);
1042
+			$msg .= '<ul>';
1043
+			foreach ($class_names as $class_name) {
1044
+				$msg .= '<li><b>Event Espresso - '
1045
+						. str_replace(
1046
+							array('EE_', 'EEM_', 'EED_', 'EES_', 'EEW_'),
1047
+							'',
1048
+							$class_name
1049
+						) . '</b></li>';
1050
+			}
1051
+			$msg .= '</ul>';
1052
+			$msg .= esc_html__(
1053
+				'Compatibility issues can be avoided and/or resolved by keeping addons and plugins updated to the latest version.',
1054
+				'event_espresso'
1055
+			);
1056
+			// save list of incompatible addons to wp-options for later use
1057
+			add_option('ee_incompatible_addons', $class_names, '', 'no');
1058
+			if (is_admin()) {
1059
+				EE_Error::add_error($msg, __FILE__, __FUNCTION__, __LINE__);
1060
+			}
1061
+		}
1062
+	}
1063
+
1064
+
1065
+	/**
1066
+	 * brew_espresso
1067
+	 * begins the process of setting hooks for initializing EE in the correct order
1068
+	 * This is happening on the 'AHEE__EE_Bootstrap__brew_espresso' hook point
1069
+	 * which runs during the WP 'plugins_loaded' action at priority 9
1070
+	 *
1071
+	 * @return void
1072
+	 */
1073
+	public function brew_espresso()
1074
+	{
1075
+		do_action('AHEE__EE_System__brew_espresso__begin', $this);
1076
+		// load some final core systems
1077
+		add_action('init', array($this, 'set_hooks_for_core'), 1);
1078
+		add_action('init', array($this, 'perform_activations_upgrades_and_migrations'), 3);
1079
+		add_action('init', array($this, 'load_CPTs_and_session'), 5);
1080
+		add_action('init', array($this, 'load_controllers'), 7);
1081
+		add_action('init', array($this, 'core_loaded_and_ready'), 9);
1082
+		add_action('init', array($this, 'initialize'), 10);
1083
+		add_action('init', array($this, 'initialize_last'), 100);
1084
+		if (is_admin() && apply_filters('FHEE__EE_System__brew_espresso__load_pue', true)) {
1085
+			// pew pew pew
1086
+			$this->loader->getShared('EventEspresso\core\services\licensing\LicenseService');
1087
+			do_action('AHEE__EE_System__brew_espresso__after_pue_init');
1088
+		}
1089
+		do_action('AHEE__EE_System__brew_espresso__complete', $this);
1090
+	}
1091
+
1092
+
1093
+	/**
1094
+	 *    set_hooks_for_core
1095
+	 *
1096
+	 * @access public
1097
+	 * @return    void
1098
+	 * @throws EE_Error
1099
+	 */
1100
+	public function set_hooks_for_core()
1101
+	{
1102
+		$this->_deactivate_incompatible_addons();
1103
+		do_action('AHEE__EE_System__set_hooks_for_core');
1104
+		$this->loader->getShared('EventEspresso\core\domain\values\session\SessionLifespan');
1105
+		// caps need to be initialized on every request so that capability maps are set.
1106
+		// @see https://events.codebasehq.com/projects/event-espresso/tickets/8674
1107
+		$this->registry->CAP->init_caps();
1108
+	}
1109
+
1110
+
1111
+	/**
1112
+	 * Using the information gathered in EE_System::_incompatible_addon_error,
1113
+	 * deactivates any addons considered incompatible with the current version of EE
1114
+	 */
1115
+	private function _deactivate_incompatible_addons()
1116
+	{
1117
+		$incompatible_addons = get_option('ee_incompatible_addons', array());
1118
+		if (! empty($incompatible_addons)) {
1119
+			$active_plugins = get_option('active_plugins', array());
1120
+			foreach ($active_plugins as $active_plugin) {
1121
+				foreach ($incompatible_addons as $incompatible_addon) {
1122
+					if (strpos($active_plugin, $incompatible_addon) !== false) {
1123
+						$this->request->unSetRequestParams(['activate'], true);
1124
+						espresso_deactivate_plugin($active_plugin);
1125
+					}
1126
+				}
1127
+			}
1128
+		}
1129
+	}
1130
+
1131
+
1132
+	/**
1133
+	 *    perform_activations_upgrades_and_migrations
1134
+	 *
1135
+	 * @access public
1136
+	 * @return    void
1137
+	 */
1138
+	public function perform_activations_upgrades_and_migrations()
1139
+	{
1140
+		do_action('AHEE__EE_System__perform_activations_upgrades_and_migrations');
1141
+	}
1142
+
1143
+
1144
+	/**
1145
+	 * @return void
1146
+	 * @throws DomainException
1147
+	 */
1148
+	public function load_CPTs_and_session()
1149
+	{
1150
+		do_action('AHEE__EE_System__load_CPTs_and_session__start');
1151
+		$this->register_custom_taxonomies->registerCustomTaxonomies();
1152
+		$this->register_custom_post_types->registerCustomPostTypes();
1153
+		$this->register_custom_taxonomy_terms->registerCustomTaxonomyTerms();
1154
+		// load legacy Custom Post Types and Taxonomies
1155
+		$this->loader->getShared('EE_Register_CPTs');
1156
+		do_action('AHEE__EE_System__load_CPTs_and_session__complete');
1157
+	}
1158
+
1159
+
1160
+	/**
1161
+	 * load_controllers
1162
+	 * this is the best place to load any additional controllers that needs access to EE core.
1163
+	 * it is expected that all basic core EE systems, that are not dependant on the current request are loaded at this
1164
+	 * time
1165
+	 *
1166
+	 * @access public
1167
+	 * @return void
1168
+	 */
1169
+	public function load_controllers()
1170
+	{
1171
+		do_action('AHEE__EE_System__load_controllers__start');
1172
+		// let's get it started
1173
+		if (
1174
+			! $this->maintenance_mode->level()
1175
+			&& ($this->request->isFrontend() || $this->request->isFrontAjax())
1176
+		) {
1177
+			do_action('AHEE__EE_System__load_controllers__load_front_controllers');
1178
+			$this->loader->getShared('EE_Front_Controller');
1179
+		} elseif ($this->request->isAdmin() || $this->request->isAdminAjax()) {
1180
+			do_action('AHEE__EE_System__load_controllers__load_admin_controllers');
1181
+			$this->loader->getShared('EE_Admin');
1182
+		} elseif ($this->request->isWordPressHeartbeat()) {
1183
+			$this->loader->getShared('EventEspresso\core\domain\services\admin\ajax\WordpressHeartbeat');
1184
+		}
1185
+		do_action('AHEE__EE_System__load_controllers__complete');
1186
+	}
1187
+
1188
+
1189
+	/**
1190
+	 * core_loaded_and_ready
1191
+	 * all of the basic EE core should be loaded at this point and available regardless of M-Mode
1192
+	 *
1193
+	 * @access public
1194
+	 * @return void
1195
+	 * @throws Exception
1196
+	 */
1197
+	public function core_loaded_and_ready()
1198
+	{
1199
+		if (
1200
+			$this->request->isAdmin()
1201
+			|| $this->request->isFrontend()
1202
+			|| $this->request->isIframe()
1203
+			|| $this->request->isWordPressApi()
1204
+		) {
1205
+			try {
1206
+				$this->loader->getShared('EventEspresso\core\services\assets\Registry');
1207
+				$this->loader->getShared('EventEspresso\core\domain\services\assets\CoreAssetManager');
1208
+				if ($this->canLoadBlocks()) {
1209
+					$this->loader->getShared(
1210
+						'EventEspresso\core\services\editor\BlockRegistrationManager'
1211
+					);
1212
+				}
1213
+			} catch (Exception $exception) {
1214
+				new ExceptionStackTraceDisplay($exception);
1215
+			}
1216
+		}
1217
+		if (
1218
+			$this->request->isAdmin()
1219
+			|| $this->request->isEeAjax()
1220
+			|| $this->request->isFrontend()
1221
+		) {
1222
+			$this->loader->getShared('EE_Session');
1223
+		}
1224
+		do_action('AHEE__EE_System__core_loaded_and_ready');
1225
+		// always load template tags, because it's faster than checking if it's a front-end request, and many page
1226
+		// builders require these even on the front-end
1227
+		require_once EE_PUBLIC . 'template_tags.php';
1228
+		do_action('AHEE__EE_System__set_hooks_for_shortcodes_modules_and_addons');
1229
+	}
1230
+
1231
+
1232
+	/**
1233
+	 * initialize
1234
+	 * this is the best place to begin initializing client code
1235
+	 *
1236
+	 * @access public
1237
+	 * @return void
1238
+	 */
1239
+	public function initialize()
1240
+	{
1241
+		do_action('AHEE__EE_System__initialize');
1242
+		add_filter(
1243
+			'safe_style_css',
1244
+			function ($styles) {
1245
+				$styles[] = 'display';
1246
+				$styles[] = 'visibility';
1247
+				$styles[] = 'position';
1248
+				$styles[] = 'top';
1249
+				$styles[] = 'right';
1250
+				$styles[] = 'bottom';
1251
+				$styles[] = 'left';
1252
+				$styles[] = 'resize';
1253
+				$styles[] = 'max-width';
1254
+				$styles[] = 'max-height';
1255
+				return $styles;
1256
+			}
1257
+		);
1258
+	}
1259
+
1260
+
1261
+	/**
1262
+	 * initialize_last
1263
+	 * this is run really late during the WP init hook point, and ensures that mostly everything else that needs to
1264
+	 * initialize has done so
1265
+	 *
1266
+	 * @access public
1267
+	 * @return void
1268
+	 */
1269
+	public function initialize_last()
1270
+	{
1271
+		do_action('AHEE__EE_System__initialize_last');
1272
+		/** @var EventEspresso\core\domain\services\custom_post_types\RewriteRules $rewrite_rules */
1273
+		$rewrite_rules = $this->loader->getShared(
1274
+			'EventEspresso\core\domain\services\custom_post_types\RewriteRules'
1275
+		);
1276
+		$rewrite_rules->flushRewriteRules();
1277
+		add_action('admin_bar_init', array($this, 'addEspressoToolbar'));
1278
+		if (
1279
+			($this->request->isAjax() || $this->request->isAdmin())
1280
+			&& $this->maintenance_mode->models_can_query()
1281
+		) {
1282
+			$this->loader->getShared('EventEspresso\core\services\privacy\export\PersonalDataExporterManager');
1283
+			$this->loader->getShared('EventEspresso\core\services\privacy\erasure\PersonalDataEraserManager');
1284
+		}
1285
+	}
1286
+
1287
+
1288
+	/**
1289
+	 * @return void
1290
+	 * @throws EE_Error
1291
+	 */
1292
+	public function addEspressoToolbar()
1293
+	{
1294
+		$this->loader->getShared(
1295
+			'EventEspresso\core\domain\services\admin\AdminToolBar',
1296
+			array($this->registry->CAP)
1297
+		);
1298
+	}
1299
+
1300
+
1301
+	/**
1302
+	 * do_not_cache
1303
+	 * sets no cache headers and defines no cache constants for WP plugins
1304
+	 *
1305
+	 * @access public
1306
+	 * @return void
1307
+	 */
1308
+	public static function do_not_cache()
1309
+	{
1310
+		// set no cache constants
1311
+		if (! defined('DONOTCACHEPAGE')) {
1312
+			define('DONOTCACHEPAGE', true);
1313
+		}
1314
+		if (! defined('DONOTCACHCEOBJECT')) {
1315
+			define('DONOTCACHCEOBJECT', true);
1316
+		}
1317
+		if (! defined('DONOTCACHEDB')) {
1318
+			define('DONOTCACHEDB', true);
1319
+		}
1320
+		// add no cache headers
1321
+		add_action('send_headers', array('EE_System', 'nocache_headers'), 10);
1322
+		// plus a little extra for nginx and Google Chrome
1323
+		add_filter('nocache_headers', array('EE_System', 'extra_nocache_headers'), 10, 1);
1324
+		// prevent browsers from prefetching of the rel='next' link, because it may contain content that interferes with the registration process
1325
+		remove_action('wp_head', 'adjacent_posts_rel_link_wp_head');
1326
+	}
1327
+
1328
+
1329
+	/**
1330
+	 *    extra_nocache_headers
1331
+	 *
1332
+	 * @access    public
1333
+	 * @param $headers
1334
+	 * @return    array
1335
+	 */
1336
+	public static function extra_nocache_headers($headers)
1337
+	{
1338
+		// for NGINX
1339
+		$headers['X-Accel-Expires'] = 0;
1340
+		// plus extra for Google Chrome since it doesn't seem to respect "no-cache", but WILL respect "no-store"
1341
+		$headers['Cache-Control'] = 'no-store, no-cache, must-revalidate, max-age=0';
1342
+		return $headers;
1343
+	}
1344
+
1345
+
1346
+	/**
1347
+	 *    nocache_headers
1348
+	 *
1349
+	 * @access    public
1350
+	 * @return    void
1351
+	 */
1352
+	public static function nocache_headers()
1353
+	{
1354
+		nocache_headers();
1355
+	}
1356
+
1357
+
1358
+	/**
1359
+	 * simply hooks into "wp_list_pages_exclude" filter (for wp_list_pages method) and makes sure EE critical pages are
1360
+	 * never returned with the function.
1361
+	 *
1362
+	 * @param  array $exclude_array any existing pages being excluded are in this array.
1363
+	 * @return array
1364
+	 */
1365
+	public function remove_pages_from_wp_list_pages($exclude_array)
1366
+	{
1367
+		return array_merge($exclude_array, $this->registry->CFG->core->get_critical_pages_array());
1368
+	}
1369
+
1370
+
1371
+	/**
1372
+	 * Return whether blocks can be registered/loaded or not.
1373
+	 * @return bool
1374
+	 */
1375
+	private function canLoadBlocks()
1376
+	{
1377
+		return apply_filters('FHEE__EE_System__canLoadBlocks', true)
1378
+			   && function_exists('register_block_type')
1379
+			   // don't load blocks if in the Divi page builder editor context
1380
+			   // @see https://github.com/eventespresso/event-espresso-core/issues/814
1381
+			   && ! $this->request->getRequestParam('et_fb', false);
1382
+	}
1383 1383
 }
Please login to merge, or discard this patch.
Spacing   +28 added lines, -28 removed lines patch added patch discarded remove patch
@@ -155,7 +155,7 @@  discard block
 block discarded – undo
155 155
         EE_Maintenance_Mode $maintenance_mode = null
156 156
     ) {
157 157
         // check if class object is instantiated
158
-        if (! self::$_instance instanceof EE_System) {
158
+        if ( ! self::$_instance instanceof EE_System) {
159 159
             self::$_instance = new self($registry, $loader, $request, $maintenance_mode);
160 160
         }
161 161
         return self::$_instance;
@@ -282,7 +282,7 @@  discard block
 block discarded – undo
282 282
         $this->capabilities = $this->loader->getShared('EE_Capabilities');
283 283
         add_action(
284 284
             'AHEE__EE_Capabilities__init_caps__before_initialization',
285
-            function () {
285
+            function() {
286 286
                 LoaderFactory::getLoader()->getShared('EE_Payment_Method_Manager');
287 287
             }
288 288
         );
@@ -323,7 +323,7 @@  discard block
 block discarded – undo
323 323
     {
324 324
         // set autoloaders for all of the classes implementing EEI_Plugin_API
325 325
         // which provide helpers for EE plugin authors to more easily register certain components with EE.
326
-        EEH_Autoloader::instance()->register_autoloaders_for_each_file_in_folder(EE_LIBRARIES . 'plugin_api');
326
+        EEH_Autoloader::instance()->register_autoloaders_for_each_file_in_folder(EE_LIBRARIES.'plugin_api');
327 327
     }
328 328
 
329 329
 
@@ -342,14 +342,14 @@  discard block
 block discarded – undo
342 342
         $load_callback,
343 343
         $plugin_file_constant
344 344
     ) {
345
-        if (! defined($version_constant)) {
345
+        if ( ! defined($version_constant)) {
346 346
             return;
347 347
         }
348 348
         $addon_version = constant($version_constant);
349 349
         if ($addon_version && version_compare($addon_version, $min_version_required, '<')) {
350 350
             remove_action('AHEE__EE_System__load_espresso_addons', $load_callback);
351
-            if (! function_exists('deactivate_plugins')) {
352
-                require_once ABSPATH . 'wp-admin/includes/plugin.php';
351
+            if ( ! function_exists('deactivate_plugins')) {
352
+                require_once ABSPATH.'wp-admin/includes/plugin.php';
353 353
             }
354 354
             deactivate_plugins(plugin_basename(constant($plugin_file_constant)));
355 355
             $this->request->unSetRequestParams(['activate', 'activate-multi'], true);
@@ -363,7 +363,7 @@  discard block
 block discarded – undo
363 363
                     $min_version_required
364 364
                 ),
365 365
                 __FILE__,
366
-                __FUNCTION__ . "({$addon_name})",
366
+                __FUNCTION__."({$addon_name})",
367 367
                 __LINE__
368 368
             );
369 369
             EE_Error::get_notices(false, true);
@@ -415,7 +415,7 @@  discard block
 block discarded – undo
415 415
                 true
416 416
             )
417 417
         ) {
418
-            include_once EE_THIRD_PARTY . 'wp-api-basic-auth/basic-auth.php';
418
+            include_once EE_THIRD_PARTY.'wp-api-basic-auth/basic-auth.php';
419 419
         }
420 420
         do_action('AHEE__EE_System__load_espresso_addons__complete');
421 421
     }
@@ -517,11 +517,11 @@  discard block
 block discarded – undo
517 517
     private function fix_espresso_db_upgrade_option($espresso_db_update = null)
518 518
     {
519 519
         do_action('FHEE__EE_System__manage_fix_espresso_db_upgrade_option__begin', $espresso_db_update);
520
-        if (! $espresso_db_update) {
520
+        if ( ! $espresso_db_update) {
521 521
             $espresso_db_update = get_option('espresso_db_update');
522 522
         }
523 523
         // check that option is an array
524
-        if (! is_array($espresso_db_update)) {
524
+        if ( ! is_array($espresso_db_update)) {
525 525
             // if option is FALSE, then it never existed
526 526
             if ($espresso_db_update === false) {
527 527
                 // make $espresso_db_update an array and save option with autoload OFF
@@ -541,10 +541,10 @@  discard block
 block discarded – undo
541 541
                     // so it must be numerically-indexed, where values are versions installed...
542 542
                     // fix it!
543 543
                     $version_string = $should_be_array;
544
-                    $corrected_db_update[ $version_string ] = array('unknown-date');
544
+                    $corrected_db_update[$version_string] = array('unknown-date');
545 545
                 } else {
546 546
                     // ok it checks out
547
-                    $corrected_db_update[ $should_be_version_string ] = $should_be_array;
547
+                    $corrected_db_update[$should_be_version_string] = $should_be_array;
548 548
                 }
549 549
             }
550 550
             $espresso_db_update = $corrected_db_update;
@@ -628,13 +628,13 @@  discard block
 block discarded – undo
628 628
      */
629 629
     public function update_list_of_installed_versions($version_history = null, $current_version_to_add = null)
630 630
     {
631
-        if (! $version_history) {
631
+        if ( ! $version_history) {
632 632
             $version_history = $this->fix_espresso_db_upgrade_option($version_history);
633 633
         }
634 634
         if ($current_version_to_add === null) {
635 635
             $current_version_to_add = espresso_version();
636 636
         }
637
-        $version_history[ $current_version_to_add ][] = date('Y-m-d H:i:s', time());
637
+        $version_history[$current_version_to_add][] = date('Y-m-d H:i:s', time());
638 638
         // re-save
639 639
         return update_option('espresso_db_update', $version_history);
640 640
     }
@@ -724,7 +724,7 @@  discard block
 block discarded – undo
724 724
         if ($activation_history_for_addon) {
725 725
             // it exists, so this isn't a completely new install
726 726
             // check if this version already in that list of previously installed versions
727
-            if (! isset($activation_history_for_addon[ $version_to_upgrade_to ])) {
727
+            if ( ! isset($activation_history_for_addon[$version_to_upgrade_to])) {
728 728
                 // it a version we haven't seen before
729 729
                 if ($version_is_higher === 1) {
730 730
                     $req_type = EE_System::req_type_upgrade;
@@ -802,7 +802,7 @@  discard block
 block discarded – undo
802 802
             foreach ($activation_history as $version => $times_activated) {
803 803
                 // check there is a record of when this version was activated. Otherwise,
804 804
                 // mark it as unknown
805
-                if (! $times_activated) {
805
+                if ( ! $times_activated) {
806 806
                     $times_activated = array('unknown-date');
807 807
                 }
808 808
                 if (is_string($times_activated)) {
@@ -906,7 +906,7 @@  discard block
 block discarded – undo
906 906
     private function _parse_model_names()
907 907
     {
908 908
         // get all the files in the EE_MODELS folder that end in .model.php
909
-        $models = glob(EE_MODELS . '*.model.php');
909
+        $models = glob(EE_MODELS.'*.model.php');
910 910
         $model_names = array();
911 911
         $non_abstract_db_models = array();
912 912
         foreach ($models as $model) {
@@ -915,9 +915,9 @@  discard block
 block discarded – undo
915 915
             $short_name = str_replace('EEM_', '', $classname);
916 916
             $reflectionClass = new ReflectionClass($classname);
917 917
             if ($reflectionClass->isSubclassOf('EEM_Base') && ! $reflectionClass->isAbstract()) {
918
-                $non_abstract_db_models[ $short_name ] = $classname;
918
+                $non_abstract_db_models[$short_name] = $classname;
919 919
             }
920
-            $model_names[ $short_name ] = $classname;
920
+            $model_names[$short_name] = $classname;
921 921
         }
922 922
         $this->registry->models = apply_filters('FHEE__EE_System__parse_model_names', $model_names);
923 923
         $this->registry->non_abstract_db_models = apply_filters(
@@ -952,7 +952,7 @@  discard block
 block discarded – undo
952 952
             )
953 953
         );
954 954
         if ($domain->isCaffeinated()) {
955
-            require_once EE_CAFF_PATH . 'brewing_regular.php';
955
+            require_once EE_CAFF_PATH.'brewing_regular.php';
956 956
         }
957 957
     }
958 958
 
@@ -1034,7 +1034,7 @@  discard block
 block discarded – undo
1034 1034
         $class_names = EEH_Class_Tools::get_class_names_for_all_callbacks_on_hook(
1035 1035
             'AHEE__EE_System__register_shortcodes_modules_and_addons'
1036 1036
         );
1037
-        if (! empty($class_names)) {
1037
+        if ( ! empty($class_names)) {
1038 1038
             $msg = esc_html__(
1039 1039
                 'The following plugins, addons, or modules appear to be incompatible with this version of Event Espresso and were automatically deactivated to avoid fatal errors:',
1040 1040
                 'event_espresso'
@@ -1046,7 +1046,7 @@  discard block
 block discarded – undo
1046 1046
                             array('EE_', 'EEM_', 'EED_', 'EES_', 'EEW_'),
1047 1047
                             '',
1048 1048
                             $class_name
1049
-                        ) . '</b></li>';
1049
+                        ).'</b></li>';
1050 1050
             }
1051 1051
             $msg .= '</ul>';
1052 1052
             $msg .= esc_html__(
@@ -1115,7 +1115,7 @@  discard block
 block discarded – undo
1115 1115
     private function _deactivate_incompatible_addons()
1116 1116
     {
1117 1117
         $incompatible_addons = get_option('ee_incompatible_addons', array());
1118
-        if (! empty($incompatible_addons)) {
1118
+        if ( ! empty($incompatible_addons)) {
1119 1119
             $active_plugins = get_option('active_plugins', array());
1120 1120
             foreach ($active_plugins as $active_plugin) {
1121 1121
                 foreach ($incompatible_addons as $incompatible_addon) {
@@ -1224,7 +1224,7 @@  discard block
 block discarded – undo
1224 1224
         do_action('AHEE__EE_System__core_loaded_and_ready');
1225 1225
         // always load template tags, because it's faster than checking if it's a front-end request, and many page
1226 1226
         // builders require these even on the front-end
1227
-        require_once EE_PUBLIC . 'template_tags.php';
1227
+        require_once EE_PUBLIC.'template_tags.php';
1228 1228
         do_action('AHEE__EE_System__set_hooks_for_shortcodes_modules_and_addons');
1229 1229
     }
1230 1230
 
@@ -1241,7 +1241,7 @@  discard block
 block discarded – undo
1241 1241
         do_action('AHEE__EE_System__initialize');
1242 1242
         add_filter(
1243 1243
             'safe_style_css',
1244
-            function ($styles) {
1244
+            function($styles) {
1245 1245
                 $styles[] = 'display';
1246 1246
                 $styles[] = 'visibility';
1247 1247
                 $styles[] = 'position';
@@ -1308,13 +1308,13 @@  discard block
 block discarded – undo
1308 1308
     public static function do_not_cache()
1309 1309
     {
1310 1310
         // set no cache constants
1311
-        if (! defined('DONOTCACHEPAGE')) {
1311
+        if ( ! defined('DONOTCACHEPAGE')) {
1312 1312
             define('DONOTCACHEPAGE', true);
1313 1313
         }
1314
-        if (! defined('DONOTCACHCEOBJECT')) {
1314
+        if ( ! defined('DONOTCACHCEOBJECT')) {
1315 1315
             define('DONOTCACHCEOBJECT', true);
1316 1316
         }
1317
-        if (! defined('DONOTCACHEDB')) {
1317
+        if ( ! defined('DONOTCACHEDB')) {
1318 1318
             define('DONOTCACHEDB', true);
1319 1319
         }
1320 1320
         // add no cache headers
Please login to merge, or discard this patch.
espresso.php 1 patch
Indentation   +80 added lines, -80 removed lines patch added patch discarded remove patch
@@ -38,103 +38,103 @@
 block discarded – undo
38 38
  * @since           4.0
39 39
  */
40 40
 if (function_exists('espresso_version')) {
41
-    if (! function_exists('espresso_duplicate_plugin_error')) {
42
-        /**
43
-         *    espresso_duplicate_plugin_error
44
-         *    displays if more than one version of EE is activated at the same time
45
-         */
46
-        function espresso_duplicate_plugin_error()
47
-        {
48
-            ?>
41
+	if (! function_exists('espresso_duplicate_plugin_error')) {
42
+		/**
43
+		 *    espresso_duplicate_plugin_error
44
+		 *    displays if more than one version of EE is activated at the same time
45
+		 */
46
+		function espresso_duplicate_plugin_error()
47
+		{
48
+			?>
49 49
             <div class="error">
50 50
                 <p>
51 51
                     <?php
52
-                    echo esc_html__(
53
-                        'Can not run multiple versions of Event Espresso! One version has been automatically deactivated. Please verify that you have the correct version you want still active.',
54
-                        'event_espresso'
55
-                    ); ?>
52
+					echo esc_html__(
53
+						'Can not run multiple versions of Event Espresso! One version has been automatically deactivated. Please verify that you have the correct version you want still active.',
54
+						'event_espresso'
55
+					); ?>
56 56
                 </p>
57 57
             </div>
58 58
             <?php
59
-            espresso_deactivate_plugin(plugin_basename(__FILE__));
60
-        }
61
-    }
62
-    add_action('admin_notices', 'espresso_duplicate_plugin_error', 1);
59
+			espresso_deactivate_plugin(plugin_basename(__FILE__));
60
+		}
61
+	}
62
+	add_action('admin_notices', 'espresso_duplicate_plugin_error', 1);
63 63
 } else {
64
-    define('EE_MIN_PHP_VER_REQUIRED', '5.6.2');
65
-    if (! version_compare(PHP_VERSION, EE_MIN_PHP_VER_REQUIRED, '>=')) {
66
-        /**
67
-         * espresso_minimum_php_version_error
68
-         *
69
-         * @return void
70
-         */
71
-        function espresso_minimum_php_version_error()
72
-        {
73
-            ?>
64
+	define('EE_MIN_PHP_VER_REQUIRED', '5.6.2');
65
+	if (! version_compare(PHP_VERSION, EE_MIN_PHP_VER_REQUIRED, '>=')) {
66
+		/**
67
+		 * espresso_minimum_php_version_error
68
+		 *
69
+		 * @return void
70
+		 */
71
+		function espresso_minimum_php_version_error()
72
+		{
73
+			?>
74 74
             <div class="error">
75 75
                 <p>
76 76
                     <?php
77
-                    printf(
78
-                        esc_html__(
79
-                            'We\'re sorry, but Event Espresso requires PHP version %1$s or greater in order to operate. You are currently running version %2$s.%3$sIn order to update your version of PHP, you will need to contact your current hosting provider.%3$sFor information on stable PHP versions, please go to %4$s.',
80
-                            'event_espresso'
81
-                        ),
82
-                        EE_MIN_PHP_VER_REQUIRED,
83
-                        PHP_VERSION,
84
-                        '<br/>',
85
-                        '<a href="http://php.net/downloads.php">http://php.net/downloads.php</a>'
86
-                    );
87
-                    ?>
77
+					printf(
78
+						esc_html__(
79
+							'We\'re sorry, but Event Espresso requires PHP version %1$s or greater in order to operate. You are currently running version %2$s.%3$sIn order to update your version of PHP, you will need to contact your current hosting provider.%3$sFor information on stable PHP versions, please go to %4$s.',
80
+							'event_espresso'
81
+						),
82
+						EE_MIN_PHP_VER_REQUIRED,
83
+						PHP_VERSION,
84
+						'<br/>',
85
+						'<a href="http://php.net/downloads.php">http://php.net/downloads.php</a>'
86
+					);
87
+					?>
88 88
                 </p>
89 89
             </div>
90 90
             <?php
91
-            espresso_deactivate_plugin(plugin_basename(__FILE__));
92
-        }
91
+			espresso_deactivate_plugin(plugin_basename(__FILE__));
92
+		}
93 93
 
94
-        add_action('admin_notices', 'espresso_minimum_php_version_error', 1);
95
-    } else {
96
-        define('EVENT_ESPRESSO_MAIN_FILE', __FILE__);
97
-        /**
98
-         * espresso_version
99
-         * Returns the plugin version
100
-         *
101
-         * @return string
102
-         */
103
-        function espresso_version()
104
-        {
105
-            return apply_filters('FHEE__espresso__espresso_version', '4.10.33.rc.006');
106
-        }
94
+		add_action('admin_notices', 'espresso_minimum_php_version_error', 1);
95
+	} else {
96
+		define('EVENT_ESPRESSO_MAIN_FILE', __FILE__);
97
+		/**
98
+		 * espresso_version
99
+		 * Returns the plugin version
100
+		 *
101
+		 * @return string
102
+		 */
103
+		function espresso_version()
104
+		{
105
+			return apply_filters('FHEE__espresso__espresso_version', '4.10.33.rc.006');
106
+		}
107 107
 
108
-        /**
109
-         * espresso_plugin_activation
110
-         * adds a wp-option to indicate that EE has been activated via the WP admin plugins page
111
-         */
112
-        function espresso_plugin_activation()
113
-        {
114
-            update_option('ee_espresso_activation', true);
115
-        }
108
+		/**
109
+		 * espresso_plugin_activation
110
+		 * adds a wp-option to indicate that EE has been activated via the WP admin plugins page
111
+		 */
112
+		function espresso_plugin_activation()
113
+		{
114
+			update_option('ee_espresso_activation', true);
115
+		}
116 116
 
117
-        register_activation_hook(EVENT_ESPRESSO_MAIN_FILE, 'espresso_plugin_activation');
117
+		register_activation_hook(EVENT_ESPRESSO_MAIN_FILE, 'espresso_plugin_activation');
118 118
 
119
-        require_once __DIR__ . '/core/bootstrap_espresso.php';
120
-        bootstrap_espresso();
121
-    }
119
+		require_once __DIR__ . '/core/bootstrap_espresso.php';
120
+		bootstrap_espresso();
121
+	}
122 122
 }
123 123
 if (! function_exists('espresso_deactivate_plugin')) {
124
-    /**
125
-     *    deactivate_plugin
126
-     * usage:  espresso_deactivate_plugin( plugin_basename( __FILE__ ));
127
-     *
128
-     * @access public
129
-     * @param string $plugin_basename - the results of plugin_basename( __FILE__ ) for the plugin's main file
130
-     * @return    void
131
-     */
132
-    function espresso_deactivate_plugin($plugin_basename = '')
133
-    {
134
-        if (! function_exists('deactivate_plugins')) {
135
-            require_once ABSPATH . 'wp-admin/includes/plugin.php';
136
-        }
137
-        unset($_GET['activate'], $_REQUEST['activate']);
138
-        deactivate_plugins($plugin_basename);
139
-    }
124
+	/**
125
+	 *    deactivate_plugin
126
+	 * usage:  espresso_deactivate_plugin( plugin_basename( __FILE__ ));
127
+	 *
128
+	 * @access public
129
+	 * @param string $plugin_basename - the results of plugin_basename( __FILE__ ) for the plugin's main file
130
+	 * @return    void
131
+	 */
132
+	function espresso_deactivate_plugin($plugin_basename = '')
133
+	{
134
+		if (! function_exists('deactivate_plugins')) {
135
+			require_once ABSPATH . 'wp-admin/includes/plugin.php';
136
+		}
137
+		unset($_GET['activate'], $_REQUEST['activate']);
138
+		deactivate_plugins($plugin_basename);
139
+	}
140 140
 }
141 141
\ No newline at end of file
Please login to merge, or discard this patch.
core/EE_Data_Migration_Manager.core.php 2 patches
Indentation   +1316 added lines, -1316 removed lines patch added patch discarded remove patch
@@ -32,1320 +32,1320 @@
 block discarded – undo
32 32
 class EE_Data_Migration_Manager implements ResettableInterface
33 33
 {
34 34
 
35
-    /**
36
-     *
37
-     * @var EE_Registry
38
-     */
39
-    // protected $EE;
40
-    /**
41
-     * name of the WordPress option which stores an array of data about
42
-     */
43
-    const data_migrations_option_name = 'ee_data_migration';
44
-
45
-
46
-    const data_migration_script_option_prefix         = 'ee_data_migration_script_';
47
-
48
-    const data_migration_script_mapping_option_prefix = 'ee_dms_map_';
49
-
50
-    /**
51
-     * name of the WordPress option which stores the database' current version. IE, the code may be at version 4.2.0,
52
-     * but as migrations are performed the database will progress from 3.1.35 to 4.1.0 etc.
53
-     */
54
-    const current_database_state = 'ee_data_migration_current_db_state';
55
-
56
-    /**
57
-     * Special status string returned when we're positive there are no more data migration
58
-     * scripts that can be run.
59
-     */
60
-    const status_no_more_migration_scripts = 'no_more_migration_scripts';
61
-
62
-    /**
63
-     * string indicating the migration should continue
64
-     */
65
-    const status_continue = 'status_continue';
66
-
67
-    /**
68
-     * string indicating the migration has completed and should be ended
69
-     */
70
-    const status_completed = 'status_completed';
71
-
72
-    /**
73
-     * string indicating a fatal error occurred and the data migration should be completely aborted
74
-     */
75
-    const status_fatal_error = 'status_fatal_error';
76
-
77
-    /**
78
-     * the number of 'items' (usually DB rows) to migrate on each 'step' (ajax request sent
79
-     * during migration)
80
-     */
81
-    const step_size = 50;
82
-
83
-    /**
84
-     * option name that stores the queue of ee plugins needing to have
85
-     * their data initialized (or re-initialized) once we are done migrations
86
-     */
87
-    const db_init_queue_option_name = 'ee_db_init_queue';
88
-
89
-    /**
90
-     * Array of information concerning data migrations that have run in the history
91
-     * of this EE installation. Keys should be the name of the version the script upgraded to
92
-     *
93
-     * @var EE_Data_Migration_Script_Base[]
94
-     */
95
-    private $_data_migrations_ran = null;
96
-
97
-    /**
98
-     * The last run script. It's nice to store this somewhere accessible, as its easiest
99
-     * to know which was the last run by which is the newest wp option; but in most of the code
100
-     * we just use the local $_data_migration_ran array, which organized the scripts differently
101
-     *
102
-     * @var EE_Data_Migration_Script_Base
103
-     */
104
-    private $_last_ran_script = null;
105
-
106
-    /**
107
-     * Similarly to _last_ran_script, but this is the last INCOMPLETE migration script.
108
-     *
109
-     * @var EE_Data_Migration_Script_Base
110
-     */
111
-    private $_last_ran_incomplete_script = null;
112
-
113
-    /**
114
-     * array where keys are classnames, and values are filepaths of all the known migration scripts
115
-     *
116
-     * @var array
117
-     */
118
-    private $_data_migration_class_to_filepath_map;
119
-
120
-    /**
121
-     * the following 4 properties are fully set on construction.
122
-     * Note: the first two apply to whether to continue running ALL migration scripts (ie, even though we're finished
123
-     * one, we may want to start the next one); whereas the last two indicate whether to continue running a single
124
-     * data migration script
125
-     *
126
-     * @var array
127
-     */
128
-    public $stati_that_indicate_to_continue_migrations              = [];
129
-
130
-    public $stati_that_indicate_to_stop_migrations                  = [];
131
-
132
-    public $stati_that_indicate_to_continue_single_migration_script = [];
133
-
134
-    public $stati_that_indicate_to_stop_single_migration_script     = [];
135
-
136
-    /**
137
-     * @var TableManager $table_manager
138
-     */
139
-    protected $_table_manager;
140
-
141
-    /**
142
-     * @var TableAnalysis $table_analysis
143
-     */
144
-    protected $_table_analysis;
145
-
146
-    /**
147
-     * @var array $script_migration_versions
148
-     */
149
-    protected $script_migration_versions;
150
-
151
-    /**
152
-     * @var EE_Data_Migration_Manager $_instance
153
-     * @access    private
154
-     */
155
-    private static $_instance = null;
156
-
157
-
158
-    /**
159
-     * @singleton method used to instantiate class object
160
-     * @access    public
161
-     * @return EE_Data_Migration_Manager instance
162
-     */
163
-    public static function instance()
164
-    {
165
-        // check if class object is instantiated
166
-        if (! self::$_instance instanceof EE_Data_Migration_Manager) {
167
-            self::$_instance = new self();
168
-        }
169
-        return self::$_instance;
170
-    }
171
-
172
-
173
-    /**
174
-     * resets the singleton to its brand-new state (but does NOT delete old references to the old singleton. Meaning,
175
-     * all new usages of the singleton should be made with Classname::instance()) and returns it
176
-     *
177
-     * @return EE_Data_Migration_Manager
178
-     */
179
-    public static function reset()
180
-    {
181
-        self::$_instance = null;
182
-        return self::instance();
183
-    }
184
-
185
-
186
-    /**
187
-     * @throws EE_Error
188
-     * @throws ReflectionException
189
-     */
190
-    private function __construct()
191
-    {
192
-        $this->stati_that_indicate_to_continue_migrations              = [
193
-            self::status_continue,
194
-            self::status_completed,
195
-        ];
196
-        $this->stati_that_indicate_to_stop_migrations                  = [
197
-            self::status_fatal_error,
198
-            self::status_no_more_migration_scripts,
199
-        ];
200
-        $this->stati_that_indicate_to_continue_single_migration_script = [
201
-            self::status_continue,
202
-        ];
203
-        $this->stati_that_indicate_to_stop_single_migration_script     = [
204
-            self::status_completed,
205
-            self::status_fatal_error
206
-            // note: status_no_more_migration_scripts doesn't apply
207
-        ];
208
-        // make sure we've included the base migration script, because we may need the EE_DMS_Unknown_1_0_0 class
209
-        // to be defined, because right now it doesn't get autoloaded on its own
210
-        EE_Registry::instance()->load_core('Data_Migration_Class_Base', [], true);
211
-        EE_Registry::instance()->load_core('Data_Migration_Script_Base', [], true);
212
-        EE_Registry::instance()->load_core('DMS_Unknown_1_0_0', [], true);
213
-        EE_Registry::instance()->load_core('Data_Migration_Script_Stage', [], true);
214
-        EE_Registry::instance()->load_core('Data_Migration_Script_Stage_Table', [], true);
215
-        $this->_table_manager  = EE_Registry::instance()->create('TableManager', [], true);
216
-        $this->_table_analysis = EE_Registry::instance()->create('TableAnalysis', [], true);
217
-    }
218
-
219
-
220
-    /**
221
-     * Deciphers, from an option's name, what plugin and version it relates to (see _save_migrations_ran to see what
222
-     * the option names are like, but generally they're like
223
-     * 'ee_data_migration_script_Core.4.1.0' in 4.2 or 'ee_data_migration_script_4.1.0' before that).
224
-     * The option name shouldn't ever be like 'ee_data_migration_script_Core.4.1.0.reg' because it's derived,
225
-     * indirectly, from the data migration's classname, which should always be like EE_DMS_%s_%d_%d_%d.dms.php
226
-     * (ex: EE_DMS_Core_4_1_0.dms.php)
227
-     *
228
-     * @param string $option_name (see EE_Data_Migration_Manage::_save_migrations_ran() where the option name is set)
229
-     * @return array where the first item is the plugin slug (eg 'Core','Calendar', etc.) and the 2nd is the version of
230
-     *                            that plugin (eg '4.1.0')
231
-     */
232
-    private function _get_plugin_slug_and_version_string_from_dms_option_name($option_name)
233
-    {
234
-        $plugin_slug_and_version_string = str_replace(
235
-            EE_Data_Migration_Manager::data_migration_script_option_prefix,
236
-            "",
237
-            $option_name
238
-        );
239
-        // check if $plugin_slug_and_version_string is like '4.1.0' (4.1-style) or 'Core.4.1.0' (4.2-style)
240
-        $parts = explode(".", $plugin_slug_and_version_string);
241
-
242
-        if (count($parts) == 4) {
243
-            // it's 4.2-style.eg Core.4.1.0
244
-            $plugin_slug    = $parts[0];                                     // eg Core
245
-            $version_string = $parts[1] . "." . $parts[2] . "." . $parts[3]; // eg 4.1.0
246
-        } else {
247
-            // it's 4.1-style: eg 4.1.0
248
-            $plugin_slug    = 'Core';
249
-            $version_string = $plugin_slug_and_version_string;// eg 4.1.0
250
-        }
251
-        return [$plugin_slug, $version_string];
252
-    }
253
-
254
-
255
-    /**
256
-     * Gets the DMS class from the WordPress option, otherwise throws an EE_Error if it's not
257
-     * for a known DMS class.
258
-     *
259
-     * @param string $dms_option_name
260
-     * @param string $dms_option_value (serialized)
261
-     * @return EE_Data_Migration_Script_Base
262
-     * @throws EE_Error
263
-     */
264
-    private function _get_dms_class_from_wp_option($dms_option_name, $dms_option_value)
265
-    {
266
-        $data_migration_data = maybe_unserialize($dms_option_value);
267
-        if (isset($data_migration_data['class']) && class_exists($data_migration_data['class'])) {
268
-            // During multisite migrations, it's possible we already grabbed another instance of this class
269
-            // but for a different blog. Make sure we don't reuse them (as they store info specific
270
-            // to their respective blog, like which database table to migrate).
271
-            $class = LoaderFactory::getLoader()->getNew($data_migration_data['class']);
272
-            if ($class instanceof EE_Data_Migration_Script_Base) {
273
-                $class->instantiate_from_array_of_properties($data_migration_data);
274
-                return $class;
275
-            } else {
276
-                // huh, so it's an object but not a data migration script?? that shouldn't happen
277
-                // just leave it as an array (which will probably just get ignored)
278
-                throw new EE_Error(
279
-                    sprintf(
280
-                        esc_html__(
281
-                            "Trying to retrieve DMS class from wp option. No DMS by the name '%s' exists",
282
-                            'event_espresso'
283
-                        ),
284
-                        $data_migration_data['class']
285
-                    )
286
-                );
287
-            }
288
-        } else {
289
-            // so the data doesn't specify a class. So it must either be a legacy array of info or some array (which we'll probably just ignore), or a class that no longer exists
290
-            throw new EE_Error(
291
-                sprintf(
292
-                    esc_html__("The wp option  with key '%s' does not represent a DMS", 'event_espresso'),
293
-                    $dms_option_name
294
-                )
295
-            );
296
-        }
297
-    }
298
-
299
-
300
-    /**
301
-     * Gets the array describing what data migrations have run.
302
-     * Also has a side effect of recording which was the last run,
303
-     * and which was the last run which hasn't finished yet
304
-     *
305
-     * @return array where each element should be an array of EE_Data_Migration_Script_Base
306
-     *               (but also has a few legacy arrays in there - which should probably be ignored)
307
-     * @throws EE_Error
308
-     */
309
-    public function get_data_migrations_ran()
310
-    {
311
-        if (! $this->_data_migrations_ran) {
312
-            // setup autoloaders for each of the scripts in there
313
-            $this->get_all_data_migration_scripts_available();
314
-            $data_migrations_options =
315
-                $this->get_all_migration_script_options();// get_option(EE_Data_Migration_Manager::data_migrations_option_name,get_option('espresso_data_migrations',array()));
316
-
317
-            $data_migrations_ran = [];
318
-            // convert into data migration script classes where possible
319
-            foreach ($data_migrations_options as $data_migration_option) {
320
-                list($plugin_slug, $version_string) = $this->_get_plugin_slug_and_version_string_from_dms_option_name(
321
-                    $data_migration_option['option_name']
322
-                );
323
-
324
-                try {
325
-                    $class                                                  = $this->_get_dms_class_from_wp_option(
326
-                        $data_migration_option['option_name'],
327
-                        $data_migration_option['option_value']
328
-                    );
329
-                    $data_migrations_ran[ $plugin_slug ][ $version_string ] = $class;
330
-                    // ok so far THIS is the 'last-run-script'... unless we find another on next iteration
331
-                    $this->_last_ran_script = $class;
332
-                    if (! $class->is_completed()) {
333
-                        // sometimes we also like to know which was the last incomplete script (or if there are any at all)
334
-                        $this->_last_ran_incomplete_script = $class;
335
-                    }
336
-                } catch (EE_Error $e) {
337
-                    // ok so it's not a DMS. We'll just keep it, although other code will need to expect non-DMSs
338
-                    $data_migrations_ran[ $plugin_slug ][ $version_string ] = maybe_unserialize(
339
-                        $data_migration_option['option_value']
340
-                    );
341
-                }
342
-            }
343
-            // so here the array of $data_migrations_ran is actually a mix of classes and a few legacy arrays
344
-            $this->_data_migrations_ran = $data_migrations_ran;
345
-            if (! $this->_data_migrations_ran || ! is_array($this->_data_migrations_ran)) {
346
-                $this->_data_migrations_ran = [];
347
-            }
348
-        }
349
-        return $this->_data_migrations_ran;
350
-    }
351
-
352
-
353
-    /**
354
-     *
355
-     * @param string $script_name eg 'DMS_Core_4_1_0'
356
-     * @param string $old_table   eg 'wp_events_detail'
357
-     * @param string $old_pk      eg 'wp_esp_posts'
358
-     * @param        $new_table
359
-     * @return mixed string or int
360
-     * @throws EE_Error
361
-     * @throws ReflectionException
362
-     */
363
-    public function get_mapping_new_pk($script_name, $old_table, $old_pk, $new_table)
364
-    {
365
-        $script  = EE_Registry::instance()->load_dms($script_name);
366
-        return $script->get_mapping_new_pk($old_table, $old_pk, $new_table);
367
-    }
368
-
369
-
370
-    /**
371
-     * Gets all the options containing migration scripts that have been run. Ordering is important: it's assumed that
372
-     * the last option returned in this array is the most-recently run DMS option
373
-     *
374
-     * @return array
375
-     */
376
-    public function get_all_migration_script_options()
377
-    {
378
-        global $wpdb;
379
-        return $wpdb->get_results(
380
-            "SELECT * FROM {$wpdb->options} WHERE option_name like '"
381
-            . EE_Data_Migration_Manager::data_migration_script_option_prefix
382
-            . "%' ORDER BY option_id ASC",
383
-            ARRAY_A
384
-        );
385
-    }
386
-
387
-
388
-    /**
389
-     * Gets the array of folders which contain data migration scripts. Also adds them to be auto-loaded
390
-     *
391
-     * @return array where each value is the full folder path of a folder containing data migration scripts, WITH
392
-     *               slashes at the end of the folder name.
393
-     */
394
-    public function get_data_migration_script_folders()
395
-    {
396
-        return apply_filters(
397
-            'FHEE__EE_Data_Migration_Manager__get_data_migration_script_folders',
398
-            ['Core' => EE_CORE . 'data_migration_scripts']
399
-        );
400
-    }
401
-
402
-
403
-    /**
404
-     * Gets the version the migration script upgrades to
405
-     *
406
-     * @param string $migration_script_name eg 'EE_DMS_Core_4_1_0'
407
-     * @return array {
408
-     *      @type string  $slug     like 'Core','Calendar',etc
409
-     *      @type string  $version  like 4.3.0
410
-     * }
411
-     * @throws EE_Error
412
-     */
413
-    public function script_migrates_to_version($migration_script_name, $eeAddonClass = '')
414
-    {
415
-        if (isset($this->script_migration_versions[ $migration_script_name ])) {
416
-            return $this->script_migration_versions[ $migration_script_name ];
417
-        }
418
-        $dms_info                                                  = $this->parse_dms_classname($migration_script_name);
419
-        $this->script_migration_versions[ $migration_script_name ] = [
420
-            'slug'    => $eeAddonClass !== '' ? $eeAddonClass : $dms_info['slug'],
421
-            'version' => $dms_info['major_version']
422
-                         . "."
423
-                         . $dms_info['minor_version']
424
-                         . "."
425
-                         . $dms_info['micro_version'],
426
-        ];
427
-        return $this->script_migration_versions[ $migration_script_name ];
428
-    }
429
-
430
-
431
-    /**
432
-     * Gets the juicy details out of a dms filename like 'EE_DMS_Core_4_1_0'
433
-     *
434
-     * @param string $classname
435
-     * @return array with keys 'slug','major_version','minor_version', and 'micro_version' (the last 3 are integers)
436
-     * @throws EE_Error
437
-     */
438
-    public function parse_dms_classname($classname)
439
-    {
440
-        $matches = [];
441
-        preg_match('~EE_DMS_(.*)_([0-9]*)_([0-9]*)_([0-9]*)~', $classname, $matches);
442
-        if (! $matches || ! (isset($matches[1]) && isset($matches[2]) && isset($matches[3]))) {
443
-            throw new EE_Error(
444
-                sprintf(
445
-                    esc_html__(
446
-                        "%s is not a valid Data Migration Script. The classname should be like EE_DMS_w_x_y_z, where w is either 'Core' or the slug of an addon and x, y and z are numbers, ",
447
-                        "event_espresso"
448
-                    ),
449
-                    $classname
450
-                )
451
-            );
452
-        }
453
-        return [
454
-            'slug'          => $matches[1],
455
-            'major_version' => intval($matches[2]),
456
-            'minor_version' => intval($matches[3]),
457
-            'micro_version' => intval($matches[4]),
458
-        ];
459
-    }
460
-
461
-
462
-    /**
463
-     * Ensures that the option indicating the current DB version is set. This should only be
464
-     * a concern when activating EE for the first time, THEORETICALLY.
465
-     * If we detect that we're activating EE4 over top of EE3.1, then we set the current db state to 3.1.x, otherwise
466
-     * to 4.1.x.
467
-     *
468
-     * @return string of current db state
469
-     */
470
-    public function ensure_current_database_state_is_set()
471
-    {
472
-        $espresso_db_core_updates = get_option('espresso_db_update', []);
473
-        $db_state                 = get_option(EE_Data_Migration_Manager::current_database_state);
474
-        if (! $db_state) {
475
-            // mark the DB as being in the state as the last version in there.
476
-            // this is done to trigger maintenance mode and do data migration scripts
477
-            // if the admin installed this version of EE over 3.1.x or 4.0.x
478
-            // otherwise, the normal maintenance mode code is fine
479
-            $previous_versions_installed = array_keys($espresso_db_core_updates);
480
-            $previous_version_installed  = end($previous_versions_installed);
481
-            if (version_compare('4.1.0', $previous_version_installed)) {
482
-                // last installed version was less than 4.1, so we want the data migrations to happen.
483
-                // SO, we're going to say the DB is at that state
484
-                $db_state = ['Core' => $previous_version_installed];
485
-            } else {
486
-                $db_state = ['Core' => EVENT_ESPRESSO_VERSION];
487
-            }
488
-            update_option(EE_Data_Migration_Manager::current_database_state, $db_state);
489
-        }
490
-        // in 4.1, $db_state would have only been a simple string like '4.1.0',
491
-        // but in 4.2+ it should be an array with at least key 'Core' and the value of that plugin's
492
-        // db, and possibly other keys for other addons like 'Calendar','Permissions',etc
493
-        if (! is_array($db_state)) {
494
-            $db_state = ['Core' => $db_state];
495
-            update_option(EE_Data_Migration_Manager::current_database_state, $db_state);
496
-        }
497
-        return $db_state;
498
-    }
499
-
500
-
501
-    /**
502
-     * Checks if there are any data migration scripts that ought to be run.
503
-     * If found, returns the instantiated classes.
504
-     * If none are found (ie, they've all already been run, or they don't apply), returns an empty array
505
-     *
506
-     * @return EE_Data_Migration_Script_Base[]
507
-     * @throws EE_Error
508
-     * @throws EE_Error
509
-     */
510
-    public function check_for_applicable_data_migration_scripts()
511
-    {
512
-        // get the option describing what options have already run
513
-        $scripts_ran = $this->get_data_migrations_ran();
514
-        // $scripts_ran = array('4.1.0.core'=>array('monkey'=>null));
515
-        $script_class_and_filepaths_available = $this->get_all_data_migration_scripts_available();
516
-
517
-
518
-        $current_database_state = $this->ensure_current_database_state_is_set();
519
-        // determine which have already been run
520
-        $script_classes_that_should_run_per_iteration = [];
521
-        $iteration                                    = 0;
522
-        $next_database_state_to_consider              = $current_database_state;
523
-        $theoretical_database_state = null;
524
-        do {
525
-            // the next state after the currently-considered one
526
-            // will start off looking the same as the current, but we may make additions...
527
-            $theoretical_database_state = $next_database_state_to_consider;
528
-            // the next db state to consider is
529
-            // "what would the DB be like had we run all the scripts we found that applied last time?"
530
-            foreach ($script_class_and_filepaths_available as $classname => $filepath) {
531
-                $migrates_to_version         = $this->script_migrates_to_version($classname);
532
-                $script_converts_plugin_slug = $migrates_to_version['slug'];
533
-                $script_converts_to_version  = $migrates_to_version['version'];
534
-                // check if this version script is DONE or not; or if it's never been run
535
-                if (
536
-                    ! $scripts_ran
537
-                    || ! isset($scripts_ran[ $script_converts_plugin_slug ][ $script_converts_to_version ])
538
-                ) {
539
-                    // we haven't run this conversion script before
540
-                    // now check if it applies...
541
-                    // note that we've added an autoloader for it on get_all_data_migration_scripts_available
542
-                    // Also, make sure we get a new one. It's possible this is being ran during a multisite migration,
543
-                    // in which case we don't want to reuse a DMS script from a different blog!
544
-                    $script = LoaderFactory::getLoader()->getNew($classname);
545
-                    /* @var $script EE_Data_Migration_Script_Base */
546
-                    $can_migrate = $script->can_migrate_from_version($theoretical_database_state);
547
-                    if ($can_migrate) {
548
-                        $script_classes_that_should_run_per_iteration[ $iteration ][ $script->priority() ][] = $script;
549
-                        $migrates_to_version                                                                 =
550
-                            $script->migrates_to_version();
551
-                        $next_database_state_to_consider[ $migrates_to_version['slug'] ]                     =
552
-                            $migrates_to_version['version'];
553
-                        unset($script_class_and_filepaths_available[ $classname ]);
554
-                    }
555
-                } elseif (
556
-                    $scripts_ran[ $script_converts_plugin_slug ][ $script_converts_to_version ]
557
-                          instanceof
558
-                          EE_Data_Migration_Script_Base
559
-                ) {
560
-                    // this script has been run, or at least started
561
-                    $script = $scripts_ran[ $script_converts_plugin_slug ][ $script_converts_to_version ];
562
-                    if ($script->get_status() !== self::status_completed) {
563
-                        // this script is already underway... keep going with it
564
-                        $script_classes_that_should_run_per_iteration[ $iteration ][ $script->priority() ][] = $script;
565
-                        $migrates_to_version                                                                 =
566
-                            $script->migrates_to_version();
567
-                        $next_database_state_to_consider[ $migrates_to_version['slug'] ]                     =
568
-                            $migrates_to_version['version'];
569
-                        unset($script_class_and_filepaths_available[ $classname ]);
570
-                    }
571
-                    // else it must have a status that indicates it has finished,
572
-                    // so we don't want to try and run it again
573
-                }
574
-                // else it exists, but it's not  a proper data migration script maybe the script got renamed?
575
-                // or was simply removed from EE? either way, it's certainly not runnable!
576
-            }
577
-            $iteration++;
578
-        } while ($next_database_state_to_consider !== $theoretical_database_state && $iteration < 6);
579
-        // ok we have all the scripts that should run, now let's make them into flat array
580
-        $scripts_that_should_run = [];
581
-        foreach ($script_classes_that_should_run_per_iteration as $scripts_at_priority) {
582
-            ksort($scripts_at_priority);
583
-            foreach ($scripts_at_priority as $scripts) {
584
-                foreach ($scripts as $script) {
585
-                    $scripts_that_should_run[ get_class($script) ] = $script;
586
-                }
587
-            }
588
-        }
589
-
590
-        do_action(
591
-            'AHEE__EE_Data_Migration_Manager__check_for_applicable_data_migration_scripts__scripts_that_should_run',
592
-            $scripts_that_should_run
593
-        );
594
-        return $scripts_that_should_run;
595
-    }
596
-
597
-
598
-    /**
599
-     * Gets the script which is currently being run, if there is one. If $include_completed_scripts is set to TRUE
600
-     * it will return the last run script even if it's complete.
601
-     * This means: if you want to find the currently-executing script, leave it as FALSE.
602
-     * If you really just want to find the script which ran most recently, regardless of status, leave it as TRUE.
603
-     *
604
-     * @param bool $include_completed_scripts
605
-     * @return EE_Data_Migration_Script_Base
606
-     * @throws EE_Error
607
-     */
608
-    public function get_last_ran_script($include_completed_scripts = false)
609
-    {
610
-        // make sure we've set up the class properties _last_ran_script and _last_ran_incomplete_script
611
-        if (! $this->_data_migrations_ran) {
612
-            $this->get_data_migrations_ran();
613
-        }
614
-        if ($include_completed_scripts) {
615
-            return $this->_last_ran_script;
616
-        } else {
617
-            return $this->_last_ran_incomplete_script;
618
-        }
619
-    }
620
-
621
-
622
-    /**
623
-     * Runs the data migration scripts (well, each request to this method calls one of the
624
-     * data migration scripts' migration_step() functions).
625
-     *
626
-     * @param int   $step_size
627
-     * @return array {
628
-     *                                  // where the first item is one EE_Data_Migration_Script_Base's stati,
629
-     *                                  //and the second item is a string describing what was done
630
-     * @type int    $records_to_migrate from the current migration script
631
-     * @type int    $records_migrated
632
-     * @type string $status             one of EE_Data_Migration_Manager::status_*
633
-     * @type string $script             verbose name of the current DMS
634
-     * @type string $message            string describing what was done during this step
635
-     *                                  }
636
-     * @throws EE_Error
637
-     */
638
-    public function migration_step($step_size = 0)
639
-    {
640
-
641
-        // bandaid fix for issue https://events.codebasehq.com/projects/event-espresso/tickets/7535
642
-        if (class_exists('EE_CPT_Strategy')) {
643
-            remove_action('pre_get_posts', [EE_CPT_Strategy::instance(), 'pre_get_posts'], 5);
644
-        }
645
-
646
-        try {
647
-            $currently_executing_script = $this->get_last_ran_script();
648
-            if (! $currently_executing_script) {
649
-                // Find the next script that needs to execute
650
-                $scripts = $this->check_for_applicable_data_migration_scripts();
651
-                if (! $scripts) {
652
-                    // huh, no more scripts to run... apparently we're done!
653
-                    // but don't forget to make sure initial data is there
654
-                    // we should be good to allow them to exit maintenance mode now
655
-                    EE_Maintenance_Mode::instance()->set_maintenance_level(
656
-                        EE_Maintenance_Mode::level_0_not_in_maintenance
657
-                    );
658
-                    // saving migrations run should actually be unnecessary,
659
-                    // but leaving in place just in case... remember this migration was finished
660
-                    // (even if we time out while initializing db for core and plugins)
661
-                    $this->_save_migrations_ran();
662
-                    // make sure DB was updated AFTER we've recorded the migration was done
663
-                    $this->initialize_db_for_enqueued_ee_plugins();
664
-                    return [
665
-                        'records_to_migrate' => 1,
666
-                        'records_migrated'   => 1,
667
-                        'status'             => self::status_no_more_migration_scripts,
668
-                        'script'             => esc_html__("Data Migration Completed Successfully", "event_espresso"),
669
-                        'message'            => esc_html__("All done!", "event_espresso"),
670
-                    ];
671
-                }
672
-                $currently_executing_script = array_shift($scripts);
673
-                // and add to the array/wp option showing the scripts run
674
-
675
-                $migrates_to                                            =
676
-                    $this->script_migrates_to_version(get_class($currently_executing_script));
677
-                $plugin_slug                                            = $migrates_to['slug'];
678
-                $version                                                = $migrates_to['version'];
679
-                $this->_data_migrations_ran[ $plugin_slug ][ $version ] = $currently_executing_script;
680
-            }
681
-            $current_script_name = get_class($currently_executing_script);
682
-        } catch (Exception $e) {
683
-            // an exception occurred while trying to get migration scripts
684
-
685
-            $message = sprintf(
686
-                esc_html__("Error Message: %sStack Trace:%s", "event_espresso"),
687
-                $e->getMessage() . '<br>',
688
-                $e->getTraceAsString()
689
-            );
690
-            // record it on the array of data migration scripts run. This will be overwritten next time we try and try to run data migrations
691
-            // but that's ok-- it's just an FYI to support that we couldn't even run any data migrations
692
-            $this->add_error_to_migrations_ran(
693
-                sprintf(esc_html__("Could not run data migrations because: %s", "event_espresso"), $message)
694
-            );
695
-            return [
696
-                'records_to_migrate' => 1,
697
-                'records_migrated'   => 0,
698
-                'status'             => self::status_fatal_error,
699
-                'script'             => esc_html__("Error loading data migration scripts", "event_espresso"),
700
-                'message'            => $message,
701
-            ];
702
-        }
703
-        // can we wrap it up and verify default data?
704
-        $init_dbs = false;
705
-        // ok so we definitely have a data migration script
706
-        try {
707
-            // how big of a bite do we want to take? Allow users to easily override via their wp-config
708
-            if (absint($step_size) < 1) {
709
-                $step_size = defined('EE_MIGRATION_STEP_SIZE') && absint(EE_MIGRATION_STEP_SIZE)
710
-                    ? EE_MIGRATION_STEP_SIZE
711
-                    : EE_Data_Migration_Manager::step_size;
712
-            }
713
-            // do what we came to do!
714
-            $currently_executing_script->migration_step($step_size);
715
-            switch ($currently_executing_script->get_status()) {
716
-                case EE_Data_Migration_Manager::status_continue:
717
-                    $response_array = [
718
-                        'records_to_migrate' => $currently_executing_script->count_records_to_migrate(),
719
-                        'records_migrated'   => $currently_executing_script->count_records_migrated(),
720
-                        'status'             => EE_Data_Migration_Manager::status_continue,
721
-                        'message'            => $currently_executing_script->get_feedback_message(),
722
-                        'script'             => $currently_executing_script->pretty_name(),
723
-                    ];
724
-                    break;
725
-                case EE_Data_Migration_Manager::status_completed:
726
-                    // ok so THAT script has completed
727
-                    $this->update_current_database_state_to($this->script_migrates_to_version($current_script_name));
728
-                    $response_array = [
729
-                        'records_to_migrate' => $currently_executing_script->count_records_to_migrate(),
730
-                        'records_migrated'   => $currently_executing_script->count_records_migrated(),
731
-                        'status'             => EE_Data_Migration_Manager::status_completed,
732
-                        'message'            => $currently_executing_script->get_feedback_message(),
733
-                        'script'             => sprintf(
734
-                            esc_html__("%s Completed", 'event_espresso'),
735
-                            $currently_executing_script->pretty_name()
736
-                        ),
737
-                    ];
738
-                    // check if there are any more after this one.
739
-                    $scripts_remaining = $this->check_for_applicable_data_migration_scripts();
740
-                    if (! $scripts_remaining) {
741
-                        // we should be good to allow them to exit maintenance mode now
742
-                        EE_Maintenance_Mode::instance()->set_maintenance_level(
743
-                            EE_Maintenance_Mode::level_0_not_in_maintenance
744
-                        );
745
-                        // huh, no more scripts to run... apparently we're done!
746
-                        // but don't forget to make sure initial data is there
747
-                        $init_dbs                 = true;
748
-                        $response_array['status'] = self::status_no_more_migration_scripts;
749
-                    }
750
-                    break;
751
-                default:
752
-                    $response_array = [
753
-                        'records_to_migrate' => $currently_executing_script->count_records_to_migrate(),
754
-                        'records_migrated'   => $currently_executing_script->count_records_migrated(),
755
-                        'status'             => $currently_executing_script->get_status(),
756
-                        'message'            => sprintf(
757
-                            esc_html__("Minor errors occurred during %s: %s", "event_espresso"),
758
-                            $currently_executing_script->pretty_name(),
759
-                            implode(", ", $currently_executing_script->get_errors())
760
-                        ),
761
-                        'script'             => $currently_executing_script->pretty_name(),
762
-                    ];
763
-                    break;
764
-            }
765
-        } catch (Exception $e) {
766
-            // ok so some exception was thrown which killed the data migration script
767
-            // double-check we have a real script
768
-            if ($currently_executing_script instanceof EE_Data_Migration_Script_Base) {
769
-                $script_name = $currently_executing_script->pretty_name();
770
-                $currently_executing_script->set_broken();
771
-                $currently_executing_script->add_error($e->getMessage());
772
-            } else {
773
-                $script_name = esc_html__("Error getting Migration Script", "event_espresso");
774
-            }
775
-            $response_array = [
776
-                'records_to_migrate' => 1,
777
-                'records_migrated'   => 0,
778
-                'status'             => self::status_fatal_error,
779
-                'message'            => sprintf(
780
-                    esc_html__("A fatal error occurred during the migration: %s", "event_espresso"),
781
-                    $e->getMessage()
782
-                ),
783
-                'script'             => $script_name,
784
-            ];
785
-        }
786
-        $successful_save = $this->_save_migrations_ran();
787
-        if ($successful_save !== true) {
788
-            // ok so the current wp option didn't save. that's tricky, because we'd like to update it
789
-            // and mark it as having a fatal error, but remember- WE CAN'T SAVE THIS WP OPTION!
790
-            // however, if we throw an exception, and return that, then the next request
791
-            // won't have as much info in it, and it may be able to save
792
-            throw new EE_Error(
793
-                sprintf(
794
-                    esc_html__(
795
-                        "The error '%s' occurred updating the status of the migration. This is a FATAL ERROR, but the error is preventing the system from remembering that. Please contact event espresso support.",
796
-                        "event_espresso"
797
-                    ),
798
-                    $successful_save
799
-                )
800
-            );
801
-        }
802
-        // if we're all done, initialize EE plugins' default data etc.
803
-        if ($init_dbs) {
804
-            $this->initialize_db_for_enqueued_ee_plugins();
805
-        }
806
-        return $response_array;
807
-    }
808
-
809
-
810
-    /**
811
-     * Echo out JSON response to migration script AJAX requests. Takes precautions
812
-     * to buffer output so that we don't throw junk into our json.
813
-     *
814
-     * @return array with keys:
815
-     * 'records_to_migrate' which counts ALL the records for the current migration, and should remain constant. (ie,
816
-     * it's NOT the count of hwo many remain)
817
-     * 'records_migrated' which also counts ALL the records which have been migrated (ie, percent_complete =
818
-     * records_migrated/records_to_migrate)
819
-     * 'status'=>a string, one of EE_Data_migration_Manager::status_*
820
-     * 'message'=>a string, containing any message you want to show to the user. We may decide to split this up into
821
-     * errors, notifications, and successes
822
-     * 'script'=>a pretty name of the script currently running
823
-     */
824
-    public function response_to_migration_ajax_request()
825
-    {
826
-        ob_start();
827
-        try {
828
-            $response = $this->migration_step();
829
-        } catch (Exception $e) {
830
-            $response = [
831
-                'records_to_migrate' => 0,
832
-                'records_migrated'   => 0,
833
-                'status'             => EE_Data_Migration_Manager::status_fatal_error,
834
-                'message'            => sprintf(
835
-                    esc_html__("Unknown fatal error occurred: %s", "event_espresso"),
836
-                    $e->getMessage()
837
-                ),
838
-                'script'             => 'Unknown',
839
-            ];
840
-            $this->add_error_to_migrations_ran($e->getMessage() . "; Stack trace:" . $e->getTraceAsString());
841
-        }
842
-        $warnings_etc = @ob_get_contents();
843
-        ob_end_clean();
844
-        $response['message'] .= $warnings_etc;
845
-        return $response;
846
-    }
847
-
848
-
849
-    /**
850
-     * Updates the WordPress option that keeps track of which EE version the database
851
-     * is at (ie, the code may be at 4.1.0, but the database is still at 3.1.35)
852
-     *
853
-     * @param array $slug_and_version {
854
-     * @type string $slug             like 'Core' or 'Calendar',
855
-     * @type string $version          like '4.1.0'
856
-     *                                }
857
-     * @return void
858
-     */
859
-    public function update_current_database_state_to($slug_and_version = null)
860
-    {
861
-        if (! $slug_and_version) {
862
-            // no version was provided, assume it should be at the current code version
863
-            $slug_and_version = ['slug' => 'Core', 'version' => espresso_version()];
864
-        }
865
-        $current_database_state                              = get_option(self::current_database_state);
866
-        $current_database_state[ $slug_and_version['slug'] ] = $slug_and_version['version'];
867
-        update_option(self::current_database_state, $current_database_state);
868
-    }
869
-
870
-
871
-    /**
872
-     * Determines if the database is currently at a state matching what's indicated in $slug and $version.
873
-     *
874
-     * @param array $slug_and_version {
875
-     * @type string $slug             like 'Core' or 'Calendar',
876
-     * @type string $version          like '4.1.0'
877
-     *                                }
878
-     * @return boolean
879
-     */
880
-    public function database_needs_updating_to($slug_and_version)
881
-    {
882
-
883
-        $slug                   = $slug_and_version['slug'];
884
-        $version                = $slug_and_version['version'];
885
-        $current_database_state = get_option(self::current_database_state);
886
-        if (! isset($current_database_state[ $slug ])) {
887
-            return true;
888
-        } else {
889
-            // just compare the first 3 parts of version string, eg "4.7.1", not "4.7.1.dev.032" because DBs shouldn't change on nano version changes
890
-            $version_parts_current_db_state     = array_slice(explode('.', $current_database_state[ $slug ]), 0, 3);
891
-            $version_parts_of_provided_db_state = array_slice(explode('.', $version), 0, 3);
892
-            $needs_updating                     = false;
893
-            foreach ($version_parts_current_db_state as $offset => $version_part_in_current_db_state) {
894
-                if ($version_part_in_current_db_state < $version_parts_of_provided_db_state[ $offset ]) {
895
-                    $needs_updating = true;
896
-                    break;
897
-                }
898
-            }
899
-            return $needs_updating;
900
-        }
901
-    }
902
-
903
-
904
-    /**
905
-     * Gets all the data migration scripts available in the core folder and folders
906
-     * in addons. Has the side effect of adding them for autoloading
907
-     *
908
-     * @return array keys are expected classnames, values are their filepaths
909
-     * @throws InvalidInterfaceException
910
-     * @throws InvalidDataTypeException
911
-     * @throws EE_Error
912
-     * @throws InvalidArgumentException
913
-     */
914
-    public function get_all_data_migration_scripts_available()
915
-    {
916
-        if (! $this->_data_migration_class_to_filepath_map) {
917
-            $this->_data_migration_class_to_filepath_map = [];
918
-            foreach ($this->get_data_migration_script_folders() as $eeAddonClass => $folder_path) {
919
-                // strip any placeholders added to classname to make it a unique array key
920
-                $eeAddonClass = trim($eeAddonClass, '*');
921
-                $eeAddonClass = $eeAddonClass === 'Core' || class_exists($eeAddonClass)
922
-                    ? $eeAddonClass
923
-                    : '';
924
-                $folder_path  = EEH_File::end_with_directory_separator($folder_path);
925
-                $files        = glob($folder_path . '*.dms.php');
926
-                if (empty($files)) {
927
-                    continue;
928
-                }
929
-                foreach ($files as $file) {
930
-                    $pos_of_last_slash = strrpos($file, '/');
931
-                    $classname         = str_replace('.dms.php', '', substr($file, $pos_of_last_slash + 1));
932
-                    $migrates_to       = $this->script_migrates_to_version($classname, $eeAddonClass);
933
-                    $slug              = $migrates_to['slug'];
934
-                    // check that the slug as contained in the DMS is associated with
935
-                    // the slug of an addon or core
936
-                    if ($slug !== 'Core' && EE_Registry::instance()->get_addon_by_name($slug) === null) {
937
-                        EE_Error::doing_it_wrong(
938
-                            __FUNCTION__,
939
-                            sprintf(
940
-                                esc_html__(
941
-                                    'The data migration script "%s" migrates the "%s" data, but there is no EE addon with that name. There is only: %s. ',
942
-                                    'event_espresso'
943
-                                ),
944
-                                $classname,
945
-                                $slug,
946
-                                implode(', ', array_keys(EE_Registry::instance()->get_addons_by_name()))
947
-                            ),
948
-                            '4.3.0.alpha.019'
949
-                        );
950
-                    }
951
-                    $this->_data_migration_class_to_filepath_map[ $classname ] = $file;
952
-                }
953
-            }
954
-            EEH_Autoloader::register_autoloader($this->_data_migration_class_to_filepath_map);
955
-        }
956
-        return $this->_data_migration_class_to_filepath_map;
957
-    }
958
-
959
-
960
-    /**
961
-     * Once we have an addon that works with EE4.1, we will actually want to fetch the PUE slugs
962
-     * from each addon, and check if they need updating,
963
-     *
964
-     * @return boolean
965
-     */
966
-    public function addons_need_updating()
967
-    {
968
-        return false;
969
-    }
970
-
971
-
972
-    /**
973
-     * Adds this error string to the data_migrations_ran array, but we don't necessarily know
974
-     * where to put it, so we just throw it in there... better than nothing...
975
-     *
976
-     * @param string $error_message
977
-     */
978
-    public function add_error_to_migrations_ran($error_message)
979
-    {
980
-        // get last-run migration script
981
-        global $wpdb;
982
-        $last_migration_script_option = $wpdb->get_row(
983
-            "SELECT * FROM $wpdb->options WHERE option_name like '"
984
-            . EE_Data_Migration_Manager::data_migration_script_option_prefix
985
-            . "%' ORDER BY option_id DESC LIMIT 1",
986
-            ARRAY_A
987
-        );
988
-
989
-        $last_ran_migration_script_properties = isset($last_migration_script_option['option_value'])
990
-            ? maybe_unserialize($last_migration_script_option['option_value']) : null;
991
-        // now, tread lightly because we're here because a FATAL non-catchable error
992
-        // was thrown last time when we were trying to run a data migration script
993
-        // so the fatal error could have happened while getting the migration script
994
-        // or doing running it...
995
-        $versions_migrated_to = isset($last_migration_script_option['option_name']) ? str_replace(
996
-            EE_Data_Migration_Manager::data_migration_script_option_prefix,
997
-            "",
998
-            $last_migration_script_option['option_name']
999
-        ) : null;
1000
-
1001
-        // check if it THINKS it's a data migration script and especially if it's one that HASN'T finished yet
1002
-        // because if it has finished, then it obviously couldn't be the cause of this error, right? (because it's all done)
1003
-        if (
1004
-            isset($last_ran_migration_script_properties['class'])
1005
-            && isset($last_ran_migration_script_properties['_status'])
1006
-            && $last_ran_migration_script_properties['_status'] != self::status_completed
1007
-        ) {
1008
-            // ok then just add this error to its list of errors
1009
-            $last_ran_migration_script_properties['_errors'][] = $error_message;
1010
-            $last_ran_migration_script_properties['_status']   = self::status_fatal_error;
1011
-        } else {
1012
-            // so we don't even know which script was last running
1013
-            // use the data migration error stub, which is designed specifically for this type of thing
1014
-            $general_migration_error = new EE_DMS_Unknown_1_0_0();
1015
-            $general_migration_error->add_error($error_message);
1016
-            $general_migration_error->set_broken();
1017
-            $last_ran_migration_script_properties = $general_migration_error->properties_as_array();
1018
-            $versions_migrated_to                 = 'Unknown.1.0.0';
1019
-            // now just to make sure appears as last (in case the were previously a fatal error like this)
1020
-            // delete the old one
1021
-            delete_option(self::data_migration_script_option_prefix . $versions_migrated_to);
1022
-        }
1023
-        update_option(
1024
-            self::data_migration_script_option_prefix . $versions_migrated_to,
1025
-            $last_ran_migration_script_properties
1026
-        );
1027
-    }
1028
-
1029
-
1030
-    /**
1031
-     * saves what data migrations have run to the database
1032
-     *
1033
-     * @return bool|string TRUE if successfully saved migrations ran, string if an error occurred
1034
-     * @throws EE_Error
1035
-     */
1036
-    protected function _save_migrations_ran()
1037
-    {
1038
-        if ($this->_data_migrations_ran == null) {
1039
-            $this->get_data_migrations_ran();
1040
-        }
1041
-        // now, we don't want to save actual classes to the DB because that's messy
1042
-        $successful_updates = true;
1043
-        foreach ($this->_data_migrations_ran as $plugin_slug => $migrations_ran_for_plugin) {
1044
-            foreach ($migrations_ran_for_plugin as $version_string => $array_or_migration_obj) {
1045
-                $plugin_slug_for_use_in_option_name = $plugin_slug . ".";
1046
-                $option_name                        =
1047
-                    self::data_migration_script_option_prefix . $plugin_slug_for_use_in_option_name . $version_string;
1048
-                $old_option_value                   = get_option($option_name);
1049
-                if ($array_or_migration_obj instanceof EE_Data_Migration_Script_Base) {
1050
-                    $script_array_for_saving = $array_or_migration_obj->properties_as_array();
1051
-                    if ($old_option_value != $script_array_for_saving) {
1052
-                        $successful_updates = update_option($option_name, $script_array_for_saving);
1053
-                    }
1054
-                } else {// we don't know what this array-thing is. So just save it as-is
1055
-                    if ($old_option_value != $array_or_migration_obj) {
1056
-                        $successful_updates = update_option($option_name, $array_or_migration_obj);
1057
-                    }
1058
-                }
1059
-                if (! $successful_updates) {
1060
-                    global $wpdb;
1061
-                    return $wpdb->last_error;
1062
-                }
1063
-            }
1064
-        }
1065
-        return true;
1066
-        // $updated = update_option(self::data_migrations_option_name, $array_of_migrations);
1067
-        // if ($updated !== true) {
1068
-        //     global $wpdb;
1069
-        //     return $wpdb->last_error;
1070
-        // } else {
1071
-        //     return true;
1072
-        // }
1073
-        // wp_mail(
1074
-        //     "[email protected]",
1075
-        //     time() . " price debug info",
1076
-        //     "updated: $updated, last error: $last_error, byte length of option: " . strlen(
1077
-        //         serialize($array_of_migrations)
1078
-        //     )
1079
-        // );
1080
-    }
1081
-
1082
-
1083
-    /**
1084
-     * Takes an array of data migration script properties and re-creates the class from
1085
-     * them. The argument $properties_array is assumed to have been made by
1086
-     * EE_Data_Migration_Script_Base::properties_as_array()
1087
-     *
1088
-     * @param array $properties_array
1089
-     * @return EE_Data_Migration_Script_Base
1090
-     * @throws EE_Error
1091
-     */
1092
-    public function _instantiate_script_from_properties_array($properties_array)
1093
-    {
1094
-        if (! isset($properties_array['class'])) {
1095
-            throw new EE_Error(
1096
-                sprintf(
1097
-                    esc_html__("Properties array  has no 'class' properties. Here's what it has: %s", "event_espresso"),
1098
-                    implode(",", $properties_array)
1099
-                )
1100
-            );
1101
-        }
1102
-        $class_name = $properties_array['class'];
1103
-        if (! class_exists($class_name)) {
1104
-            throw new EE_Error(sprintf(
1105
-                esc_html__("There is no migration script named %s", "event_espresso"),
1106
-                $class_name
1107
-            ));
1108
-        }
1109
-        $class = new $class_name();
1110
-        if (! $class instanceof EE_Data_Migration_Script_Base) {
1111
-            throw new EE_Error(
1112
-                sprintf(
1113
-                    esc_html__(
1114
-                        "Class '%s' is supposed to be a migration script. Its not, its a '%s'",
1115
-                        "event_espresso"
1116
-                    ),
1117
-                    $class_name,
1118
-                    get_class($class)
1119
-                )
1120
-            );
1121
-        }
1122
-        $class->instantiate_from_array_of_properties($properties_array);
1123
-        return $class;
1124
-    }
1125
-
1126
-
1127
-    /**
1128
-     * Gets the classname for the most up-to-date DMS (ie, the one that will finally
1129
-     * leave the DB in a state usable by the current plugin code).
1130
-     *
1131
-     * @param string $plugin_slug the slug for the ee plugin we are searching for. Default is 'Core'
1132
-     * @return string
1133
-     * @throws EE_Error
1134
-     * @throws EE_Error
1135
-     */
1136
-    public function get_most_up_to_date_dms($plugin_slug = 'Core')
1137
-    {
1138
-        $class_to_filepath_map         = $this->get_all_data_migration_scripts_available();
1139
-        $most_up_to_date_dms_classname = null;
1140
-        foreach ($class_to_filepath_map as $classname => $filepath) {
1141
-            if ($most_up_to_date_dms_classname === null) {
1142
-                $migrates_to      = $this->script_migrates_to_version($classname);
1143
-                $this_plugin_slug = $migrates_to['slug'];
1144
-                if ($this_plugin_slug == $plugin_slug) {
1145
-                    // if it's for core, it wins
1146
-                    $most_up_to_date_dms_classname = $classname;
1147
-                }
1148
-                // if it wasn't for core, we must keep searching for one that is!
1149
-                continue;
1150
-            }
1151
-            $champion_migrates_to  = $this->script_migrates_to_version($most_up_to_date_dms_classname);
1152
-            $contender_migrates_to = $this->script_migrates_to_version($classname);
1153
-            if (
1154
-                $contender_migrates_to['slug'] == $plugin_slug
1155
-                && version_compare(
1156
-                    $champion_migrates_to['version'],
1157
-                    $contender_migrates_to['version'],
1158
-                    '<'
1159
-                )
1160
-            ) {
1161
-                // so the contenders version is higher, and it's for Core
1162
-                $most_up_to_date_dms_classname = $classname;
1163
-            }
1164
-        }
1165
-        return $most_up_to_date_dms_classname;
1166
-    }
1167
-
1168
-
1169
-    /**
1170
-     * Gets the migration script specified but ONLY if it has already run.
1171
-     *
1172
-     * Eg, if you wanted to see if 'EE_DMS_Core_4_1_0' has run, you would run the following code:
1173
-     * <code> $core_4_1_0_dms_ran = EE_Data_Migration_Manager::instance()->get_migration_ran( '4.1.0', 'Core' ) !==
1174
-     * NULL;</code> This is especially useful in addons' data migration scripts, this way they can tell if a core (or
1175
-     * other addon) DMS has run, in case the current DMS depends on it.
1176
-     *
1177
-     * @param string $version     the version the DMS searched for migrates to. Usually just the content before the 3rd
1178
-     *                            period. Eg '4.1.0'
1179
-     * @param string $plugin_slug like 'Core', 'Mailchimp', 'Calendar', etc
1180
-     * @return EE_Data_Migration_Script_Base
1181
-     * @throws EE_Error
1182
-     */
1183
-    public function get_migration_ran($version, $plugin_slug = 'Core')
1184
-    {
1185
-        $migrations_ran = $this->get_data_migrations_ran();
1186
-        if (isset($migrations_ran[ $plugin_slug ]) && isset($migrations_ran[ $plugin_slug ][ $version ])) {
1187
-            return $migrations_ran[ $plugin_slug ][ $version ];
1188
-        } else {
1189
-            return null;
1190
-        }
1191
-    }
1192
-
1193
-
1194
-    /**
1195
-     * Resets the borked data migration scripts, so they're no longer borked, and we can again attempt to migrate
1196
-     *
1197
-     * @return bool
1198
-     * @throws EE_Error
1199
-     */
1200
-    public function reattempt()
1201
-    {
1202
-        // find if the last-run script was borked
1203
-        // set it as being non-borked (we shouldn't ever get DMSs that we don't recognize)
1204
-        // add an 'error' saying that we attempted to reset
1205
-        // does it have a stage that was borked too? if so make it no longer borked
1206
-        // add an 'error' saying we attempted to reset
1207
-        $last_ran_script = $this->get_last_ran_script();
1208
-        if ($last_ran_script instanceof EE_DMS_Unknown_1_0_0) {
1209
-            // if it was an error DMS, just mark it as complete (if another error occurs it will overwrite it)
1210
-            $last_ran_script->set_completed();
1211
-        } elseif ($last_ran_script instanceof EE_Data_Migration_Script_Base) {
1212
-            $last_ran_script->reattempt();
1213
-        } else {
1214
-            throw new EE_Error(
1215
-                sprintf(
1216
-                    esc_html__(
1217
-                        'Unable to reattempt the last ran migration script because it was not a valid migration script. || It was %s',
1218
-                        'event_espresso'
1219
-                    ),
1220
-                    print_r($last_ran_script, true)
1221
-                )
1222
-            );
1223
-        }
1224
-        return $this->_save_migrations_ran();
1225
-    }
1226
-
1227
-
1228
-    /**
1229
-     * Gets whether this particular migration has run or not
1230
-     *
1231
-     * @param string $version     the version the DMS searched for migrates to. Usually just the content before the 3rd
1232
-     *                            period. Eg '4.1.0'
1233
-     * @param string $plugin_slug like 'Core', 'Mailchimp', 'Calendar', etc
1234
-     * @return boolean
1235
-     * @throws EE_Error
1236
-     */
1237
-    public function migration_has_ran($version, $plugin_slug = 'Core')
1238
-    {
1239
-        return $this->get_migration_ran($version, $plugin_slug) !== null;
1240
-    }
1241
-
1242
-
1243
-    /**
1244
-     * Enqueues this ee plugin to have its data initialized
1245
-     *
1246
-     * @param string $plugin_slug either 'Core' or EE_Addon::name()'s return value
1247
-     */
1248
-    public function enqueue_db_initialization_for($plugin_slug)
1249
-    {
1250
-        $queue = $this->get_db_initialization_queue();
1251
-        if (! in_array($plugin_slug, $queue)) {
1252
-            $queue[] = $plugin_slug;
1253
-        }
1254
-        update_option(self::db_init_queue_option_name, $queue);
1255
-    }
1256
-
1257
-
1258
-    /**
1259
-     * Calls EE_Addon::initialize_db_if_no_migrations_required() on each addon
1260
-     * specified in EE_Data_Migration_Manager::get_db_init_queue(), and if 'Core' is
1261
-     * in the queue, calls EE_System::initialize_db_if_no_migrations_required().
1262
-     *
1263
-     * @throws EE_Error
1264
-     */
1265
-    public function initialize_db_for_enqueued_ee_plugins()
1266
-    {
1267
-        $queue = $this->get_db_initialization_queue();
1268
-        foreach ($queue as $plugin_slug) {
1269
-            $most_up_to_date_dms = $this->get_most_up_to_date_dms($plugin_slug);
1270
-            if (! $most_up_to_date_dms) {
1271
-                // if there is NO DMS for this plugin, obviously there's no schema to verify anyways
1272
-                $verify_db = false;
1273
-            } else {
1274
-                $most_up_to_date_dms_migrates_to = $this->script_migrates_to_version($most_up_to_date_dms);
1275
-                $verify_db                       = $this->database_needs_updating_to($most_up_to_date_dms_migrates_to);
1276
-            }
1277
-            if ($plugin_slug == 'Core') {
1278
-                EE_System::instance()->initialize_db_if_no_migrations_required(
1279
-                    false,
1280
-                    $verify_db
1281
-                );
1282
-            } else {
1283
-                // just loop through the addons to make sure their database is set up
1284
-                foreach (EE_Registry::instance()->addons as $addon) {
1285
-                    if ($addon->name() == $plugin_slug) {
1286
-                        $addon->initialize_db_if_no_migrations_required($verify_db);
1287
-                        break;
1288
-                    }
1289
-                }
1290
-            }
1291
-        }
1292
-        // because we just initialized the DBs for the enqueued ee plugins
1293
-        // we don't need to keep remembering which ones needed to be initialized
1294
-        delete_option(self::db_init_queue_option_name);
1295
-    }
1296
-
1297
-
1298
-    /**
1299
-     * Gets a numerically-indexed array of plugin slugs that need to have their databases
1300
-     * (re-)initialized after migrations are complete. ie, each element should be either
1301
-     * 'Core', or the return value of EE_Addon::name() for an addon
1302
-     *
1303
-     * @return array
1304
-     */
1305
-    public function get_db_initialization_queue()
1306
-    {
1307
-        return get_option(self::db_init_queue_option_name, []);
1308
-    }
1309
-
1310
-
1311
-    /**
1312
-     * Gets the injected table analyzer, or throws an exception
1313
-     *
1314
-     * @return TableAnalysis
1315
-     * @throws EE_Error
1316
-     */
1317
-    protected function _get_table_analysis()
1318
-    {
1319
-        if ($this->_table_analysis instanceof TableAnalysis) {
1320
-            return $this->_table_analysis;
1321
-        } else {
1322
-            throw new EE_Error(
1323
-                sprintf(
1324
-                    esc_html__('Table analysis class on class %1$s is not set properly.', 'event_espresso'),
1325
-                    get_class($this)
1326
-                )
1327
-            );
1328
-        }
1329
-    }
1330
-
1331
-
1332
-    /**
1333
-     * Gets the injected table manager, or throws an exception
1334
-     *
1335
-     * @return TableManager
1336
-     * @throws EE_Error
1337
-     */
1338
-    protected function _get_table_manager()
1339
-    {
1340
-        if ($this->_table_manager instanceof TableManager) {
1341
-            return $this->_table_manager;
1342
-        } else {
1343
-            throw new EE_Error(
1344
-                sprintf(
1345
-                    esc_html__('Table manager class on class %1$s is not set properly.', 'event_espresso'),
1346
-                    get_class($this)
1347
-                )
1348
-            );
1349
-        }
1350
-    }
35
+	/**
36
+	 *
37
+	 * @var EE_Registry
38
+	 */
39
+	// protected $EE;
40
+	/**
41
+	 * name of the WordPress option which stores an array of data about
42
+	 */
43
+	const data_migrations_option_name = 'ee_data_migration';
44
+
45
+
46
+	const data_migration_script_option_prefix         = 'ee_data_migration_script_';
47
+
48
+	const data_migration_script_mapping_option_prefix = 'ee_dms_map_';
49
+
50
+	/**
51
+	 * name of the WordPress option which stores the database' current version. IE, the code may be at version 4.2.0,
52
+	 * but as migrations are performed the database will progress from 3.1.35 to 4.1.0 etc.
53
+	 */
54
+	const current_database_state = 'ee_data_migration_current_db_state';
55
+
56
+	/**
57
+	 * Special status string returned when we're positive there are no more data migration
58
+	 * scripts that can be run.
59
+	 */
60
+	const status_no_more_migration_scripts = 'no_more_migration_scripts';
61
+
62
+	/**
63
+	 * string indicating the migration should continue
64
+	 */
65
+	const status_continue = 'status_continue';
66
+
67
+	/**
68
+	 * string indicating the migration has completed and should be ended
69
+	 */
70
+	const status_completed = 'status_completed';
71
+
72
+	/**
73
+	 * string indicating a fatal error occurred and the data migration should be completely aborted
74
+	 */
75
+	const status_fatal_error = 'status_fatal_error';
76
+
77
+	/**
78
+	 * the number of 'items' (usually DB rows) to migrate on each 'step' (ajax request sent
79
+	 * during migration)
80
+	 */
81
+	const step_size = 50;
82
+
83
+	/**
84
+	 * option name that stores the queue of ee plugins needing to have
85
+	 * their data initialized (or re-initialized) once we are done migrations
86
+	 */
87
+	const db_init_queue_option_name = 'ee_db_init_queue';
88
+
89
+	/**
90
+	 * Array of information concerning data migrations that have run in the history
91
+	 * of this EE installation. Keys should be the name of the version the script upgraded to
92
+	 *
93
+	 * @var EE_Data_Migration_Script_Base[]
94
+	 */
95
+	private $_data_migrations_ran = null;
96
+
97
+	/**
98
+	 * The last run script. It's nice to store this somewhere accessible, as its easiest
99
+	 * to know which was the last run by which is the newest wp option; but in most of the code
100
+	 * we just use the local $_data_migration_ran array, which organized the scripts differently
101
+	 *
102
+	 * @var EE_Data_Migration_Script_Base
103
+	 */
104
+	private $_last_ran_script = null;
105
+
106
+	/**
107
+	 * Similarly to _last_ran_script, but this is the last INCOMPLETE migration script.
108
+	 *
109
+	 * @var EE_Data_Migration_Script_Base
110
+	 */
111
+	private $_last_ran_incomplete_script = null;
112
+
113
+	/**
114
+	 * array where keys are classnames, and values are filepaths of all the known migration scripts
115
+	 *
116
+	 * @var array
117
+	 */
118
+	private $_data_migration_class_to_filepath_map;
119
+
120
+	/**
121
+	 * the following 4 properties are fully set on construction.
122
+	 * Note: the first two apply to whether to continue running ALL migration scripts (ie, even though we're finished
123
+	 * one, we may want to start the next one); whereas the last two indicate whether to continue running a single
124
+	 * data migration script
125
+	 *
126
+	 * @var array
127
+	 */
128
+	public $stati_that_indicate_to_continue_migrations              = [];
129
+
130
+	public $stati_that_indicate_to_stop_migrations                  = [];
131
+
132
+	public $stati_that_indicate_to_continue_single_migration_script = [];
133
+
134
+	public $stati_that_indicate_to_stop_single_migration_script     = [];
135
+
136
+	/**
137
+	 * @var TableManager $table_manager
138
+	 */
139
+	protected $_table_manager;
140
+
141
+	/**
142
+	 * @var TableAnalysis $table_analysis
143
+	 */
144
+	protected $_table_analysis;
145
+
146
+	/**
147
+	 * @var array $script_migration_versions
148
+	 */
149
+	protected $script_migration_versions;
150
+
151
+	/**
152
+	 * @var EE_Data_Migration_Manager $_instance
153
+	 * @access    private
154
+	 */
155
+	private static $_instance = null;
156
+
157
+
158
+	/**
159
+	 * @singleton method used to instantiate class object
160
+	 * @access    public
161
+	 * @return EE_Data_Migration_Manager instance
162
+	 */
163
+	public static function instance()
164
+	{
165
+		// check if class object is instantiated
166
+		if (! self::$_instance instanceof EE_Data_Migration_Manager) {
167
+			self::$_instance = new self();
168
+		}
169
+		return self::$_instance;
170
+	}
171
+
172
+
173
+	/**
174
+	 * resets the singleton to its brand-new state (but does NOT delete old references to the old singleton. Meaning,
175
+	 * all new usages of the singleton should be made with Classname::instance()) and returns it
176
+	 *
177
+	 * @return EE_Data_Migration_Manager
178
+	 */
179
+	public static function reset()
180
+	{
181
+		self::$_instance = null;
182
+		return self::instance();
183
+	}
184
+
185
+
186
+	/**
187
+	 * @throws EE_Error
188
+	 * @throws ReflectionException
189
+	 */
190
+	private function __construct()
191
+	{
192
+		$this->stati_that_indicate_to_continue_migrations              = [
193
+			self::status_continue,
194
+			self::status_completed,
195
+		];
196
+		$this->stati_that_indicate_to_stop_migrations                  = [
197
+			self::status_fatal_error,
198
+			self::status_no_more_migration_scripts,
199
+		];
200
+		$this->stati_that_indicate_to_continue_single_migration_script = [
201
+			self::status_continue,
202
+		];
203
+		$this->stati_that_indicate_to_stop_single_migration_script     = [
204
+			self::status_completed,
205
+			self::status_fatal_error
206
+			// note: status_no_more_migration_scripts doesn't apply
207
+		];
208
+		// make sure we've included the base migration script, because we may need the EE_DMS_Unknown_1_0_0 class
209
+		// to be defined, because right now it doesn't get autoloaded on its own
210
+		EE_Registry::instance()->load_core('Data_Migration_Class_Base', [], true);
211
+		EE_Registry::instance()->load_core('Data_Migration_Script_Base', [], true);
212
+		EE_Registry::instance()->load_core('DMS_Unknown_1_0_0', [], true);
213
+		EE_Registry::instance()->load_core('Data_Migration_Script_Stage', [], true);
214
+		EE_Registry::instance()->load_core('Data_Migration_Script_Stage_Table', [], true);
215
+		$this->_table_manager  = EE_Registry::instance()->create('TableManager', [], true);
216
+		$this->_table_analysis = EE_Registry::instance()->create('TableAnalysis', [], true);
217
+	}
218
+
219
+
220
+	/**
221
+	 * Deciphers, from an option's name, what plugin and version it relates to (see _save_migrations_ran to see what
222
+	 * the option names are like, but generally they're like
223
+	 * 'ee_data_migration_script_Core.4.1.0' in 4.2 or 'ee_data_migration_script_4.1.0' before that).
224
+	 * The option name shouldn't ever be like 'ee_data_migration_script_Core.4.1.0.reg' because it's derived,
225
+	 * indirectly, from the data migration's classname, which should always be like EE_DMS_%s_%d_%d_%d.dms.php
226
+	 * (ex: EE_DMS_Core_4_1_0.dms.php)
227
+	 *
228
+	 * @param string $option_name (see EE_Data_Migration_Manage::_save_migrations_ran() where the option name is set)
229
+	 * @return array where the first item is the plugin slug (eg 'Core','Calendar', etc.) and the 2nd is the version of
230
+	 *                            that plugin (eg '4.1.0')
231
+	 */
232
+	private function _get_plugin_slug_and_version_string_from_dms_option_name($option_name)
233
+	{
234
+		$plugin_slug_and_version_string = str_replace(
235
+			EE_Data_Migration_Manager::data_migration_script_option_prefix,
236
+			"",
237
+			$option_name
238
+		);
239
+		// check if $plugin_slug_and_version_string is like '4.1.0' (4.1-style) or 'Core.4.1.0' (4.2-style)
240
+		$parts = explode(".", $plugin_slug_and_version_string);
241
+
242
+		if (count($parts) == 4) {
243
+			// it's 4.2-style.eg Core.4.1.0
244
+			$plugin_slug    = $parts[0];                                     // eg Core
245
+			$version_string = $parts[1] . "." . $parts[2] . "." . $parts[3]; // eg 4.1.0
246
+		} else {
247
+			// it's 4.1-style: eg 4.1.0
248
+			$plugin_slug    = 'Core';
249
+			$version_string = $plugin_slug_and_version_string;// eg 4.1.0
250
+		}
251
+		return [$plugin_slug, $version_string];
252
+	}
253
+
254
+
255
+	/**
256
+	 * Gets the DMS class from the WordPress option, otherwise throws an EE_Error if it's not
257
+	 * for a known DMS class.
258
+	 *
259
+	 * @param string $dms_option_name
260
+	 * @param string $dms_option_value (serialized)
261
+	 * @return EE_Data_Migration_Script_Base
262
+	 * @throws EE_Error
263
+	 */
264
+	private function _get_dms_class_from_wp_option($dms_option_name, $dms_option_value)
265
+	{
266
+		$data_migration_data = maybe_unserialize($dms_option_value);
267
+		if (isset($data_migration_data['class']) && class_exists($data_migration_data['class'])) {
268
+			// During multisite migrations, it's possible we already grabbed another instance of this class
269
+			// but for a different blog. Make sure we don't reuse them (as they store info specific
270
+			// to their respective blog, like which database table to migrate).
271
+			$class = LoaderFactory::getLoader()->getNew($data_migration_data['class']);
272
+			if ($class instanceof EE_Data_Migration_Script_Base) {
273
+				$class->instantiate_from_array_of_properties($data_migration_data);
274
+				return $class;
275
+			} else {
276
+				// huh, so it's an object but not a data migration script?? that shouldn't happen
277
+				// just leave it as an array (which will probably just get ignored)
278
+				throw new EE_Error(
279
+					sprintf(
280
+						esc_html__(
281
+							"Trying to retrieve DMS class from wp option. No DMS by the name '%s' exists",
282
+							'event_espresso'
283
+						),
284
+						$data_migration_data['class']
285
+					)
286
+				);
287
+			}
288
+		} else {
289
+			// so the data doesn't specify a class. So it must either be a legacy array of info or some array (which we'll probably just ignore), or a class that no longer exists
290
+			throw new EE_Error(
291
+				sprintf(
292
+					esc_html__("The wp option  with key '%s' does not represent a DMS", 'event_espresso'),
293
+					$dms_option_name
294
+				)
295
+			);
296
+		}
297
+	}
298
+
299
+
300
+	/**
301
+	 * Gets the array describing what data migrations have run.
302
+	 * Also has a side effect of recording which was the last run,
303
+	 * and which was the last run which hasn't finished yet
304
+	 *
305
+	 * @return array where each element should be an array of EE_Data_Migration_Script_Base
306
+	 *               (but also has a few legacy arrays in there - which should probably be ignored)
307
+	 * @throws EE_Error
308
+	 */
309
+	public function get_data_migrations_ran()
310
+	{
311
+		if (! $this->_data_migrations_ran) {
312
+			// setup autoloaders for each of the scripts in there
313
+			$this->get_all_data_migration_scripts_available();
314
+			$data_migrations_options =
315
+				$this->get_all_migration_script_options();// get_option(EE_Data_Migration_Manager::data_migrations_option_name,get_option('espresso_data_migrations',array()));
316
+
317
+			$data_migrations_ran = [];
318
+			// convert into data migration script classes where possible
319
+			foreach ($data_migrations_options as $data_migration_option) {
320
+				list($plugin_slug, $version_string) = $this->_get_plugin_slug_and_version_string_from_dms_option_name(
321
+					$data_migration_option['option_name']
322
+				);
323
+
324
+				try {
325
+					$class                                                  = $this->_get_dms_class_from_wp_option(
326
+						$data_migration_option['option_name'],
327
+						$data_migration_option['option_value']
328
+					);
329
+					$data_migrations_ran[ $plugin_slug ][ $version_string ] = $class;
330
+					// ok so far THIS is the 'last-run-script'... unless we find another on next iteration
331
+					$this->_last_ran_script = $class;
332
+					if (! $class->is_completed()) {
333
+						// sometimes we also like to know which was the last incomplete script (or if there are any at all)
334
+						$this->_last_ran_incomplete_script = $class;
335
+					}
336
+				} catch (EE_Error $e) {
337
+					// ok so it's not a DMS. We'll just keep it, although other code will need to expect non-DMSs
338
+					$data_migrations_ran[ $plugin_slug ][ $version_string ] = maybe_unserialize(
339
+						$data_migration_option['option_value']
340
+					);
341
+				}
342
+			}
343
+			// so here the array of $data_migrations_ran is actually a mix of classes and a few legacy arrays
344
+			$this->_data_migrations_ran = $data_migrations_ran;
345
+			if (! $this->_data_migrations_ran || ! is_array($this->_data_migrations_ran)) {
346
+				$this->_data_migrations_ran = [];
347
+			}
348
+		}
349
+		return $this->_data_migrations_ran;
350
+	}
351
+
352
+
353
+	/**
354
+	 *
355
+	 * @param string $script_name eg 'DMS_Core_4_1_0'
356
+	 * @param string $old_table   eg 'wp_events_detail'
357
+	 * @param string $old_pk      eg 'wp_esp_posts'
358
+	 * @param        $new_table
359
+	 * @return mixed string or int
360
+	 * @throws EE_Error
361
+	 * @throws ReflectionException
362
+	 */
363
+	public function get_mapping_new_pk($script_name, $old_table, $old_pk, $new_table)
364
+	{
365
+		$script  = EE_Registry::instance()->load_dms($script_name);
366
+		return $script->get_mapping_new_pk($old_table, $old_pk, $new_table);
367
+	}
368
+
369
+
370
+	/**
371
+	 * Gets all the options containing migration scripts that have been run. Ordering is important: it's assumed that
372
+	 * the last option returned in this array is the most-recently run DMS option
373
+	 *
374
+	 * @return array
375
+	 */
376
+	public function get_all_migration_script_options()
377
+	{
378
+		global $wpdb;
379
+		return $wpdb->get_results(
380
+			"SELECT * FROM {$wpdb->options} WHERE option_name like '"
381
+			. EE_Data_Migration_Manager::data_migration_script_option_prefix
382
+			. "%' ORDER BY option_id ASC",
383
+			ARRAY_A
384
+		);
385
+	}
386
+
387
+
388
+	/**
389
+	 * Gets the array of folders which contain data migration scripts. Also adds them to be auto-loaded
390
+	 *
391
+	 * @return array where each value is the full folder path of a folder containing data migration scripts, WITH
392
+	 *               slashes at the end of the folder name.
393
+	 */
394
+	public function get_data_migration_script_folders()
395
+	{
396
+		return apply_filters(
397
+			'FHEE__EE_Data_Migration_Manager__get_data_migration_script_folders',
398
+			['Core' => EE_CORE . 'data_migration_scripts']
399
+		);
400
+	}
401
+
402
+
403
+	/**
404
+	 * Gets the version the migration script upgrades to
405
+	 *
406
+	 * @param string $migration_script_name eg 'EE_DMS_Core_4_1_0'
407
+	 * @return array {
408
+	 *      @type string  $slug     like 'Core','Calendar',etc
409
+	 *      @type string  $version  like 4.3.0
410
+	 * }
411
+	 * @throws EE_Error
412
+	 */
413
+	public function script_migrates_to_version($migration_script_name, $eeAddonClass = '')
414
+	{
415
+		if (isset($this->script_migration_versions[ $migration_script_name ])) {
416
+			return $this->script_migration_versions[ $migration_script_name ];
417
+		}
418
+		$dms_info                                                  = $this->parse_dms_classname($migration_script_name);
419
+		$this->script_migration_versions[ $migration_script_name ] = [
420
+			'slug'    => $eeAddonClass !== '' ? $eeAddonClass : $dms_info['slug'],
421
+			'version' => $dms_info['major_version']
422
+						 . "."
423
+						 . $dms_info['minor_version']
424
+						 . "."
425
+						 . $dms_info['micro_version'],
426
+		];
427
+		return $this->script_migration_versions[ $migration_script_name ];
428
+	}
429
+
430
+
431
+	/**
432
+	 * Gets the juicy details out of a dms filename like 'EE_DMS_Core_4_1_0'
433
+	 *
434
+	 * @param string $classname
435
+	 * @return array with keys 'slug','major_version','minor_version', and 'micro_version' (the last 3 are integers)
436
+	 * @throws EE_Error
437
+	 */
438
+	public function parse_dms_classname($classname)
439
+	{
440
+		$matches = [];
441
+		preg_match('~EE_DMS_(.*)_([0-9]*)_([0-9]*)_([0-9]*)~', $classname, $matches);
442
+		if (! $matches || ! (isset($matches[1]) && isset($matches[2]) && isset($matches[3]))) {
443
+			throw new EE_Error(
444
+				sprintf(
445
+					esc_html__(
446
+						"%s is not a valid Data Migration Script. The classname should be like EE_DMS_w_x_y_z, where w is either 'Core' or the slug of an addon and x, y and z are numbers, ",
447
+						"event_espresso"
448
+					),
449
+					$classname
450
+				)
451
+			);
452
+		}
453
+		return [
454
+			'slug'          => $matches[1],
455
+			'major_version' => intval($matches[2]),
456
+			'minor_version' => intval($matches[3]),
457
+			'micro_version' => intval($matches[4]),
458
+		];
459
+	}
460
+
461
+
462
+	/**
463
+	 * Ensures that the option indicating the current DB version is set. This should only be
464
+	 * a concern when activating EE for the first time, THEORETICALLY.
465
+	 * If we detect that we're activating EE4 over top of EE3.1, then we set the current db state to 3.1.x, otherwise
466
+	 * to 4.1.x.
467
+	 *
468
+	 * @return string of current db state
469
+	 */
470
+	public function ensure_current_database_state_is_set()
471
+	{
472
+		$espresso_db_core_updates = get_option('espresso_db_update', []);
473
+		$db_state                 = get_option(EE_Data_Migration_Manager::current_database_state);
474
+		if (! $db_state) {
475
+			// mark the DB as being in the state as the last version in there.
476
+			// this is done to trigger maintenance mode and do data migration scripts
477
+			// if the admin installed this version of EE over 3.1.x or 4.0.x
478
+			// otherwise, the normal maintenance mode code is fine
479
+			$previous_versions_installed = array_keys($espresso_db_core_updates);
480
+			$previous_version_installed  = end($previous_versions_installed);
481
+			if (version_compare('4.1.0', $previous_version_installed)) {
482
+				// last installed version was less than 4.1, so we want the data migrations to happen.
483
+				// SO, we're going to say the DB is at that state
484
+				$db_state = ['Core' => $previous_version_installed];
485
+			} else {
486
+				$db_state = ['Core' => EVENT_ESPRESSO_VERSION];
487
+			}
488
+			update_option(EE_Data_Migration_Manager::current_database_state, $db_state);
489
+		}
490
+		// in 4.1, $db_state would have only been a simple string like '4.1.0',
491
+		// but in 4.2+ it should be an array with at least key 'Core' and the value of that plugin's
492
+		// db, and possibly other keys for other addons like 'Calendar','Permissions',etc
493
+		if (! is_array($db_state)) {
494
+			$db_state = ['Core' => $db_state];
495
+			update_option(EE_Data_Migration_Manager::current_database_state, $db_state);
496
+		}
497
+		return $db_state;
498
+	}
499
+
500
+
501
+	/**
502
+	 * Checks if there are any data migration scripts that ought to be run.
503
+	 * If found, returns the instantiated classes.
504
+	 * If none are found (ie, they've all already been run, or they don't apply), returns an empty array
505
+	 *
506
+	 * @return EE_Data_Migration_Script_Base[]
507
+	 * @throws EE_Error
508
+	 * @throws EE_Error
509
+	 */
510
+	public function check_for_applicable_data_migration_scripts()
511
+	{
512
+		// get the option describing what options have already run
513
+		$scripts_ran = $this->get_data_migrations_ran();
514
+		// $scripts_ran = array('4.1.0.core'=>array('monkey'=>null));
515
+		$script_class_and_filepaths_available = $this->get_all_data_migration_scripts_available();
516
+
517
+
518
+		$current_database_state = $this->ensure_current_database_state_is_set();
519
+		// determine which have already been run
520
+		$script_classes_that_should_run_per_iteration = [];
521
+		$iteration                                    = 0;
522
+		$next_database_state_to_consider              = $current_database_state;
523
+		$theoretical_database_state = null;
524
+		do {
525
+			// the next state after the currently-considered one
526
+			// will start off looking the same as the current, but we may make additions...
527
+			$theoretical_database_state = $next_database_state_to_consider;
528
+			// the next db state to consider is
529
+			// "what would the DB be like had we run all the scripts we found that applied last time?"
530
+			foreach ($script_class_and_filepaths_available as $classname => $filepath) {
531
+				$migrates_to_version         = $this->script_migrates_to_version($classname);
532
+				$script_converts_plugin_slug = $migrates_to_version['slug'];
533
+				$script_converts_to_version  = $migrates_to_version['version'];
534
+				// check if this version script is DONE or not; or if it's never been run
535
+				if (
536
+					! $scripts_ran
537
+					|| ! isset($scripts_ran[ $script_converts_plugin_slug ][ $script_converts_to_version ])
538
+				) {
539
+					// we haven't run this conversion script before
540
+					// now check if it applies...
541
+					// note that we've added an autoloader for it on get_all_data_migration_scripts_available
542
+					// Also, make sure we get a new one. It's possible this is being ran during a multisite migration,
543
+					// in which case we don't want to reuse a DMS script from a different blog!
544
+					$script = LoaderFactory::getLoader()->getNew($classname);
545
+					/* @var $script EE_Data_Migration_Script_Base */
546
+					$can_migrate = $script->can_migrate_from_version($theoretical_database_state);
547
+					if ($can_migrate) {
548
+						$script_classes_that_should_run_per_iteration[ $iteration ][ $script->priority() ][] = $script;
549
+						$migrates_to_version                                                                 =
550
+							$script->migrates_to_version();
551
+						$next_database_state_to_consider[ $migrates_to_version['slug'] ]                     =
552
+							$migrates_to_version['version'];
553
+						unset($script_class_and_filepaths_available[ $classname ]);
554
+					}
555
+				} elseif (
556
+					$scripts_ran[ $script_converts_plugin_slug ][ $script_converts_to_version ]
557
+						  instanceof
558
+						  EE_Data_Migration_Script_Base
559
+				) {
560
+					// this script has been run, or at least started
561
+					$script = $scripts_ran[ $script_converts_plugin_slug ][ $script_converts_to_version ];
562
+					if ($script->get_status() !== self::status_completed) {
563
+						// this script is already underway... keep going with it
564
+						$script_classes_that_should_run_per_iteration[ $iteration ][ $script->priority() ][] = $script;
565
+						$migrates_to_version                                                                 =
566
+							$script->migrates_to_version();
567
+						$next_database_state_to_consider[ $migrates_to_version['slug'] ]                     =
568
+							$migrates_to_version['version'];
569
+						unset($script_class_and_filepaths_available[ $classname ]);
570
+					}
571
+					// else it must have a status that indicates it has finished,
572
+					// so we don't want to try and run it again
573
+				}
574
+				// else it exists, but it's not  a proper data migration script maybe the script got renamed?
575
+				// or was simply removed from EE? either way, it's certainly not runnable!
576
+			}
577
+			$iteration++;
578
+		} while ($next_database_state_to_consider !== $theoretical_database_state && $iteration < 6);
579
+		// ok we have all the scripts that should run, now let's make them into flat array
580
+		$scripts_that_should_run = [];
581
+		foreach ($script_classes_that_should_run_per_iteration as $scripts_at_priority) {
582
+			ksort($scripts_at_priority);
583
+			foreach ($scripts_at_priority as $scripts) {
584
+				foreach ($scripts as $script) {
585
+					$scripts_that_should_run[ get_class($script) ] = $script;
586
+				}
587
+			}
588
+		}
589
+
590
+		do_action(
591
+			'AHEE__EE_Data_Migration_Manager__check_for_applicable_data_migration_scripts__scripts_that_should_run',
592
+			$scripts_that_should_run
593
+		);
594
+		return $scripts_that_should_run;
595
+	}
596
+
597
+
598
+	/**
599
+	 * Gets the script which is currently being run, if there is one. If $include_completed_scripts is set to TRUE
600
+	 * it will return the last run script even if it's complete.
601
+	 * This means: if you want to find the currently-executing script, leave it as FALSE.
602
+	 * If you really just want to find the script which ran most recently, regardless of status, leave it as TRUE.
603
+	 *
604
+	 * @param bool $include_completed_scripts
605
+	 * @return EE_Data_Migration_Script_Base
606
+	 * @throws EE_Error
607
+	 */
608
+	public function get_last_ran_script($include_completed_scripts = false)
609
+	{
610
+		// make sure we've set up the class properties _last_ran_script and _last_ran_incomplete_script
611
+		if (! $this->_data_migrations_ran) {
612
+			$this->get_data_migrations_ran();
613
+		}
614
+		if ($include_completed_scripts) {
615
+			return $this->_last_ran_script;
616
+		} else {
617
+			return $this->_last_ran_incomplete_script;
618
+		}
619
+	}
620
+
621
+
622
+	/**
623
+	 * Runs the data migration scripts (well, each request to this method calls one of the
624
+	 * data migration scripts' migration_step() functions).
625
+	 *
626
+	 * @param int   $step_size
627
+	 * @return array {
628
+	 *                                  // where the first item is one EE_Data_Migration_Script_Base's stati,
629
+	 *                                  //and the second item is a string describing what was done
630
+	 * @type int    $records_to_migrate from the current migration script
631
+	 * @type int    $records_migrated
632
+	 * @type string $status             one of EE_Data_Migration_Manager::status_*
633
+	 * @type string $script             verbose name of the current DMS
634
+	 * @type string $message            string describing what was done during this step
635
+	 *                                  }
636
+	 * @throws EE_Error
637
+	 */
638
+	public function migration_step($step_size = 0)
639
+	{
640
+
641
+		// bandaid fix for issue https://events.codebasehq.com/projects/event-espresso/tickets/7535
642
+		if (class_exists('EE_CPT_Strategy')) {
643
+			remove_action('pre_get_posts', [EE_CPT_Strategy::instance(), 'pre_get_posts'], 5);
644
+		}
645
+
646
+		try {
647
+			$currently_executing_script = $this->get_last_ran_script();
648
+			if (! $currently_executing_script) {
649
+				// Find the next script that needs to execute
650
+				$scripts = $this->check_for_applicable_data_migration_scripts();
651
+				if (! $scripts) {
652
+					// huh, no more scripts to run... apparently we're done!
653
+					// but don't forget to make sure initial data is there
654
+					// we should be good to allow them to exit maintenance mode now
655
+					EE_Maintenance_Mode::instance()->set_maintenance_level(
656
+						EE_Maintenance_Mode::level_0_not_in_maintenance
657
+					);
658
+					// saving migrations run should actually be unnecessary,
659
+					// but leaving in place just in case... remember this migration was finished
660
+					// (even if we time out while initializing db for core and plugins)
661
+					$this->_save_migrations_ran();
662
+					// make sure DB was updated AFTER we've recorded the migration was done
663
+					$this->initialize_db_for_enqueued_ee_plugins();
664
+					return [
665
+						'records_to_migrate' => 1,
666
+						'records_migrated'   => 1,
667
+						'status'             => self::status_no_more_migration_scripts,
668
+						'script'             => esc_html__("Data Migration Completed Successfully", "event_espresso"),
669
+						'message'            => esc_html__("All done!", "event_espresso"),
670
+					];
671
+				}
672
+				$currently_executing_script = array_shift($scripts);
673
+				// and add to the array/wp option showing the scripts run
674
+
675
+				$migrates_to                                            =
676
+					$this->script_migrates_to_version(get_class($currently_executing_script));
677
+				$plugin_slug                                            = $migrates_to['slug'];
678
+				$version                                                = $migrates_to['version'];
679
+				$this->_data_migrations_ran[ $plugin_slug ][ $version ] = $currently_executing_script;
680
+			}
681
+			$current_script_name = get_class($currently_executing_script);
682
+		} catch (Exception $e) {
683
+			// an exception occurred while trying to get migration scripts
684
+
685
+			$message = sprintf(
686
+				esc_html__("Error Message: %sStack Trace:%s", "event_espresso"),
687
+				$e->getMessage() . '<br>',
688
+				$e->getTraceAsString()
689
+			);
690
+			// record it on the array of data migration scripts run. This will be overwritten next time we try and try to run data migrations
691
+			// but that's ok-- it's just an FYI to support that we couldn't even run any data migrations
692
+			$this->add_error_to_migrations_ran(
693
+				sprintf(esc_html__("Could not run data migrations because: %s", "event_espresso"), $message)
694
+			);
695
+			return [
696
+				'records_to_migrate' => 1,
697
+				'records_migrated'   => 0,
698
+				'status'             => self::status_fatal_error,
699
+				'script'             => esc_html__("Error loading data migration scripts", "event_espresso"),
700
+				'message'            => $message,
701
+			];
702
+		}
703
+		// can we wrap it up and verify default data?
704
+		$init_dbs = false;
705
+		// ok so we definitely have a data migration script
706
+		try {
707
+			// how big of a bite do we want to take? Allow users to easily override via their wp-config
708
+			if (absint($step_size) < 1) {
709
+				$step_size = defined('EE_MIGRATION_STEP_SIZE') && absint(EE_MIGRATION_STEP_SIZE)
710
+					? EE_MIGRATION_STEP_SIZE
711
+					: EE_Data_Migration_Manager::step_size;
712
+			}
713
+			// do what we came to do!
714
+			$currently_executing_script->migration_step($step_size);
715
+			switch ($currently_executing_script->get_status()) {
716
+				case EE_Data_Migration_Manager::status_continue:
717
+					$response_array = [
718
+						'records_to_migrate' => $currently_executing_script->count_records_to_migrate(),
719
+						'records_migrated'   => $currently_executing_script->count_records_migrated(),
720
+						'status'             => EE_Data_Migration_Manager::status_continue,
721
+						'message'            => $currently_executing_script->get_feedback_message(),
722
+						'script'             => $currently_executing_script->pretty_name(),
723
+					];
724
+					break;
725
+				case EE_Data_Migration_Manager::status_completed:
726
+					// ok so THAT script has completed
727
+					$this->update_current_database_state_to($this->script_migrates_to_version($current_script_name));
728
+					$response_array = [
729
+						'records_to_migrate' => $currently_executing_script->count_records_to_migrate(),
730
+						'records_migrated'   => $currently_executing_script->count_records_migrated(),
731
+						'status'             => EE_Data_Migration_Manager::status_completed,
732
+						'message'            => $currently_executing_script->get_feedback_message(),
733
+						'script'             => sprintf(
734
+							esc_html__("%s Completed", 'event_espresso'),
735
+							$currently_executing_script->pretty_name()
736
+						),
737
+					];
738
+					// check if there are any more after this one.
739
+					$scripts_remaining = $this->check_for_applicable_data_migration_scripts();
740
+					if (! $scripts_remaining) {
741
+						// we should be good to allow them to exit maintenance mode now
742
+						EE_Maintenance_Mode::instance()->set_maintenance_level(
743
+							EE_Maintenance_Mode::level_0_not_in_maintenance
744
+						);
745
+						// huh, no more scripts to run... apparently we're done!
746
+						// but don't forget to make sure initial data is there
747
+						$init_dbs                 = true;
748
+						$response_array['status'] = self::status_no_more_migration_scripts;
749
+					}
750
+					break;
751
+				default:
752
+					$response_array = [
753
+						'records_to_migrate' => $currently_executing_script->count_records_to_migrate(),
754
+						'records_migrated'   => $currently_executing_script->count_records_migrated(),
755
+						'status'             => $currently_executing_script->get_status(),
756
+						'message'            => sprintf(
757
+							esc_html__("Minor errors occurred during %s: %s", "event_espresso"),
758
+							$currently_executing_script->pretty_name(),
759
+							implode(", ", $currently_executing_script->get_errors())
760
+						),
761
+						'script'             => $currently_executing_script->pretty_name(),
762
+					];
763
+					break;
764
+			}
765
+		} catch (Exception $e) {
766
+			// ok so some exception was thrown which killed the data migration script
767
+			// double-check we have a real script
768
+			if ($currently_executing_script instanceof EE_Data_Migration_Script_Base) {
769
+				$script_name = $currently_executing_script->pretty_name();
770
+				$currently_executing_script->set_broken();
771
+				$currently_executing_script->add_error($e->getMessage());
772
+			} else {
773
+				$script_name = esc_html__("Error getting Migration Script", "event_espresso");
774
+			}
775
+			$response_array = [
776
+				'records_to_migrate' => 1,
777
+				'records_migrated'   => 0,
778
+				'status'             => self::status_fatal_error,
779
+				'message'            => sprintf(
780
+					esc_html__("A fatal error occurred during the migration: %s", "event_espresso"),
781
+					$e->getMessage()
782
+				),
783
+				'script'             => $script_name,
784
+			];
785
+		}
786
+		$successful_save = $this->_save_migrations_ran();
787
+		if ($successful_save !== true) {
788
+			// ok so the current wp option didn't save. that's tricky, because we'd like to update it
789
+			// and mark it as having a fatal error, but remember- WE CAN'T SAVE THIS WP OPTION!
790
+			// however, if we throw an exception, and return that, then the next request
791
+			// won't have as much info in it, and it may be able to save
792
+			throw new EE_Error(
793
+				sprintf(
794
+					esc_html__(
795
+						"The error '%s' occurred updating the status of the migration. This is a FATAL ERROR, but the error is preventing the system from remembering that. Please contact event espresso support.",
796
+						"event_espresso"
797
+					),
798
+					$successful_save
799
+				)
800
+			);
801
+		}
802
+		// if we're all done, initialize EE plugins' default data etc.
803
+		if ($init_dbs) {
804
+			$this->initialize_db_for_enqueued_ee_plugins();
805
+		}
806
+		return $response_array;
807
+	}
808
+
809
+
810
+	/**
811
+	 * Echo out JSON response to migration script AJAX requests. Takes precautions
812
+	 * to buffer output so that we don't throw junk into our json.
813
+	 *
814
+	 * @return array with keys:
815
+	 * 'records_to_migrate' which counts ALL the records for the current migration, and should remain constant. (ie,
816
+	 * it's NOT the count of hwo many remain)
817
+	 * 'records_migrated' which also counts ALL the records which have been migrated (ie, percent_complete =
818
+	 * records_migrated/records_to_migrate)
819
+	 * 'status'=>a string, one of EE_Data_migration_Manager::status_*
820
+	 * 'message'=>a string, containing any message you want to show to the user. We may decide to split this up into
821
+	 * errors, notifications, and successes
822
+	 * 'script'=>a pretty name of the script currently running
823
+	 */
824
+	public function response_to_migration_ajax_request()
825
+	{
826
+		ob_start();
827
+		try {
828
+			$response = $this->migration_step();
829
+		} catch (Exception $e) {
830
+			$response = [
831
+				'records_to_migrate' => 0,
832
+				'records_migrated'   => 0,
833
+				'status'             => EE_Data_Migration_Manager::status_fatal_error,
834
+				'message'            => sprintf(
835
+					esc_html__("Unknown fatal error occurred: %s", "event_espresso"),
836
+					$e->getMessage()
837
+				),
838
+				'script'             => 'Unknown',
839
+			];
840
+			$this->add_error_to_migrations_ran($e->getMessage() . "; Stack trace:" . $e->getTraceAsString());
841
+		}
842
+		$warnings_etc = @ob_get_contents();
843
+		ob_end_clean();
844
+		$response['message'] .= $warnings_etc;
845
+		return $response;
846
+	}
847
+
848
+
849
+	/**
850
+	 * Updates the WordPress option that keeps track of which EE version the database
851
+	 * is at (ie, the code may be at 4.1.0, but the database is still at 3.1.35)
852
+	 *
853
+	 * @param array $slug_and_version {
854
+	 * @type string $slug             like 'Core' or 'Calendar',
855
+	 * @type string $version          like '4.1.0'
856
+	 *                                }
857
+	 * @return void
858
+	 */
859
+	public function update_current_database_state_to($slug_and_version = null)
860
+	{
861
+		if (! $slug_and_version) {
862
+			// no version was provided, assume it should be at the current code version
863
+			$slug_and_version = ['slug' => 'Core', 'version' => espresso_version()];
864
+		}
865
+		$current_database_state                              = get_option(self::current_database_state);
866
+		$current_database_state[ $slug_and_version['slug'] ] = $slug_and_version['version'];
867
+		update_option(self::current_database_state, $current_database_state);
868
+	}
869
+
870
+
871
+	/**
872
+	 * Determines if the database is currently at a state matching what's indicated in $slug and $version.
873
+	 *
874
+	 * @param array $slug_and_version {
875
+	 * @type string $slug             like 'Core' or 'Calendar',
876
+	 * @type string $version          like '4.1.0'
877
+	 *                                }
878
+	 * @return boolean
879
+	 */
880
+	public function database_needs_updating_to($slug_and_version)
881
+	{
882
+
883
+		$slug                   = $slug_and_version['slug'];
884
+		$version                = $slug_and_version['version'];
885
+		$current_database_state = get_option(self::current_database_state);
886
+		if (! isset($current_database_state[ $slug ])) {
887
+			return true;
888
+		} else {
889
+			// just compare the first 3 parts of version string, eg "4.7.1", not "4.7.1.dev.032" because DBs shouldn't change on nano version changes
890
+			$version_parts_current_db_state     = array_slice(explode('.', $current_database_state[ $slug ]), 0, 3);
891
+			$version_parts_of_provided_db_state = array_slice(explode('.', $version), 0, 3);
892
+			$needs_updating                     = false;
893
+			foreach ($version_parts_current_db_state as $offset => $version_part_in_current_db_state) {
894
+				if ($version_part_in_current_db_state < $version_parts_of_provided_db_state[ $offset ]) {
895
+					$needs_updating = true;
896
+					break;
897
+				}
898
+			}
899
+			return $needs_updating;
900
+		}
901
+	}
902
+
903
+
904
+	/**
905
+	 * Gets all the data migration scripts available in the core folder and folders
906
+	 * in addons. Has the side effect of adding them for autoloading
907
+	 *
908
+	 * @return array keys are expected classnames, values are their filepaths
909
+	 * @throws InvalidInterfaceException
910
+	 * @throws InvalidDataTypeException
911
+	 * @throws EE_Error
912
+	 * @throws InvalidArgumentException
913
+	 */
914
+	public function get_all_data_migration_scripts_available()
915
+	{
916
+		if (! $this->_data_migration_class_to_filepath_map) {
917
+			$this->_data_migration_class_to_filepath_map = [];
918
+			foreach ($this->get_data_migration_script_folders() as $eeAddonClass => $folder_path) {
919
+				// strip any placeholders added to classname to make it a unique array key
920
+				$eeAddonClass = trim($eeAddonClass, '*');
921
+				$eeAddonClass = $eeAddonClass === 'Core' || class_exists($eeAddonClass)
922
+					? $eeAddonClass
923
+					: '';
924
+				$folder_path  = EEH_File::end_with_directory_separator($folder_path);
925
+				$files        = glob($folder_path . '*.dms.php');
926
+				if (empty($files)) {
927
+					continue;
928
+				}
929
+				foreach ($files as $file) {
930
+					$pos_of_last_slash = strrpos($file, '/');
931
+					$classname         = str_replace('.dms.php', '', substr($file, $pos_of_last_slash + 1));
932
+					$migrates_to       = $this->script_migrates_to_version($classname, $eeAddonClass);
933
+					$slug              = $migrates_to['slug'];
934
+					// check that the slug as contained in the DMS is associated with
935
+					// the slug of an addon or core
936
+					if ($slug !== 'Core' && EE_Registry::instance()->get_addon_by_name($slug) === null) {
937
+						EE_Error::doing_it_wrong(
938
+							__FUNCTION__,
939
+							sprintf(
940
+								esc_html__(
941
+									'The data migration script "%s" migrates the "%s" data, but there is no EE addon with that name. There is only: %s. ',
942
+									'event_espresso'
943
+								),
944
+								$classname,
945
+								$slug,
946
+								implode(', ', array_keys(EE_Registry::instance()->get_addons_by_name()))
947
+							),
948
+							'4.3.0.alpha.019'
949
+						);
950
+					}
951
+					$this->_data_migration_class_to_filepath_map[ $classname ] = $file;
952
+				}
953
+			}
954
+			EEH_Autoloader::register_autoloader($this->_data_migration_class_to_filepath_map);
955
+		}
956
+		return $this->_data_migration_class_to_filepath_map;
957
+	}
958
+
959
+
960
+	/**
961
+	 * Once we have an addon that works with EE4.1, we will actually want to fetch the PUE slugs
962
+	 * from each addon, and check if they need updating,
963
+	 *
964
+	 * @return boolean
965
+	 */
966
+	public function addons_need_updating()
967
+	{
968
+		return false;
969
+	}
970
+
971
+
972
+	/**
973
+	 * Adds this error string to the data_migrations_ran array, but we don't necessarily know
974
+	 * where to put it, so we just throw it in there... better than nothing...
975
+	 *
976
+	 * @param string $error_message
977
+	 */
978
+	public function add_error_to_migrations_ran($error_message)
979
+	{
980
+		// get last-run migration script
981
+		global $wpdb;
982
+		$last_migration_script_option = $wpdb->get_row(
983
+			"SELECT * FROM $wpdb->options WHERE option_name like '"
984
+			. EE_Data_Migration_Manager::data_migration_script_option_prefix
985
+			. "%' ORDER BY option_id DESC LIMIT 1",
986
+			ARRAY_A
987
+		);
988
+
989
+		$last_ran_migration_script_properties = isset($last_migration_script_option['option_value'])
990
+			? maybe_unserialize($last_migration_script_option['option_value']) : null;
991
+		// now, tread lightly because we're here because a FATAL non-catchable error
992
+		// was thrown last time when we were trying to run a data migration script
993
+		// so the fatal error could have happened while getting the migration script
994
+		// or doing running it...
995
+		$versions_migrated_to = isset($last_migration_script_option['option_name']) ? str_replace(
996
+			EE_Data_Migration_Manager::data_migration_script_option_prefix,
997
+			"",
998
+			$last_migration_script_option['option_name']
999
+		) : null;
1000
+
1001
+		// check if it THINKS it's a data migration script and especially if it's one that HASN'T finished yet
1002
+		// because if it has finished, then it obviously couldn't be the cause of this error, right? (because it's all done)
1003
+		if (
1004
+			isset($last_ran_migration_script_properties['class'])
1005
+			&& isset($last_ran_migration_script_properties['_status'])
1006
+			&& $last_ran_migration_script_properties['_status'] != self::status_completed
1007
+		) {
1008
+			// ok then just add this error to its list of errors
1009
+			$last_ran_migration_script_properties['_errors'][] = $error_message;
1010
+			$last_ran_migration_script_properties['_status']   = self::status_fatal_error;
1011
+		} else {
1012
+			// so we don't even know which script was last running
1013
+			// use the data migration error stub, which is designed specifically for this type of thing
1014
+			$general_migration_error = new EE_DMS_Unknown_1_0_0();
1015
+			$general_migration_error->add_error($error_message);
1016
+			$general_migration_error->set_broken();
1017
+			$last_ran_migration_script_properties = $general_migration_error->properties_as_array();
1018
+			$versions_migrated_to                 = 'Unknown.1.0.0';
1019
+			// now just to make sure appears as last (in case the were previously a fatal error like this)
1020
+			// delete the old one
1021
+			delete_option(self::data_migration_script_option_prefix . $versions_migrated_to);
1022
+		}
1023
+		update_option(
1024
+			self::data_migration_script_option_prefix . $versions_migrated_to,
1025
+			$last_ran_migration_script_properties
1026
+		);
1027
+	}
1028
+
1029
+
1030
+	/**
1031
+	 * saves what data migrations have run to the database
1032
+	 *
1033
+	 * @return bool|string TRUE if successfully saved migrations ran, string if an error occurred
1034
+	 * @throws EE_Error
1035
+	 */
1036
+	protected function _save_migrations_ran()
1037
+	{
1038
+		if ($this->_data_migrations_ran == null) {
1039
+			$this->get_data_migrations_ran();
1040
+		}
1041
+		// now, we don't want to save actual classes to the DB because that's messy
1042
+		$successful_updates = true;
1043
+		foreach ($this->_data_migrations_ran as $plugin_slug => $migrations_ran_for_plugin) {
1044
+			foreach ($migrations_ran_for_plugin as $version_string => $array_or_migration_obj) {
1045
+				$plugin_slug_for_use_in_option_name = $plugin_slug . ".";
1046
+				$option_name                        =
1047
+					self::data_migration_script_option_prefix . $plugin_slug_for_use_in_option_name . $version_string;
1048
+				$old_option_value                   = get_option($option_name);
1049
+				if ($array_or_migration_obj instanceof EE_Data_Migration_Script_Base) {
1050
+					$script_array_for_saving = $array_or_migration_obj->properties_as_array();
1051
+					if ($old_option_value != $script_array_for_saving) {
1052
+						$successful_updates = update_option($option_name, $script_array_for_saving);
1053
+					}
1054
+				} else {// we don't know what this array-thing is. So just save it as-is
1055
+					if ($old_option_value != $array_or_migration_obj) {
1056
+						$successful_updates = update_option($option_name, $array_or_migration_obj);
1057
+					}
1058
+				}
1059
+				if (! $successful_updates) {
1060
+					global $wpdb;
1061
+					return $wpdb->last_error;
1062
+				}
1063
+			}
1064
+		}
1065
+		return true;
1066
+		// $updated = update_option(self::data_migrations_option_name, $array_of_migrations);
1067
+		// if ($updated !== true) {
1068
+		//     global $wpdb;
1069
+		//     return $wpdb->last_error;
1070
+		// } else {
1071
+		//     return true;
1072
+		// }
1073
+		// wp_mail(
1074
+		//     "[email protected]",
1075
+		//     time() . " price debug info",
1076
+		//     "updated: $updated, last error: $last_error, byte length of option: " . strlen(
1077
+		//         serialize($array_of_migrations)
1078
+		//     )
1079
+		// );
1080
+	}
1081
+
1082
+
1083
+	/**
1084
+	 * Takes an array of data migration script properties and re-creates the class from
1085
+	 * them. The argument $properties_array is assumed to have been made by
1086
+	 * EE_Data_Migration_Script_Base::properties_as_array()
1087
+	 *
1088
+	 * @param array $properties_array
1089
+	 * @return EE_Data_Migration_Script_Base
1090
+	 * @throws EE_Error
1091
+	 */
1092
+	public function _instantiate_script_from_properties_array($properties_array)
1093
+	{
1094
+		if (! isset($properties_array['class'])) {
1095
+			throw new EE_Error(
1096
+				sprintf(
1097
+					esc_html__("Properties array  has no 'class' properties. Here's what it has: %s", "event_espresso"),
1098
+					implode(",", $properties_array)
1099
+				)
1100
+			);
1101
+		}
1102
+		$class_name = $properties_array['class'];
1103
+		if (! class_exists($class_name)) {
1104
+			throw new EE_Error(sprintf(
1105
+				esc_html__("There is no migration script named %s", "event_espresso"),
1106
+				$class_name
1107
+			));
1108
+		}
1109
+		$class = new $class_name();
1110
+		if (! $class instanceof EE_Data_Migration_Script_Base) {
1111
+			throw new EE_Error(
1112
+				sprintf(
1113
+					esc_html__(
1114
+						"Class '%s' is supposed to be a migration script. Its not, its a '%s'",
1115
+						"event_espresso"
1116
+					),
1117
+					$class_name,
1118
+					get_class($class)
1119
+				)
1120
+			);
1121
+		}
1122
+		$class->instantiate_from_array_of_properties($properties_array);
1123
+		return $class;
1124
+	}
1125
+
1126
+
1127
+	/**
1128
+	 * Gets the classname for the most up-to-date DMS (ie, the one that will finally
1129
+	 * leave the DB in a state usable by the current plugin code).
1130
+	 *
1131
+	 * @param string $plugin_slug the slug for the ee plugin we are searching for. Default is 'Core'
1132
+	 * @return string
1133
+	 * @throws EE_Error
1134
+	 * @throws EE_Error
1135
+	 */
1136
+	public function get_most_up_to_date_dms($plugin_slug = 'Core')
1137
+	{
1138
+		$class_to_filepath_map         = $this->get_all_data_migration_scripts_available();
1139
+		$most_up_to_date_dms_classname = null;
1140
+		foreach ($class_to_filepath_map as $classname => $filepath) {
1141
+			if ($most_up_to_date_dms_classname === null) {
1142
+				$migrates_to      = $this->script_migrates_to_version($classname);
1143
+				$this_plugin_slug = $migrates_to['slug'];
1144
+				if ($this_plugin_slug == $plugin_slug) {
1145
+					// if it's for core, it wins
1146
+					$most_up_to_date_dms_classname = $classname;
1147
+				}
1148
+				// if it wasn't for core, we must keep searching for one that is!
1149
+				continue;
1150
+			}
1151
+			$champion_migrates_to  = $this->script_migrates_to_version($most_up_to_date_dms_classname);
1152
+			$contender_migrates_to = $this->script_migrates_to_version($classname);
1153
+			if (
1154
+				$contender_migrates_to['slug'] == $plugin_slug
1155
+				&& version_compare(
1156
+					$champion_migrates_to['version'],
1157
+					$contender_migrates_to['version'],
1158
+					'<'
1159
+				)
1160
+			) {
1161
+				// so the contenders version is higher, and it's for Core
1162
+				$most_up_to_date_dms_classname = $classname;
1163
+			}
1164
+		}
1165
+		return $most_up_to_date_dms_classname;
1166
+	}
1167
+
1168
+
1169
+	/**
1170
+	 * Gets the migration script specified but ONLY if it has already run.
1171
+	 *
1172
+	 * Eg, if you wanted to see if 'EE_DMS_Core_4_1_0' has run, you would run the following code:
1173
+	 * <code> $core_4_1_0_dms_ran = EE_Data_Migration_Manager::instance()->get_migration_ran( '4.1.0', 'Core' ) !==
1174
+	 * NULL;</code> This is especially useful in addons' data migration scripts, this way they can tell if a core (or
1175
+	 * other addon) DMS has run, in case the current DMS depends on it.
1176
+	 *
1177
+	 * @param string $version     the version the DMS searched for migrates to. Usually just the content before the 3rd
1178
+	 *                            period. Eg '4.1.0'
1179
+	 * @param string $plugin_slug like 'Core', 'Mailchimp', 'Calendar', etc
1180
+	 * @return EE_Data_Migration_Script_Base
1181
+	 * @throws EE_Error
1182
+	 */
1183
+	public function get_migration_ran($version, $plugin_slug = 'Core')
1184
+	{
1185
+		$migrations_ran = $this->get_data_migrations_ran();
1186
+		if (isset($migrations_ran[ $plugin_slug ]) && isset($migrations_ran[ $plugin_slug ][ $version ])) {
1187
+			return $migrations_ran[ $plugin_slug ][ $version ];
1188
+		} else {
1189
+			return null;
1190
+		}
1191
+	}
1192
+
1193
+
1194
+	/**
1195
+	 * Resets the borked data migration scripts, so they're no longer borked, and we can again attempt to migrate
1196
+	 *
1197
+	 * @return bool
1198
+	 * @throws EE_Error
1199
+	 */
1200
+	public function reattempt()
1201
+	{
1202
+		// find if the last-run script was borked
1203
+		// set it as being non-borked (we shouldn't ever get DMSs that we don't recognize)
1204
+		// add an 'error' saying that we attempted to reset
1205
+		// does it have a stage that was borked too? if so make it no longer borked
1206
+		// add an 'error' saying we attempted to reset
1207
+		$last_ran_script = $this->get_last_ran_script();
1208
+		if ($last_ran_script instanceof EE_DMS_Unknown_1_0_0) {
1209
+			// if it was an error DMS, just mark it as complete (if another error occurs it will overwrite it)
1210
+			$last_ran_script->set_completed();
1211
+		} elseif ($last_ran_script instanceof EE_Data_Migration_Script_Base) {
1212
+			$last_ran_script->reattempt();
1213
+		} else {
1214
+			throw new EE_Error(
1215
+				sprintf(
1216
+					esc_html__(
1217
+						'Unable to reattempt the last ran migration script because it was not a valid migration script. || It was %s',
1218
+						'event_espresso'
1219
+					),
1220
+					print_r($last_ran_script, true)
1221
+				)
1222
+			);
1223
+		}
1224
+		return $this->_save_migrations_ran();
1225
+	}
1226
+
1227
+
1228
+	/**
1229
+	 * Gets whether this particular migration has run or not
1230
+	 *
1231
+	 * @param string $version     the version the DMS searched for migrates to. Usually just the content before the 3rd
1232
+	 *                            period. Eg '4.1.0'
1233
+	 * @param string $plugin_slug like 'Core', 'Mailchimp', 'Calendar', etc
1234
+	 * @return boolean
1235
+	 * @throws EE_Error
1236
+	 */
1237
+	public function migration_has_ran($version, $plugin_slug = 'Core')
1238
+	{
1239
+		return $this->get_migration_ran($version, $plugin_slug) !== null;
1240
+	}
1241
+
1242
+
1243
+	/**
1244
+	 * Enqueues this ee plugin to have its data initialized
1245
+	 *
1246
+	 * @param string $plugin_slug either 'Core' or EE_Addon::name()'s return value
1247
+	 */
1248
+	public function enqueue_db_initialization_for($plugin_slug)
1249
+	{
1250
+		$queue = $this->get_db_initialization_queue();
1251
+		if (! in_array($plugin_slug, $queue)) {
1252
+			$queue[] = $plugin_slug;
1253
+		}
1254
+		update_option(self::db_init_queue_option_name, $queue);
1255
+	}
1256
+
1257
+
1258
+	/**
1259
+	 * Calls EE_Addon::initialize_db_if_no_migrations_required() on each addon
1260
+	 * specified in EE_Data_Migration_Manager::get_db_init_queue(), and if 'Core' is
1261
+	 * in the queue, calls EE_System::initialize_db_if_no_migrations_required().
1262
+	 *
1263
+	 * @throws EE_Error
1264
+	 */
1265
+	public function initialize_db_for_enqueued_ee_plugins()
1266
+	{
1267
+		$queue = $this->get_db_initialization_queue();
1268
+		foreach ($queue as $plugin_slug) {
1269
+			$most_up_to_date_dms = $this->get_most_up_to_date_dms($plugin_slug);
1270
+			if (! $most_up_to_date_dms) {
1271
+				// if there is NO DMS for this plugin, obviously there's no schema to verify anyways
1272
+				$verify_db = false;
1273
+			} else {
1274
+				$most_up_to_date_dms_migrates_to = $this->script_migrates_to_version($most_up_to_date_dms);
1275
+				$verify_db                       = $this->database_needs_updating_to($most_up_to_date_dms_migrates_to);
1276
+			}
1277
+			if ($plugin_slug == 'Core') {
1278
+				EE_System::instance()->initialize_db_if_no_migrations_required(
1279
+					false,
1280
+					$verify_db
1281
+				);
1282
+			} else {
1283
+				// just loop through the addons to make sure their database is set up
1284
+				foreach (EE_Registry::instance()->addons as $addon) {
1285
+					if ($addon->name() == $plugin_slug) {
1286
+						$addon->initialize_db_if_no_migrations_required($verify_db);
1287
+						break;
1288
+					}
1289
+				}
1290
+			}
1291
+		}
1292
+		// because we just initialized the DBs for the enqueued ee plugins
1293
+		// we don't need to keep remembering which ones needed to be initialized
1294
+		delete_option(self::db_init_queue_option_name);
1295
+	}
1296
+
1297
+
1298
+	/**
1299
+	 * Gets a numerically-indexed array of plugin slugs that need to have their databases
1300
+	 * (re-)initialized after migrations are complete. ie, each element should be either
1301
+	 * 'Core', or the return value of EE_Addon::name() for an addon
1302
+	 *
1303
+	 * @return array
1304
+	 */
1305
+	public function get_db_initialization_queue()
1306
+	{
1307
+		return get_option(self::db_init_queue_option_name, []);
1308
+	}
1309
+
1310
+
1311
+	/**
1312
+	 * Gets the injected table analyzer, or throws an exception
1313
+	 *
1314
+	 * @return TableAnalysis
1315
+	 * @throws EE_Error
1316
+	 */
1317
+	protected function _get_table_analysis()
1318
+	{
1319
+		if ($this->_table_analysis instanceof TableAnalysis) {
1320
+			return $this->_table_analysis;
1321
+		} else {
1322
+			throw new EE_Error(
1323
+				sprintf(
1324
+					esc_html__('Table analysis class on class %1$s is not set properly.', 'event_espresso'),
1325
+					get_class($this)
1326
+				)
1327
+			);
1328
+		}
1329
+	}
1330
+
1331
+
1332
+	/**
1333
+	 * Gets the injected table manager, or throws an exception
1334
+	 *
1335
+	 * @return TableManager
1336
+	 * @throws EE_Error
1337
+	 */
1338
+	protected function _get_table_manager()
1339
+	{
1340
+		if ($this->_table_manager instanceof TableManager) {
1341
+			return $this->_table_manager;
1342
+		} else {
1343
+			throw new EE_Error(
1344
+				sprintf(
1345
+					esc_html__('Table manager class on class %1$s is not set properly.', 'event_espresso'),
1346
+					get_class($this)
1347
+				)
1348
+			);
1349
+		}
1350
+	}
1351 1351
 }
Please login to merge, or discard this patch.
Spacing   +60 added lines, -60 removed lines patch added patch discarded remove patch
@@ -163,7 +163,7 @@  discard block
 block discarded – undo
163 163
     public static function instance()
164 164
     {
165 165
         // check if class object is instantiated
166
-        if (! self::$_instance instanceof EE_Data_Migration_Manager) {
166
+        if ( ! self::$_instance instanceof EE_Data_Migration_Manager) {
167 167
             self::$_instance = new self();
168 168
         }
169 169
         return self::$_instance;
@@ -189,11 +189,11 @@  discard block
 block discarded – undo
189 189
      */
190 190
     private function __construct()
191 191
     {
192
-        $this->stati_that_indicate_to_continue_migrations              = [
192
+        $this->stati_that_indicate_to_continue_migrations = [
193 193
             self::status_continue,
194 194
             self::status_completed,
195 195
         ];
196
-        $this->stati_that_indicate_to_stop_migrations                  = [
196
+        $this->stati_that_indicate_to_stop_migrations = [
197 197
             self::status_fatal_error,
198 198
             self::status_no_more_migration_scripts,
199 199
         ];
@@ -241,12 +241,12 @@  discard block
 block discarded – undo
241 241
 
242 242
         if (count($parts) == 4) {
243 243
             // it's 4.2-style.eg Core.4.1.0
244
-            $plugin_slug    = $parts[0];                                     // eg Core
245
-            $version_string = $parts[1] . "." . $parts[2] . "." . $parts[3]; // eg 4.1.0
244
+            $plugin_slug    = $parts[0]; // eg Core
245
+            $version_string = $parts[1].".".$parts[2].".".$parts[3]; // eg 4.1.0
246 246
         } else {
247 247
             // it's 4.1-style: eg 4.1.0
248 248
             $plugin_slug    = 'Core';
249
-            $version_string = $plugin_slug_and_version_string;// eg 4.1.0
249
+            $version_string = $plugin_slug_and_version_string; // eg 4.1.0
250 250
         }
251 251
         return [$plugin_slug, $version_string];
252 252
     }
@@ -308,11 +308,11 @@  discard block
 block discarded – undo
308 308
      */
309 309
     public function get_data_migrations_ran()
310 310
     {
311
-        if (! $this->_data_migrations_ran) {
311
+        if ( ! $this->_data_migrations_ran) {
312 312
             // setup autoloaders for each of the scripts in there
313 313
             $this->get_all_data_migration_scripts_available();
314 314
             $data_migrations_options =
315
-                $this->get_all_migration_script_options();// get_option(EE_Data_Migration_Manager::data_migrations_option_name,get_option('espresso_data_migrations',array()));
315
+                $this->get_all_migration_script_options(); // get_option(EE_Data_Migration_Manager::data_migrations_option_name,get_option('espresso_data_migrations',array()));
316 316
 
317 317
             $data_migrations_ran = [];
318 318
             // convert into data migration script classes where possible
@@ -322,27 +322,27 @@  discard block
 block discarded – undo
322 322
                 );
323 323
 
324 324
                 try {
325
-                    $class                                                  = $this->_get_dms_class_from_wp_option(
325
+                    $class = $this->_get_dms_class_from_wp_option(
326 326
                         $data_migration_option['option_name'],
327 327
                         $data_migration_option['option_value']
328 328
                     );
329
-                    $data_migrations_ran[ $plugin_slug ][ $version_string ] = $class;
329
+                    $data_migrations_ran[$plugin_slug][$version_string] = $class;
330 330
                     // ok so far THIS is the 'last-run-script'... unless we find another on next iteration
331 331
                     $this->_last_ran_script = $class;
332
-                    if (! $class->is_completed()) {
332
+                    if ( ! $class->is_completed()) {
333 333
                         // sometimes we also like to know which was the last incomplete script (or if there are any at all)
334 334
                         $this->_last_ran_incomplete_script = $class;
335 335
                     }
336 336
                 } catch (EE_Error $e) {
337 337
                     // ok so it's not a DMS. We'll just keep it, although other code will need to expect non-DMSs
338
-                    $data_migrations_ran[ $plugin_slug ][ $version_string ] = maybe_unserialize(
338
+                    $data_migrations_ran[$plugin_slug][$version_string] = maybe_unserialize(
339 339
                         $data_migration_option['option_value']
340 340
                     );
341 341
                 }
342 342
             }
343 343
             // so here the array of $data_migrations_ran is actually a mix of classes and a few legacy arrays
344 344
             $this->_data_migrations_ran = $data_migrations_ran;
345
-            if (! $this->_data_migrations_ran || ! is_array($this->_data_migrations_ran)) {
345
+            if ( ! $this->_data_migrations_ran || ! is_array($this->_data_migrations_ran)) {
346 346
                 $this->_data_migrations_ran = [];
347 347
             }
348 348
         }
@@ -362,7 +362,7 @@  discard block
 block discarded – undo
362 362
      */
363 363
     public function get_mapping_new_pk($script_name, $old_table, $old_pk, $new_table)
364 364
     {
365
-        $script  = EE_Registry::instance()->load_dms($script_name);
365
+        $script = EE_Registry::instance()->load_dms($script_name);
366 366
         return $script->get_mapping_new_pk($old_table, $old_pk, $new_table);
367 367
     }
368 368
 
@@ -395,7 +395,7 @@  discard block
 block discarded – undo
395 395
     {
396 396
         return apply_filters(
397 397
             'FHEE__EE_Data_Migration_Manager__get_data_migration_script_folders',
398
-            ['Core' => EE_CORE . 'data_migration_scripts']
398
+            ['Core' => EE_CORE.'data_migration_scripts']
399 399
         );
400 400
     }
401 401
 
@@ -412,11 +412,11 @@  discard block
 block discarded – undo
412 412
      */
413 413
     public function script_migrates_to_version($migration_script_name, $eeAddonClass = '')
414 414
     {
415
-        if (isset($this->script_migration_versions[ $migration_script_name ])) {
416
-            return $this->script_migration_versions[ $migration_script_name ];
415
+        if (isset($this->script_migration_versions[$migration_script_name])) {
416
+            return $this->script_migration_versions[$migration_script_name];
417 417
         }
418 418
         $dms_info                                                  = $this->parse_dms_classname($migration_script_name);
419
-        $this->script_migration_versions[ $migration_script_name ] = [
419
+        $this->script_migration_versions[$migration_script_name] = [
420 420
             'slug'    => $eeAddonClass !== '' ? $eeAddonClass : $dms_info['slug'],
421 421
             'version' => $dms_info['major_version']
422 422
                          . "."
@@ -424,7 +424,7 @@  discard block
 block discarded – undo
424 424
                          . "."
425 425
                          . $dms_info['micro_version'],
426 426
         ];
427
-        return $this->script_migration_versions[ $migration_script_name ];
427
+        return $this->script_migration_versions[$migration_script_name];
428 428
     }
429 429
 
430 430
 
@@ -439,7 +439,7 @@  discard block
 block discarded – undo
439 439
     {
440 440
         $matches = [];
441 441
         preg_match('~EE_DMS_(.*)_([0-9]*)_([0-9]*)_([0-9]*)~', $classname, $matches);
442
-        if (! $matches || ! (isset($matches[1]) && isset($matches[2]) && isset($matches[3]))) {
442
+        if ( ! $matches || ! (isset($matches[1]) && isset($matches[2]) && isset($matches[3]))) {
443 443
             throw new EE_Error(
444 444
                 sprintf(
445 445
                     esc_html__(
@@ -471,7 +471,7 @@  discard block
 block discarded – undo
471 471
     {
472 472
         $espresso_db_core_updates = get_option('espresso_db_update', []);
473 473
         $db_state                 = get_option(EE_Data_Migration_Manager::current_database_state);
474
-        if (! $db_state) {
474
+        if ( ! $db_state) {
475 475
             // mark the DB as being in the state as the last version in there.
476 476
             // this is done to trigger maintenance mode and do data migration scripts
477 477
             // if the admin installed this version of EE over 3.1.x or 4.0.x
@@ -490,7 +490,7 @@  discard block
 block discarded – undo
490 490
         // in 4.1, $db_state would have only been a simple string like '4.1.0',
491 491
         // but in 4.2+ it should be an array with at least key 'Core' and the value of that plugin's
492 492
         // db, and possibly other keys for other addons like 'Calendar','Permissions',etc
493
-        if (! is_array($db_state)) {
493
+        if ( ! is_array($db_state)) {
494 494
             $db_state = ['Core' => $db_state];
495 495
             update_option(EE_Data_Migration_Manager::current_database_state, $db_state);
496 496
         }
@@ -534,7 +534,7 @@  discard block
 block discarded – undo
534 534
                 // check if this version script is DONE or not; or if it's never been run
535 535
                 if (
536 536
                     ! $scripts_ran
537
-                    || ! isset($scripts_ran[ $script_converts_plugin_slug ][ $script_converts_to_version ])
537
+                    || ! isset($scripts_ran[$script_converts_plugin_slug][$script_converts_to_version])
538 538
                 ) {
539 539
                     // we haven't run this conversion script before
540 540
                     // now check if it applies...
@@ -545,28 +545,28 @@  discard block
 block discarded – undo
545 545
                     /* @var $script EE_Data_Migration_Script_Base */
546 546
                     $can_migrate = $script->can_migrate_from_version($theoretical_database_state);
547 547
                     if ($can_migrate) {
548
-                        $script_classes_that_should_run_per_iteration[ $iteration ][ $script->priority() ][] = $script;
548
+                        $script_classes_that_should_run_per_iteration[$iteration][$script->priority()][] = $script;
549 549
                         $migrates_to_version                                                                 =
550 550
                             $script->migrates_to_version();
551
-                        $next_database_state_to_consider[ $migrates_to_version['slug'] ]                     =
551
+                        $next_database_state_to_consider[$migrates_to_version['slug']]                     =
552 552
                             $migrates_to_version['version'];
553
-                        unset($script_class_and_filepaths_available[ $classname ]);
553
+                        unset($script_class_and_filepaths_available[$classname]);
554 554
                     }
555 555
                 } elseif (
556
-                    $scripts_ran[ $script_converts_plugin_slug ][ $script_converts_to_version ]
556
+                    $scripts_ran[$script_converts_plugin_slug][$script_converts_to_version]
557 557
                           instanceof
558 558
                           EE_Data_Migration_Script_Base
559 559
                 ) {
560 560
                     // this script has been run, or at least started
561
-                    $script = $scripts_ran[ $script_converts_plugin_slug ][ $script_converts_to_version ];
561
+                    $script = $scripts_ran[$script_converts_plugin_slug][$script_converts_to_version];
562 562
                     if ($script->get_status() !== self::status_completed) {
563 563
                         // this script is already underway... keep going with it
564
-                        $script_classes_that_should_run_per_iteration[ $iteration ][ $script->priority() ][] = $script;
564
+                        $script_classes_that_should_run_per_iteration[$iteration][$script->priority()][] = $script;
565 565
                         $migrates_to_version                                                                 =
566 566
                             $script->migrates_to_version();
567
-                        $next_database_state_to_consider[ $migrates_to_version['slug'] ]                     =
567
+                        $next_database_state_to_consider[$migrates_to_version['slug']]                     =
568 568
                             $migrates_to_version['version'];
569
-                        unset($script_class_and_filepaths_available[ $classname ]);
569
+                        unset($script_class_and_filepaths_available[$classname]);
570 570
                     }
571 571
                     // else it must have a status that indicates it has finished,
572 572
                     // so we don't want to try and run it again
@@ -575,14 +575,14 @@  discard block
 block discarded – undo
575 575
                 // or was simply removed from EE? either way, it's certainly not runnable!
576 576
             }
577 577
             $iteration++;
578
-        } while ($next_database_state_to_consider !== $theoretical_database_state && $iteration < 6);
578
+        }while ($next_database_state_to_consider !== $theoretical_database_state && $iteration < 6);
579 579
         // ok we have all the scripts that should run, now let's make them into flat array
580 580
         $scripts_that_should_run = [];
581 581
         foreach ($script_classes_that_should_run_per_iteration as $scripts_at_priority) {
582 582
             ksort($scripts_at_priority);
583 583
             foreach ($scripts_at_priority as $scripts) {
584 584
                 foreach ($scripts as $script) {
585
-                    $scripts_that_should_run[ get_class($script) ] = $script;
585
+                    $scripts_that_should_run[get_class($script)] = $script;
586 586
                 }
587 587
             }
588 588
         }
@@ -608,7 +608,7 @@  discard block
 block discarded – undo
608 608
     public function get_last_ran_script($include_completed_scripts = false)
609 609
     {
610 610
         // make sure we've set up the class properties _last_ran_script and _last_ran_incomplete_script
611
-        if (! $this->_data_migrations_ran) {
611
+        if ( ! $this->_data_migrations_ran) {
612 612
             $this->get_data_migrations_ran();
613 613
         }
614 614
         if ($include_completed_scripts) {
@@ -645,10 +645,10 @@  discard block
 block discarded – undo
645 645
 
646 646
         try {
647 647
             $currently_executing_script = $this->get_last_ran_script();
648
-            if (! $currently_executing_script) {
648
+            if ( ! $currently_executing_script) {
649 649
                 // Find the next script that needs to execute
650 650
                 $scripts = $this->check_for_applicable_data_migration_scripts();
651
-                if (! $scripts) {
651
+                if ( ! $scripts) {
652 652
                     // huh, no more scripts to run... apparently we're done!
653 653
                     // but don't forget to make sure initial data is there
654 654
                     // we should be good to allow them to exit maintenance mode now
@@ -676,7 +676,7 @@  discard block
 block discarded – undo
676 676
                     $this->script_migrates_to_version(get_class($currently_executing_script));
677 677
                 $plugin_slug                                            = $migrates_to['slug'];
678 678
                 $version                                                = $migrates_to['version'];
679
-                $this->_data_migrations_ran[ $plugin_slug ][ $version ] = $currently_executing_script;
679
+                $this->_data_migrations_ran[$plugin_slug][$version] = $currently_executing_script;
680 680
             }
681 681
             $current_script_name = get_class($currently_executing_script);
682 682
         } catch (Exception $e) {
@@ -684,7 +684,7 @@  discard block
 block discarded – undo
684 684
 
685 685
             $message = sprintf(
686 686
                 esc_html__("Error Message: %sStack Trace:%s", "event_espresso"),
687
-                $e->getMessage() . '<br>',
687
+                $e->getMessage().'<br>',
688 688
                 $e->getTraceAsString()
689 689
             );
690 690
             // record it on the array of data migration scripts run. This will be overwritten next time we try and try to run data migrations
@@ -737,7 +737,7 @@  discard block
 block discarded – undo
737 737
                     ];
738 738
                     // check if there are any more after this one.
739 739
                     $scripts_remaining = $this->check_for_applicable_data_migration_scripts();
740
-                    if (! $scripts_remaining) {
740
+                    if ( ! $scripts_remaining) {
741 741
                         // we should be good to allow them to exit maintenance mode now
742 742
                         EE_Maintenance_Mode::instance()->set_maintenance_level(
743 743
                             EE_Maintenance_Mode::level_0_not_in_maintenance
@@ -837,7 +837,7 @@  discard block
 block discarded – undo
837 837
                 ),
838 838
                 'script'             => 'Unknown',
839 839
             ];
840
-            $this->add_error_to_migrations_ran($e->getMessage() . "; Stack trace:" . $e->getTraceAsString());
840
+            $this->add_error_to_migrations_ran($e->getMessage()."; Stack trace:".$e->getTraceAsString());
841 841
         }
842 842
         $warnings_etc = @ob_get_contents();
843 843
         ob_end_clean();
@@ -858,12 +858,12 @@  discard block
 block discarded – undo
858 858
      */
859 859
     public function update_current_database_state_to($slug_and_version = null)
860 860
     {
861
-        if (! $slug_and_version) {
861
+        if ( ! $slug_and_version) {
862 862
             // no version was provided, assume it should be at the current code version
863 863
             $slug_and_version = ['slug' => 'Core', 'version' => espresso_version()];
864 864
         }
865 865
         $current_database_state                              = get_option(self::current_database_state);
866
-        $current_database_state[ $slug_and_version['slug'] ] = $slug_and_version['version'];
866
+        $current_database_state[$slug_and_version['slug']] = $slug_and_version['version'];
867 867
         update_option(self::current_database_state, $current_database_state);
868 868
     }
869 869
 
@@ -883,15 +883,15 @@  discard block
 block discarded – undo
883 883
         $slug                   = $slug_and_version['slug'];
884 884
         $version                = $slug_and_version['version'];
885 885
         $current_database_state = get_option(self::current_database_state);
886
-        if (! isset($current_database_state[ $slug ])) {
886
+        if ( ! isset($current_database_state[$slug])) {
887 887
             return true;
888 888
         } else {
889 889
             // just compare the first 3 parts of version string, eg "4.7.1", not "4.7.1.dev.032" because DBs shouldn't change on nano version changes
890
-            $version_parts_current_db_state     = array_slice(explode('.', $current_database_state[ $slug ]), 0, 3);
890
+            $version_parts_current_db_state     = array_slice(explode('.', $current_database_state[$slug]), 0, 3);
891 891
             $version_parts_of_provided_db_state = array_slice(explode('.', $version), 0, 3);
892 892
             $needs_updating                     = false;
893 893
             foreach ($version_parts_current_db_state as $offset => $version_part_in_current_db_state) {
894
-                if ($version_part_in_current_db_state < $version_parts_of_provided_db_state[ $offset ]) {
894
+                if ($version_part_in_current_db_state < $version_parts_of_provided_db_state[$offset]) {
895 895
                     $needs_updating = true;
896 896
                     break;
897 897
                 }
@@ -913,7 +913,7 @@  discard block
 block discarded – undo
913 913
      */
914 914
     public function get_all_data_migration_scripts_available()
915 915
     {
916
-        if (! $this->_data_migration_class_to_filepath_map) {
916
+        if ( ! $this->_data_migration_class_to_filepath_map) {
917 917
             $this->_data_migration_class_to_filepath_map = [];
918 918
             foreach ($this->get_data_migration_script_folders() as $eeAddonClass => $folder_path) {
919 919
                 // strip any placeholders added to classname to make it a unique array key
@@ -922,7 +922,7 @@  discard block
 block discarded – undo
922 922
                     ? $eeAddonClass
923 923
                     : '';
924 924
                 $folder_path  = EEH_File::end_with_directory_separator($folder_path);
925
-                $files        = glob($folder_path . '*.dms.php');
925
+                $files        = glob($folder_path.'*.dms.php');
926 926
                 if (empty($files)) {
927 927
                     continue;
928 928
                 }
@@ -948,7 +948,7 @@  discard block
 block discarded – undo
948 948
                             '4.3.0.alpha.019'
949 949
                         );
950 950
                     }
951
-                    $this->_data_migration_class_to_filepath_map[ $classname ] = $file;
951
+                    $this->_data_migration_class_to_filepath_map[$classname] = $file;
952 952
                 }
953 953
             }
954 954
             EEH_Autoloader::register_autoloader($this->_data_migration_class_to_filepath_map);
@@ -1018,10 +1018,10 @@  discard block
 block discarded – undo
1018 1018
             $versions_migrated_to                 = 'Unknown.1.0.0';
1019 1019
             // now just to make sure appears as last (in case the were previously a fatal error like this)
1020 1020
             // delete the old one
1021
-            delete_option(self::data_migration_script_option_prefix . $versions_migrated_to);
1021
+            delete_option(self::data_migration_script_option_prefix.$versions_migrated_to);
1022 1022
         }
1023 1023
         update_option(
1024
-            self::data_migration_script_option_prefix . $versions_migrated_to,
1024
+            self::data_migration_script_option_prefix.$versions_migrated_to,
1025 1025
             $last_ran_migration_script_properties
1026 1026
         );
1027 1027
     }
@@ -1042,9 +1042,9 @@  discard block
 block discarded – undo
1042 1042
         $successful_updates = true;
1043 1043
         foreach ($this->_data_migrations_ran as $plugin_slug => $migrations_ran_for_plugin) {
1044 1044
             foreach ($migrations_ran_for_plugin as $version_string => $array_or_migration_obj) {
1045
-                $plugin_slug_for_use_in_option_name = $plugin_slug . ".";
1045
+                $plugin_slug_for_use_in_option_name = $plugin_slug.".";
1046 1046
                 $option_name                        =
1047
-                    self::data_migration_script_option_prefix . $plugin_slug_for_use_in_option_name . $version_string;
1047
+                    self::data_migration_script_option_prefix.$plugin_slug_for_use_in_option_name.$version_string;
1048 1048
                 $old_option_value                   = get_option($option_name);
1049 1049
                 if ($array_or_migration_obj instanceof EE_Data_Migration_Script_Base) {
1050 1050
                     $script_array_for_saving = $array_or_migration_obj->properties_as_array();
@@ -1056,7 +1056,7 @@  discard block
 block discarded – undo
1056 1056
                         $successful_updates = update_option($option_name, $array_or_migration_obj);
1057 1057
                     }
1058 1058
                 }
1059
-                if (! $successful_updates) {
1059
+                if ( ! $successful_updates) {
1060 1060
                     global $wpdb;
1061 1061
                     return $wpdb->last_error;
1062 1062
                 }
@@ -1091,7 +1091,7 @@  discard block
 block discarded – undo
1091 1091
      */
1092 1092
     public function _instantiate_script_from_properties_array($properties_array)
1093 1093
     {
1094
-        if (! isset($properties_array['class'])) {
1094
+        if ( ! isset($properties_array['class'])) {
1095 1095
             throw new EE_Error(
1096 1096
                 sprintf(
1097 1097
                     esc_html__("Properties array  has no 'class' properties. Here's what it has: %s", "event_espresso"),
@@ -1100,14 +1100,14 @@  discard block
 block discarded – undo
1100 1100
             );
1101 1101
         }
1102 1102
         $class_name = $properties_array['class'];
1103
-        if (! class_exists($class_name)) {
1103
+        if ( ! class_exists($class_name)) {
1104 1104
             throw new EE_Error(sprintf(
1105 1105
                 esc_html__("There is no migration script named %s", "event_espresso"),
1106 1106
                 $class_name
1107 1107
             ));
1108 1108
         }
1109 1109
         $class = new $class_name();
1110
-        if (! $class instanceof EE_Data_Migration_Script_Base) {
1110
+        if ( ! $class instanceof EE_Data_Migration_Script_Base) {
1111 1111
             throw new EE_Error(
1112 1112
                 sprintf(
1113 1113
                     esc_html__(
@@ -1183,8 +1183,8 @@  discard block
 block discarded – undo
1183 1183
     public function get_migration_ran($version, $plugin_slug = 'Core')
1184 1184
     {
1185 1185
         $migrations_ran = $this->get_data_migrations_ran();
1186
-        if (isset($migrations_ran[ $plugin_slug ]) && isset($migrations_ran[ $plugin_slug ][ $version ])) {
1187
-            return $migrations_ran[ $plugin_slug ][ $version ];
1186
+        if (isset($migrations_ran[$plugin_slug]) && isset($migrations_ran[$plugin_slug][$version])) {
1187
+            return $migrations_ran[$plugin_slug][$version];
1188 1188
         } else {
1189 1189
             return null;
1190 1190
         }
@@ -1248,7 +1248,7 @@  discard block
 block discarded – undo
1248 1248
     public function enqueue_db_initialization_for($plugin_slug)
1249 1249
     {
1250 1250
         $queue = $this->get_db_initialization_queue();
1251
-        if (! in_array($plugin_slug, $queue)) {
1251
+        if ( ! in_array($plugin_slug, $queue)) {
1252 1252
             $queue[] = $plugin_slug;
1253 1253
         }
1254 1254
         update_option(self::db_init_queue_option_name, $queue);
@@ -1267,7 +1267,7 @@  discard block
 block discarded – undo
1267 1267
         $queue = $this->get_db_initialization_queue();
1268 1268
         foreach ($queue as $plugin_slug) {
1269 1269
             $most_up_to_date_dms = $this->get_most_up_to_date_dms($plugin_slug);
1270
-            if (! $most_up_to_date_dms) {
1270
+            if ( ! $most_up_to_date_dms) {
1271 1271
                 // if there is NO DMS for this plugin, obviously there's no schema to verify anyways
1272 1272
                 $verify_db = false;
1273 1273
             } else {
Please login to merge, or discard this patch.
admin_pages/general_settings/General_Settings_Admin_Page.core.php 1 patch
Indentation   +1422 added lines, -1422 removed lines patch added patch discarded remove patch
@@ -20,1437 +20,1437 @@
 block discarded – undo
20 20
 class General_Settings_Admin_Page extends EE_Admin_Page
21 21
 {
22 22
 
23
-    /**
24
-     * @var EE_Core_Config
25
-     */
26
-    public $core_config;
27
-
28
-
29
-    /**
30
-     * Initialize basic properties.
31
-     */
32
-    protected function _init_page_props()
33
-    {
34
-        $this->page_slug        = GEN_SET_PG_SLUG;
35
-        $this->page_label       = GEN_SET_LABEL;
36
-        $this->_admin_base_url  = GEN_SET_ADMIN_URL;
37
-        $this->_admin_base_path = GEN_SET_ADMIN;
38
-
39
-        $this->core_config = EE_Registry::instance()->CFG->core;
40
-    }
41
-
42
-
43
-    /**
44
-     * Set ajax hooks
45
-     */
46
-    protected function _ajax_hooks()
47
-    {
48
-        add_action('wp_ajax_espresso_display_country_settings', [$this, 'display_country_settings']);
49
-        add_action('wp_ajax_espresso_display_country_states', [$this, 'display_country_states']);
50
-        add_action('wp_ajax_espresso_delete_state', [$this, 'delete_state'], 10, 3);
51
-        add_action('wp_ajax_espresso_add_new_state', [$this, 'add_new_state']);
52
-    }
53
-
54
-
55
-    /**
56
-     * More page properties initialization.
57
-     */
58
-    protected function _define_page_props()
59
-    {
60
-        $this->_admin_page_title = GEN_SET_LABEL;
61
-        $this->_labels           = ['publishbox' => esc_html__('Update Settings', 'event_espresso')];
62
-    }
63
-
64
-
65
-    /**
66
-     * Set page routes property.
67
-     */
68
-    protected function _set_page_routes()
69
-    {
70
-        $this->_page_routes = [
71
-            'critical_pages'                => [
72
-                'func'       => '_espresso_page_settings',
73
-                'capability' => 'manage_options',
74
-            ],
75
-            'update_espresso_page_settings' => [
76
-                'func'       => '_update_espresso_page_settings',
77
-                'capability' => 'manage_options',
78
-                'noheader'   => true,
79
-            ],
80
-            'default'                       => [
81
-                'func'       => '_your_organization_settings',
82
-                'capability' => 'manage_options',
83
-            ],
84
-
85
-            'update_your_organization_settings' => [
86
-                'func'       => '_update_your_organization_settings',
87
-                'capability' => 'manage_options',
88
-                'noheader'   => true,
89
-            ],
90
-
91
-            'admin_option_settings' => [
92
-                'func'       => '_admin_option_settings',
93
-                'capability' => 'manage_options',
94
-            ],
95
-
96
-            'update_admin_option_settings' => [
97
-                'func'       => '_update_admin_option_settings',
98
-                'capability' => 'manage_options',
99
-                'noheader'   => true,
100
-            ],
101
-
102
-            'country_settings' => [
103
-                'func'       => '_country_settings',
104
-                'capability' => 'manage_options',
105
-            ],
106
-
107
-            'update_country_settings' => [
108
-                'func'       => '_update_country_settings',
109
-                'capability' => 'manage_options',
110
-                'noheader'   => true,
111
-            ],
112
-
113
-            'display_country_settings' => [
114
-                'func'       => 'display_country_settings',
115
-                'capability' => 'manage_options',
116
-                'noheader'   => true,
117
-            ],
118
-
119
-            'add_new_state' => [
120
-                'func'       => 'add_new_state',
121
-                'capability' => 'manage_options',
122
-                'noheader'   => true,
123
-            ],
124
-
125
-            'delete_state'            => [
126
-                'func'       => 'delete_state',
127
-                'capability' => 'manage_options',
128
-                'noheader'   => true,
129
-            ],
130
-            'privacy_settings'        => [
131
-                'func'       => 'privacySettings',
132
-                'capability' => 'manage_options',
133
-            ],
134
-            'update_privacy_settings' => [
135
-                'func'               => 'updatePrivacySettings',
136
-                'capability'         => 'manage_options',
137
-                'noheader'           => true,
138
-                'headers_sent_route' => 'privacy_settings',
139
-            ],
140
-        ];
141
-    }
142
-
143
-
144
-    /**
145
-     * Set page configuration property
146
-     */
147
-    protected function _set_page_config()
148
-    {
149
-        $this->_page_config = [
150
-            'critical_pages'        => [
151
-                'nav'           => [
152
-                    'label' => esc_html__('Critical Pages', 'event_espresso'),
153
-                    'order' => 50,
154
-                ],
155
-                'metaboxes'     => array_merge($this->_default_espresso_metaboxes, ['_publish_post_box']),
156
-                'help_tabs'     => [
157
-                    'general_settings_critical_pages_help_tab' => [
158
-                        'title'    => esc_html__('Critical Pages', 'event_espresso'),
159
-                        'filename' => 'general_settings_critical_pages',
160
-                    ],
161
-                ],
162
-                'require_nonce' => false,
163
-            ],
164
-            'default'               => [
165
-                'nav'           => [
166
-                    'label' => esc_html__('Your Organization', 'event_espresso'),
167
-                    'order' => 20,
168
-                ],
169
-                'help_tabs'     => [
170
-                    'general_settings_your_organization_help_tab' => [
171
-                        'title'    => esc_html__('Your Organization', 'event_espresso'),
172
-                        'filename' => 'general_settings_your_organization',
173
-                    ],
174
-                ],
175
-                'metaboxes'     => array_merge($this->_default_espresso_metaboxes, ['_publish_post_box']),
176
-                'require_nonce' => false,
177
-            ],
178
-            'admin_option_settings' => [
179
-                'nav'           => [
180
-                    'label' => esc_html__('Admin Options', 'event_espresso'),
181
-                    'order' => 60,
182
-                ],
183
-                'metaboxes'     => array_merge($this->_default_espresso_metaboxes, ['_publish_post_box']),
184
-                'help_tabs'     => [
185
-                    'general_settings_admin_options_help_tab' => [
186
-                        'title'    => esc_html__('Admin Options', 'event_espresso'),
187
-                        'filename' => 'general_settings_admin_options',
188
-                    ],
189
-                ],
190
-                'require_nonce' => false,
191
-            ],
192
-            'country_settings'      => [
193
-                'nav'           => [
194
-                    'label' => esc_html__('Countries', 'event_espresso'),
195
-                    'order' => 70,
196
-                ],
197
-                'help_tabs'     => [
198
-                    'general_settings_countries_help_tab' => [
199
-                        'title'    => esc_html__('Countries', 'event_espresso'),
200
-                        'filename' => 'general_settings_countries',
201
-                    ],
202
-                ],
203
-                'require_nonce' => false,
204
-            ],
205
-            'privacy_settings'      => [
206
-                'nav'           => [
207
-                    'label' => esc_html__('Privacy', 'event_espresso'),
208
-                    'order' => 80,
209
-                ],
210
-                'metaboxes'     => array_merge($this->_default_espresso_metaboxes, ['_publish_post_box']),
211
-                'require_nonce' => false,
212
-            ],
213
-        ];
214
-    }
215
-
216
-
217
-    protected function _add_screen_options()
218
-    {
219
-    }
220
-
221
-
222
-    protected function _add_feature_pointers()
223
-    {
224
-    }
225
-
226
-
227
-    /**
228
-     * Enqueue global scripts and styles for all routes in the General Settings Admin Pages.
229
-     */
230
-    public function load_scripts_styles()
231
-    {
232
-        // styles
233
-        wp_enqueue_style('espresso-ui-theme');
234
-        // scripts
235
-        wp_enqueue_script('ee_admin_js');
236
-    }
237
-
238
-
239
-    /**
240
-     * Execute logic running on `admin_init`
241
-     */
242
-    public function admin_init()
243
-    {
244
-        EE_Registry::$i18n_js_strings['invalid_server_response'] = wp_strip_all_tags(
245
-            esc_html__(
246
-                'An error occurred! Your request may have been processed, but a valid response from the server was not received. Please refresh the page and try again.',
247
-                'event_espresso'
248
-            )
249
-        );
250
-        EE_Registry::$i18n_js_strings['error_occurred']          = wp_strip_all_tags(
251
-            esc_html__(
252
-                'An error occurred! Please refresh the page and try again.',
253
-                'event_espresso'
254
-            )
255
-        );
256
-        EE_Registry::$i18n_js_strings['confirm_delete_state']    = wp_strip_all_tags(
257
-            esc_html__(
258
-                'Are you sure you want to delete this State / Province?',
259
-                'event_espresso'
260
-            )
261
-        );
262
-        EE_Registry::$i18n_js_strings['ajax_url']                = admin_url(
263
-            'admin-ajax.php?page=espresso_general_settings',
264
-            is_ssl() ? 'https://' : 'http://'
265
-        );
266
-    }
267
-
268
-
269
-    public function admin_notices()
270
-    {
271
-    }
272
-
273
-
274
-    public function admin_footer_scripts()
275
-    {
276
-    }
277
-
278
-
279
-    /**
280
-     * Enqueue scripts and styles for the default route.
281
-     */
282
-    public function load_scripts_styles_default()
283
-    {
284
-        // styles
285
-        wp_enqueue_style('thickbox');
286
-        // scripts
287
-        wp_enqueue_script('media-upload');
288
-        wp_enqueue_script('thickbox');
289
-        wp_register_script(
290
-            'organization_settings',
291
-            GEN_SET_ASSETS_URL . 'your_organization_settings.js',
292
-            ['jquery', 'media-upload', 'thickbox'],
293
-            EVENT_ESPRESSO_VERSION,
294
-            true
295
-        );
296
-        wp_register_style('organization-css', GEN_SET_ASSETS_URL . 'organization.css', [], EVENT_ESPRESSO_VERSION);
297
-        wp_enqueue_script('organization_settings');
298
-        wp_enqueue_style('organization-css');
299
-        $confirm_image_delete = [
300
-            'text' => wp_strip_all_tags(
301
-                esc_html__(
302
-                    'Do you really want to delete this image? Please remember to save your settings to complete the removal.',
303
-                    'event_espresso'
304
-                )
305
-            ),
306
-        ];
307
-        wp_localize_script('organization_settings', 'confirm_image_delete', $confirm_image_delete);
308
-    }
309
-
310
-
311
-    /**
312
-     * Enqueue scripts and styles for the country settings route.
313
-     */
314
-    public function load_scripts_styles_country_settings()
315
-    {
316
-        // scripts
317
-        wp_register_script(
318
-            'gen_settings_countries',
319
-            GEN_SET_ASSETS_URL . 'gen_settings_countries.js',
320
-            ['ee_admin_js'],
321
-            EVENT_ESPRESSO_VERSION,
322
-            true
323
-        );
324
-        wp_register_style('organization-css', GEN_SET_ASSETS_URL . 'organization.css', [], EVENT_ESPRESSO_VERSION);
325
-        wp_enqueue_script('gen_settings_countries');
326
-        wp_enqueue_style('organization-css');
327
-    }
328
-
329
-
330
-    /*************        Espresso Pages        *************/
331
-    /**
332
-     * _espresso_page_settings
333
-     *
334
-     * @throws EE_Error
335
-     * @throws DomainException
336
-     * @throws DomainException
337
-     * @throws InvalidDataTypeException
338
-     * @throws InvalidArgumentException
339
-     */
340
-    protected function _espresso_page_settings()
341
-    {
342
-        // Check to make sure all of the main pages are set up properly,
343
-        // if not create the default pages and display an admin notice
344
-        EEH_Activation::verify_default_pages_exist();
345
-        $this->_transient_garbage_collection();
346
-
347
-        $this->_template_args['values'] = $this->_yes_no_values;
348
-
349
-        $this->_template_args['reg_page_id']  = $this->core_config->reg_page_id ?? null;
350
-        $this->_template_args['reg_page_obj'] = isset($this->core_config->reg_page_id)
351
-            ? get_post($this->core_config->reg_page_id)
352
-            : false;
353
-
354
-        $this->_template_args['txn_page_id']  = $this->core_config->txn_page_id ?? null;
355
-        $this->_template_args['txn_page_obj'] = isset($this->core_config->txn_page_id)
356
-            ? get_post($this->core_config->txn_page_id)
357
-            : false;
358
-
359
-        $this->_template_args['thank_you_page_id']  = $this->core_config->thank_you_page_id ?? null;
360
-        $this->_template_args['thank_you_page_obj'] = isset($this->core_config->thank_you_page_id)
361
-            ? get_post($this->core_config->thank_you_page_id)
362
-            : false;
363
-
364
-        $this->_template_args['cancel_page_id']  = $this->core_config->cancel_page_id ?? null;
365
-        $this->_template_args['cancel_page_obj'] = isset($this->core_config->cancel_page_id)
366
-            ? get_post($this->core_config->cancel_page_id)
367
-            : false;
368
-
369
-        $this->_set_add_edit_form_tags('update_espresso_page_settings');
370
-        $this->_set_publish_post_box_vars(null, false, false, null, false);
371
-        $this->_template_args['admin_page_content'] = EEH_Template::display_template(
372
-            GEN_SET_TEMPLATE_PATH . 'espresso_page_settings.template.php',
373
-            $this->_template_args,
374
-            true
375
-        );
376
-        $this->display_admin_page_with_sidebar();
377
-    }
378
-
379
-
380
-    /**
381
-     * Handler for updating espresso page settings.
382
-     *
383
-     * @throws EE_Error
384
-     */
385
-    protected function _update_espresso_page_settings()
386
-    {
387
-        // capture incoming request data && set page IDs
388
-        $this->core_config->reg_page_id       = $this->request->getRequestParam(
389
-            'reg_page_id',
390
-            $this->core_config->reg_page_id,
391
-            DataType::INT
392
-        );
393
-        $this->core_config->txn_page_id       = $this->request->getRequestParam(
394
-            'txn_page_id',
395
-            $this->core_config->txn_page_id,
396
-            DataType::INT
397
-        );
398
-        $this->core_config->thank_you_page_id = $this->request->getRequestParam(
399
-            'thank_you_page_id',
400
-            $this->core_config->thank_you_page_id,
401
-            DataType::INT
402
-        );
403
-        $this->core_config->cancel_page_id    = $this->request->getRequestParam(
404
-            'cancel_page_id',
405
-            $this->core_config->cancel_page_id,
406
-            DataType::INT
407
-        );
408
-
409
-        $this->core_config = apply_filters(
410
-            'FHEE__General_Settings_Admin_Page___update_espresso_page_settings__CFG_core',
411
-            $this->core_config,
412
-            $this->request->requestParams()
413
-        );
414
-
415
-        $what = esc_html__('Critical Pages & Shortcodes', 'event_espresso');
416
-        $this->_redirect_after_action(
417
-            $this->_update_espresso_configuration(
418
-                $what,
419
-                $this->core_config,
420
-                __FILE__,
421
-                __FUNCTION__,
422
-                __LINE__
423
-            ),
424
-            $what,
425
-            '',
426
-            [
427
-                'action' => 'critical_pages',
428
-            ],
429
-            true
430
-        );
431
-    }
432
-
433
-
434
-    /*************        Your Organization        *************/
435
-
436
-
437
-    /**
438
-     * @throws DomainException
439
-     * @throws EE_Error
440
-     * @throws InvalidArgumentException
441
-     * @throws InvalidDataTypeException
442
-     * @throws InvalidInterfaceException
443
-     */
444
-    protected function _your_organization_settings()
445
-    {
446
-        $this->_template_args['admin_page_content'] = '';
447
-        try {
448
-            /** @var OrganizationSettings $organization_settings_form */
449
-            $organization_settings_form = $this->loader->getShared(OrganizationSettings::class);
450
-
451
-            $this->_template_args['admin_page_content'] = EEH_HTML::div(
452
-                $organization_settings_form->display(),
453
-                '',
454
-                'padding'
455
-            );
456
-        } catch (Exception $e) {
457
-            EE_Error::add_error($e->getMessage(), __FILE__, __FUNCTION__, __LINE__);
458
-        }
459
-        $this->_set_add_edit_form_tags('update_your_organization_settings');
460
-        $this->_set_publish_post_box_vars(null, false, false, null, false);
461
-        $this->display_admin_page_with_sidebar();
462
-    }
463
-
464
-
465
-    /**
466
-     * Handler for updating organization settings.
467
-     *
468
-     * @throws EE_Error
469
-     */
470
-    protected function _update_your_organization_settings()
471
-    {
472
-        try {
473
-            /** @var OrganizationSettings $organization_settings_form */
474
-            $organization_settings_form = $this->loader->getShared(OrganizationSettings::class);
475
-
476
-            $success = $organization_settings_form->process($this->request->requestParams());
477
-
478
-            EE_Registry::instance()->CFG = apply_filters(
479
-                'FHEE__General_Settings_Admin_Page___update_your_organization_settings__CFG',
480
-                EE_Registry::instance()->CFG
481
-            );
482
-        } catch (Exception $e) {
483
-            EE_Error::add_error($e->getMessage(), __FILE__, __FUNCTION__, __LINE__);
484
-            $success = false;
485
-        }
486
-
487
-        if ($success) {
488
-            $success = $this->_update_espresso_configuration(
489
-                esc_html__('Your Organization Settings', 'event_espresso'),
490
-                EE_Registry::instance()->CFG,
491
-                __FILE__,
492
-                __FUNCTION__,
493
-                __LINE__
494
-            );
495
-        }
496
-
497
-        $this->_redirect_after_action($success, '', '', ['action' => 'default'], true);
498
-    }
499
-
500
-
501
-
502
-    /*************        Admin Options        *************/
503
-
504
-
505
-    /**
506
-     * _admin_option_settings
507
-     *
508
-     * @throws EE_Error
509
-     * @throws LogicException
510
-     */
511
-    protected function _admin_option_settings()
512
-    {
513
-        $this->_template_args['admin_page_content'] = '';
514
-        try {
515
-            $admin_options_settings_form = new AdminOptionsSettings(EE_Registry::instance());
516
-            // still need this for the old school form in Extend_General_Settings_Admin_Page
517
-            $this->_template_args['values'] = $this->_yes_no_values;
518
-            // also need to account for the do_action that was in the old template
519
-            $admin_options_settings_form->setTemplateArgs($this->_template_args);
520
-            $this->_template_args['admin_page_content'] = $admin_options_settings_form->display();
521
-        } catch (Exception $e) {
522
-            EE_Error::add_error($e->getMessage(), __FILE__, __FUNCTION__, __LINE__);
523
-        }
524
-        $this->_set_add_edit_form_tags('update_admin_option_settings');
525
-        $this->_set_publish_post_box_vars(null, false, false, null, false);
526
-        $this->display_admin_page_with_sidebar();
527
-    }
528
-
529
-
530
-    /**
531
-     * _update_admin_option_settings
532
-     *
533
-     * @throws EE_Error
534
-     * @throws InvalidDataTypeException
535
-     * @throws InvalidFormSubmissionException
536
-     * @throws InvalidArgumentException
537
-     * @throws LogicException
538
-     */
539
-    protected function _update_admin_option_settings()
540
-    {
541
-        try {
542
-            $admin_options_settings_form = new AdminOptionsSettings(EE_Registry::instance());
543
-            $admin_options_settings_form->process(
544
-                $this->request->getRequestParam(
545
-                    $admin_options_settings_form->slug(),
546
-                    [],
547
-                    DataType::OBJECT // need to change this to ARRAY after min PHP version gets bumped to 7+
548
-                )
549
-            );
550
-            EE_Registry::instance()->CFG->admin = apply_filters(
551
-                'FHEE__General_Settings_Admin_Page___update_admin_option_settings__CFG_admin',
552
-                EE_Registry::instance()->CFG->admin
553
-            );
554
-        } catch (Exception $e) {
555
-            EE_Error::add_error($e->getMessage(), __FILE__, __FUNCTION__, __LINE__);
556
-        }
557
-        $this->_redirect_after_action(
558
-            apply_filters(
559
-                'FHEE__General_Settings_Admin_Page___update_admin_option_settings__success',
560
-                $this->_update_espresso_configuration(
561
-                    esc_html__('Admin Options', 'event_espresso'),
562
-                    EE_Registry::instance()->CFG->admin,
563
-                    __FILE__,
564
-                    __FUNCTION__,
565
-                    __LINE__
566
-                )
567
-            ),
568
-            esc_html__('Admin Options', 'event_espresso'),
569
-            'updated',
570
-            ['action' => 'admin_option_settings']
571
-        );
572
-    }
573
-
574
-
575
-    /*************        Countries        *************/
576
-
577
-
578
-    /**
579
-     * @param string|null $default
580
-     * @return string
581
-     */
582
-    protected function getCountryISO(?string $default = null): string
583
-    {
584
-        $default = $default ?? $this->getCountryIsoForSite();
585
-        $CNT_ISO = $this->request->getRequestParam('country', $default);
586
-        $CNT_ISO = $this->request->getRequestParam('CNT_ISO', $CNT_ISO);
587
-        return strtoupper($CNT_ISO);
588
-    }
589
-
590
-
591
-    /**
592
-     * @return string
593
-     */
594
-    protected function getCountryIsoForSite(): string
595
-    {
596
-        return ! empty(EE_Registry::instance()->CFG->organization->CNT_ISO)
597
-            ? EE_Registry::instance()->CFG->organization->CNT_ISO
598
-            : 'US';
599
-    }
600
-
601
-
602
-    /**
603
-     * @param string          $CNT_ISO
604
-     * @param EE_Country|null $country
605
-     * @return EE_Base_Class|EE_Country
606
-     * @throws EE_Error
607
-     * @throws InvalidArgumentException
608
-     * @throws InvalidDataTypeException
609
-     * @throws InvalidInterfaceException
610
-     * @throws ReflectionException
611
-     */
612
-    protected function verifyOrGetCountryFromIso(string $CNT_ISO, ?EE_Country $country = null)
613
-    {
614
-        /** @var EE_Country $country */
615
-        return $country instanceof EE_Country && $country->ID() === $CNT_ISO
616
-            ? $country
617
-            : EEM_Country::instance()->get_one_by_ID($CNT_ISO);
618
-    }
619
-
620
-
621
-    /**
622
-     * Output Country Settings view.
623
-     *
624
-     * @throws DomainException
625
-     * @throws EE_Error
626
-     * @throws InvalidArgumentException
627
-     * @throws InvalidDataTypeException
628
-     * @throws InvalidInterfaceException
629
-     * @throws ReflectionException
630
-     */
631
-    protected function _country_settings()
632
-    {
633
-        $CNT_ISO = $this->getCountryISO();
634
-
635
-        $this->_template_args['values']    = $this->_yes_no_values;
636
-        $this->_template_args['countries'] = new EE_Question_Form_Input(
637
-            EE_Question::new_instance(
638
-                [
639
-                    'QST_ID'           => 0,
640
-                    'QST_display_text' => esc_html__('Select Country', 'event_espresso'),
641
-                    'QST_system'       => 'admin-country',
642
-                ]
643
-            ),
644
-            EE_Answer::new_instance(
645
-                [
646
-                    'ANS_ID'    => 0,
647
-                    'ANS_value' => $CNT_ISO,
648
-                ]
649
-            ),
650
-            [
651
-                'input_id'       => 'country',
652
-                'input_name'     => 'country',
653
-                'input_prefix'   => '',
654
-                'append_qstn_id' => false,
655
-            ]
656
-        );
657
-
658
-        $country = $this->verifyOrGetCountryFromIso($CNT_ISO);
659
-        add_filter('FHEE__EEH_Form_Fields__label_html', [$this, 'country_form_field_label_wrap'], 10);
660
-        add_filter('FHEE__EEH_Form_Fields__input_html', [$this, 'country_form_field_input__wrap'], 10);
661
-        $this->_template_args['country_details_settings'] = $this->display_country_settings(
662
-            $country->ID(),
663
-            $country
664
-        );
665
-        $this->_template_args['country_states_settings']  = $this->display_country_states(
666
-            $country->ID(),
667
-            $country
668
-        );
669
-        $this->_template_args['CNT_name_for_site']        = $country->name();
670
-
671
-        $this->_set_add_edit_form_tags('update_country_settings');
672
-        $this->_set_publish_post_box_vars(null, false, false, null, false);
673
-        $this->_template_args['admin_page_content'] = EEH_Template::display_template(
674
-            GEN_SET_TEMPLATE_PATH . 'countries_settings.template.php',
675
-            $this->_template_args,
676
-            true
677
-        );
678
-        $this->display_admin_page_with_no_sidebar();
679
-    }
680
-
681
-
682
-    /**
683
-     * @param string          $CNT_ISO
684
-     * @param EE_Country|null $country
685
-     * @return string
686
-     * @throws DomainException
687
-     * @throws EE_Error
688
-     * @throws InvalidArgumentException
689
-     * @throws InvalidDataTypeException
690
-     * @throws InvalidInterfaceException
691
-     * @throws ReflectionException
692
-     */
693
-    public function display_country_settings(string $CNT_ISO = '', ?EE_Country $country = null): string
694
-    {
695
-        $CNT_ISO          = $this->getCountryISO($CNT_ISO);
696
-        $CNT_ISO_for_site = $this->getCountryIsoForSite();
697
-
698
-        if (! $CNT_ISO) {
699
-            return '';
700
-        }
701
-
702
-        // for ajax
703
-        remove_all_filters('FHEE__EEH_Form_Fields__label_html');
704
-        remove_all_filters('FHEE__EEH_Form_Fields__input_html');
705
-        add_filter('FHEE__EEH_Form_Fields__label_html', [$this, 'country_form_field_label_wrap'], 10, 2);
706
-        add_filter('FHEE__EEH_Form_Fields__input_html', [$this, 'country_form_field_input__wrap'], 10, 2);
707
-        $country                                  = $this->verifyOrGetCountryFromIso($CNT_ISO, $country);
708
-        $CNT_cur_disabled                         = $CNT_ISO !== $CNT_ISO_for_site;
709
-        $this->_template_args['CNT_cur_disabled'] = $CNT_cur_disabled;
710
-
711
-        $country_input_types            = [
712
-            'CNT_active'      => [
713
-                'type'             => 'RADIO_BTN',
714
-                'input_name'       => 'cntry[' . $CNT_ISO . ']',
715
-                'class'            => '',
716
-                'options'          => $this->_yes_no_values,
717
-                'use_desc_4_label' => true,
718
-            ],
719
-            'CNT_ISO'         => [
720
-                'type'       => 'TEXT',
721
-                'input_name' => 'cntry[' . $CNT_ISO . ']',
722
-                'class'      => 'small-text',
723
-            ],
724
-            'CNT_ISO3'        => [
725
-                'type'       => 'TEXT',
726
-                'input_name' => 'cntry[' . $CNT_ISO . ']',
727
-                'class'      => 'small-text',
728
-            ],
729
-            // 'RGN_ID'          => [
730
-            //     'type'       => 'TEXT',
731
-            //     'input_name' => 'cntry[' . $CNT_ISO . ']',
732
-            //     'class'      => 'ee-input-size--small',
733
-            // ],
734
-            'CNT_name'        => [
735
-                'type'       => 'TEXT',
736
-                'input_name' => 'cntry[' . $CNT_ISO . ']',
737
-                'class'      => 'regular-text',
738
-            ],
739
-            'CNT_cur_code'    => [
740
-                'type'       => 'TEXT',
741
-                'input_name' => 'cntry[' . $CNT_ISO . ']',
742
-                'class'      => 'small-text',
743
-                'disabled'   => $CNT_cur_disabled,
744
-            ],
745
-            'CNT_cur_single'  => [
746
-                'type'       => 'TEXT',
747
-                'input_name' => 'cntry[' . $CNT_ISO . ']',
748
-                'class'      => 'medium-text',
749
-                'disabled'   => $CNT_cur_disabled,
750
-            ],
751
-            'CNT_cur_plural'  => [
752
-                'type'       => 'TEXT',
753
-                'input_name' => 'cntry[' . $CNT_ISO . ']',
754
-                'class'      => 'medium-text',
755
-                'disabled'   => $CNT_cur_disabled,
756
-            ],
757
-            'CNT_cur_sign'    => [
758
-                'type'         => 'TEXT',
759
-                'input_name'   => 'cntry[' . $CNT_ISO . ']',
760
-                'class'        => 'small-text',
761
-                'htmlentities' => false,
762
-                'disabled'     => $CNT_cur_disabled,
763
-            ],
764
-            'CNT_cur_sign_b4' => [
765
-                'type'             => 'RADIO_BTN',
766
-                'input_name'       => 'cntry[' . $CNT_ISO . ']',
767
-                'class'            => '',
768
-                'options'          => $this->_yes_no_values,
769
-                'use_desc_4_label' => true,
770
-                'disabled'         => $CNT_cur_disabled,
771
-            ],
772
-            'CNT_cur_dec_plc' => [
773
-                'type'       => 'RADIO_BTN',
774
-                'input_name' => 'cntry[' . $CNT_ISO . ']',
775
-                'class'      => '',
776
-                'options'    => [
777
-                    ['id' => 0, 'text' => ''],
778
-                    ['id' => 1, 'text' => ''],
779
-                    ['id' => 2, 'text' => ''],
780
-                    ['id' => 3, 'text' => ''],
781
-                ],
782
-                'disabled'   => $CNT_cur_disabled,
783
-            ],
784
-            'CNT_cur_dec_mrk' => [
785
-                'type'             => 'RADIO_BTN',
786
-                'input_name'       => 'cntry[' . $CNT_ISO . ']',
787
-                'class'            => '',
788
-                'options'          => [
789
-                    [
790
-                        'id'   => ',',
791
-                        'text' => esc_html__(', (comma)', 'event_espresso'),
792
-                    ],
793
-                    ['id' => '.', 'text' => esc_html__('. (decimal)', 'event_espresso')],
794
-                ],
795
-                'use_desc_4_label' => true,
796
-                'disabled'         => $CNT_cur_disabled,
797
-            ],
798
-            'CNT_cur_thsnds'  => [
799
-                'type'             => 'RADIO_BTN',
800
-                'input_name'       => 'cntry[' . $CNT_ISO . ']',
801
-                'class'            => '',
802
-                'options'          => [
803
-                    [
804
-                        'id'   => ',',
805
-                        'text' => esc_html__(', (comma)', 'event_espresso'),
806
-                    ],
807
-                    [
808
-                        'id'   => '.',
809
-                        'text' => esc_html__('. (decimal)', 'event_espresso'),
810
-                    ],
811
-                    [
812
-                        'id'   => '&nbsp;',
813
-                        'text' => esc_html__('(space)', 'event_espresso'),
814
-                    ],
815
-                    [
816
-                        'id'   => '_',
817
-                        'text' => esc_html__('_ (underscore)', 'event_espresso'),
818
-                    ],
819
-                    [
820
-                        'id'   => "'",
821
-                        'text' => esc_html__("' (apostrophe)", 'event_espresso'),
822
-                    ],
823
-                ],
824
-                'use_desc_4_label' => true,
825
-                'disabled'         => $CNT_cur_disabled,
826
-            ],
827
-            'CNT_tel_code'    => [
828
-                'type'       => 'TEXT',
829
-                'input_name' => 'cntry[' . $CNT_ISO . ']',
830
-                'class'      => 'small-text',
831
-            ],
832
-            'CNT_is_EU'       => [
833
-                'type'             => 'RADIO_BTN',
834
-                'input_name'       => 'cntry[' . $CNT_ISO . ']',
835
-                'class'            => '',
836
-                'options'          => $this->_yes_no_values,
837
-                'use_desc_4_label' => true,
838
-            ],
839
-        ];
840
-        $this->_template_args['inputs'] = EE_Question_Form_Input::generate_question_form_inputs_for_object(
841
-            $country,
842
-            $country_input_types
843
-        );
844
-        $country_details_settings       = EEH_Template::display_template(
845
-            GEN_SET_TEMPLATE_PATH . 'country_details_settings.template.php',
846
-            $this->_template_args,
847
-            true
848
-        );
849
-
850
-        if (defined('DOING_AJAX')) {
851
-            $notices = EE_Error::get_notices(false, false, false);
852
-            echo wp_json_encode(
853
-                [
854
-                    'return_data' => $country_details_settings,
855
-                    'success'     => $notices['success'],
856
-                    'errors'      => $notices['errors'],
857
-                ]
858
-            );
859
-            die();
860
-        }
861
-        return $country_details_settings;
862
-    }
863
-
864
-
865
-    /**
866
-     * @param string          $CNT_ISO
867
-     * @param EE_Country|null $country
868
-     * @return string
869
-     * @throws DomainException
870
-     * @throws EE_Error
871
-     * @throws InvalidArgumentException
872
-     * @throws InvalidDataTypeException
873
-     * @throws InvalidInterfaceException
874
-     * @throws ReflectionException
875
-     */
876
-    public function display_country_states(string $CNT_ISO = '', ?EE_Country $country = null): string
877
-    {
878
-        $CNT_ISO = $this->getCountryISO($CNT_ISO);
879
-        if (! $CNT_ISO) {
880
-            return '';
881
-        }
882
-        // for ajax
883
-        remove_all_filters('FHEE__EEH_Form_Fields__label_html');
884
-        remove_all_filters('FHEE__EEH_Form_Fields__input_html');
885
-        add_filter('FHEE__EEH_Form_Fields__label_html', [$this, 'state_form_field_label_wrap'], 10, 2);
886
-        add_filter('FHEE__EEH_Form_Fields__input_html', [$this, 'state_form_field_input__wrap'], 10);
887
-        $states = EEM_State::instance()->get_all_states_for_these_countries([$CNT_ISO => $CNT_ISO]);
888
-        if (empty($states)) {
889
-            /** @var EventEspresso\core\services\address\CountrySubRegionDao $countrySubRegionDao */
890
-            $countrySubRegionDao = $this->loader->getShared(
891
-                'EventEspresso\core\services\address\CountrySubRegionDao'
892
-            );
893
-            if ($countrySubRegionDao instanceof EventEspresso\core\services\address\CountrySubRegionDao) {
894
-                $country = $this->verifyOrGetCountryFromIso($CNT_ISO, $country);
895
-                if ($countrySubRegionDao->saveCountrySubRegions($country)) {
896
-                    $states = EEM_State::instance()->get_all_states_for_these_countries([$CNT_ISO => $CNT_ISO]);
897
-                }
898
-            }
899
-        }
900
-        if (is_array($states)) {
901
-            foreach ($states as $STA_ID => $state) {
902
-                if ($state instanceof EE_State) {
903
-                    $inputs = EE_Question_Form_Input::generate_question_form_inputs_for_object(
904
-                        $state,
905
-                        [
906
-                            'STA_abbrev' => [
907
-                                'type'             => 'TEXT',
908
-                                'label'            => esc_html__('Code', 'event_espresso'),
909
-                                'input_name'       => 'states[' . $STA_ID . ']',
910
-                                'class'            => 'small-text',
911
-                                'add_mobile_label' => true,
912
-                            ],
913
-                            'STA_name'   => [
914
-                                'type'             => 'TEXT',
915
-                                'label'            => esc_html__('Name', 'event_espresso'),
916
-                                'input_name'       => 'states[' . $STA_ID . ']',
917
-                                'class'            => 'regular-text',
918
-                                'add_mobile_label' => true,
919
-                            ],
920
-                            'STA_active' => [
921
-                                'type'             => 'RADIO_BTN',
922
-                                'label'            => esc_html__(
923
-                                    'State Appears in Dropdown Select Lists',
924
-                                    'event_espresso'
925
-                                ),
926
-                                'input_name'       => 'states[' . $STA_ID . ']',
927
-                                'options'          => $this->_yes_no_values,
928
-                                'use_desc_4_label' => true,
929
-                                'add_mobile_label' => true,
930
-                            ],
931
-                        ]
932
-                    );
933
-
934
-                    $delete_state_url = EE_Admin_Page::add_query_args_and_nonce(
935
-                        [
936
-                            'action'     => 'delete_state',
937
-                            'STA_ID'     => $STA_ID,
938
-                            'CNT_ISO'    => $CNT_ISO,
939
-                            'STA_abbrev' => $state->abbrev(),
940
-                        ],
941
-                        GEN_SET_ADMIN_URL
942
-                    );
943
-
944
-                    $this->_template_args['states'][ $STA_ID ]['inputs']           = $inputs;
945
-                    $this->_template_args['states'][ $STA_ID ]['delete_state_url'] = $delete_state_url;
946
-                }
947
-            }
948
-        } else {
949
-            $this->_template_args['states'] = false;
950
-        }
951
-
952
-        $this->_template_args['add_new_state_url'] = EE_Admin_Page::add_query_args_and_nonce(
953
-            ['action' => 'add_new_state'],
954
-            GEN_SET_ADMIN_URL
955
-        );
956
-
957
-        $state_details_settings = EEH_Template::display_template(
958
-            GEN_SET_TEMPLATE_PATH . 'state_details_settings.template.php',
959
-            $this->_template_args,
960
-            true
961
-        );
962
-
963
-        if (defined('DOING_AJAX')) {
964
-            $notices = EE_Error::get_notices(false, false, false);
965
-            echo wp_json_encode(
966
-                [
967
-                    'return_data' => $state_details_settings,
968
-                    'success'     => $notices['success'],
969
-                    'errors'      => $notices['errors'],
970
-                ]
971
-            );
972
-            die();
973
-        }
974
-        return $state_details_settings;
975
-    }
976
-
977
-
978
-    /**
979
-     * @return void
980
-     * @throws EE_Error
981
-     * @throws InvalidArgumentException
982
-     * @throws InvalidDataTypeException
983
-     * @throws InvalidInterfaceException
984
-     * @throws ReflectionException
985
-     */
986
-    public function add_new_state()
987
-    {
988
-        $success = true;
989
-        $CNT_ISO = $this->getCountryISO('');
990
-        if (! $CNT_ISO) {
991
-            EE_Error::add_error(
992
-                esc_html__('No Country ISO code or an invalid Country ISO code was received.', 'event_espresso'),
993
-                __FILE__,
994
-                __FUNCTION__,
995
-                __LINE__
996
-            );
997
-            $success = false;
998
-        }
999
-        $STA_abbrev = $this->request->getRequestParam('STA_abbrev');
1000
-        if (! $STA_abbrev) {
1001
-            EE_Error::add_error(
1002
-                esc_html__('No State ISO code or an invalid State ISO code was received.', 'event_espresso'),
1003
-                __FILE__,
1004
-                __FUNCTION__,
1005
-                __LINE__
1006
-            );
1007
-            $success = false;
1008
-        }
1009
-        $STA_name = $this->request->getRequestParam('STA_name');
1010
-        if (! $STA_name) {
1011
-            EE_Error::add_error(
1012
-                esc_html__('No State name or an invalid State name was received.', 'event_espresso'),
1013
-                __FILE__,
1014
-                __FUNCTION__,
1015
-                __LINE__
1016
-            );
1017
-            $success = false;
1018
-        }
1019
-
1020
-        if ($success) {
1021
-            $cols_n_values = [
1022
-                'CNT_ISO'    => $CNT_ISO,
1023
-                'STA_abbrev' => $STA_abbrev,
1024
-                'STA_name'   => $STA_name,
1025
-                'STA_active' => true,
1026
-            ];
1027
-            $success       = EEM_State::instance()->insert($cols_n_values);
1028
-            EE_Error::add_success(esc_html__('The State was added successfully.', 'event_espresso'));
1029
-        }
1030
-
1031
-        if (defined('DOING_AJAX')) {
1032
-            $notices = EE_Error::get_notices(false, false, false);
1033
-            echo wp_json_encode(array_merge($notices, ['return_data' => $CNT_ISO]));
1034
-            die();
1035
-        } else {
1036
-            $this->_redirect_after_action(
1037
-                $success,
1038
-                esc_html__('State', 'event_espresso'),
1039
-                'added',
1040
-                ['action' => 'country_settings']
1041
-            );
1042
-        }
1043
-    }
1044
-
1045
-
1046
-    /**
1047
-     * @return void
1048
-     * @throws EE_Error
1049
-     * @throws InvalidArgumentException
1050
-     * @throws InvalidDataTypeException
1051
-     * @throws InvalidInterfaceException
1052
-     * @throws ReflectionException
1053
-     */
1054
-    public function delete_state()
1055
-    {
1056
-        $CNT_ISO    = $this->getCountryISO();
1057
-        $STA_ID     = $this->request->getRequestParam('STA_ID');
1058
-        $STA_abbrev = $this->request->getRequestParam('STA_abbrev');
1059
-
1060
-        if (! $STA_ID) {
1061
-            EE_Error::add_error(
1062
-                esc_html__('No State ID or an invalid State ID was received.', 'event_espresso'),
1063
-                __FILE__,
1064
-                __FUNCTION__,
1065
-                __LINE__
1066
-            );
1067
-            return;
1068
-        }
1069
-
1070
-        $success = EEM_State::instance()->delete_by_ID($STA_ID);
1071
-        if ($success !== false) {
1072
-            do_action(
1073
-                'AHEE__General_Settings_Admin_Page__delete_state__state_deleted',
1074
-                $CNT_ISO,
1075
-                $STA_ID,
1076
-                ['STA_abbrev' => $STA_abbrev]
1077
-            );
1078
-            EE_Error::add_success(esc_html__('The State was deleted successfully.', 'event_espresso'));
1079
-        }
1080
-        if (defined('DOING_AJAX')) {
1081
-            $notices                = EE_Error::get_notices(false);
1082
-            $notices['return_data'] = true;
1083
-            echo wp_json_encode($notices);
1084
-            die();
1085
-        } else {
1086
-            $this->_redirect_after_action(
1087
-                $success,
1088
-                esc_html__('State', 'event_espresso'),
1089
-                'deleted',
1090
-                ['action' => 'country_settings']
1091
-            );
1092
-        }
1093
-    }
1094
-
1095
-
1096
-    /**
1097
-     *        _update_country_settings
1098
-     *
1099
-     * @return void
1100
-     * @throws EE_Error
1101
-     * @throws InvalidArgumentException
1102
-     * @throws InvalidDataTypeException
1103
-     * @throws InvalidInterfaceException
1104
-     * @throws ReflectionException
1105
-     */
1106
-    protected function _update_country_settings()
1107
-    {
1108
-        $CNT_ISO = $this->getCountryISO();
1109
-        if (! $CNT_ISO) {
1110
-            EE_Error::add_error(
1111
-                esc_html__('No Country ISO code or an invalid Country ISO code was received.', 'event_espresso'),
1112
-                __FILE__,
1113
-                __FUNCTION__,
1114
-                __LINE__
1115
-            );
1116
-            return;
1117
-        }
1118
-
1119
-        $country = $this->verifyOrGetCountryFromIso($CNT_ISO);
1120
-
1121
-        $cols_n_values                    = [];
1122
-        $cols_n_values['CNT_ISO3']        = strtoupper(
1123
-            $this->request->getRequestParam('cntry', $country->ISO3())
1124
-        );
1125
-        $cols_n_values['CNT_name']        = $this->request->getRequestParam(
1126
-            "cntry[$CNT_ISO][CNT_name]",
1127
-            $country->name()
1128
-        );
1129
-        $cols_n_values['CNT_cur_code']    = strtoupper(
1130
-            $this->request->getRequestParam(
1131
-                "cntry[$CNT_ISO][CNT_cur_code]",
1132
-                $country->currency_code()
1133
-            )
1134
-        );
1135
-        $cols_n_values['CNT_cur_single']  = $this->request->getRequestParam(
1136
-            "cntry[$CNT_ISO][CNT_cur_single]",
1137
-            $country->currency_name_single()
1138
-        );
1139
-        $cols_n_values['CNT_cur_plural']  = $this->request->getRequestParam(
1140
-            "cntry[$CNT_ISO][CNT_cur_plural]",
1141
-            $country->currency_name_plural()
1142
-        );
1143
-        $cols_n_values['CNT_cur_sign']    = $this->request->getRequestParam(
1144
-            "cntry[$CNT_ISO][CNT_cur_sign]",
1145
-            $country->currency_sign()
1146
-        );
1147
-        $cols_n_values['CNT_cur_sign_b4'] = $this->request->getRequestParam(
1148
-            "cntry[$CNT_ISO][CNT_cur_sign_b4]",
1149
-            $country->currency_sign_before(),
1150
-            DataType::BOOL
1151
-        );
1152
-        $cols_n_values['CNT_cur_dec_plc'] = $this->request->getRequestParam(
1153
-            "cntry[$CNT_ISO][CNT_cur_dec_plc]",
1154
-            $country->currency_decimal_places()
1155
-        );
1156
-        $cols_n_values['CNT_cur_dec_mrk'] = $this->request->getRequestParam(
1157
-            "cntry[$CNT_ISO][CNT_cur_dec_mrk]",
1158
-            $country->currency_decimal_mark()
1159
-        );
1160
-        $cols_n_values['CNT_cur_thsnds']  = $this->request->getRequestParam(
1161
-            "cntry[$CNT_ISO][CNT_cur_thsnds]",
1162
-            $country->currency_thousands_separator()
1163
-        );
1164
-        $cols_n_values['CNT_tel_code']    = $this->request->getRequestParam(
1165
-            "cntry[$CNT_ISO][CNT_tel_code]",
1166
-            $country->telephoneCode()
1167
-        );
1168
-        $cols_n_values['CNT_active']      = $this->request->getRequestParam(
1169
-            "cntry[$CNT_ISO][CNT_active]",
1170
-            $country->isActive(),
1171
-            DataType::BOOL
1172
-        );
1173
-
1174
-        // allow filtering of country data
1175
-        $cols_n_values = apply_filters(
1176
-            'FHEE__General_Settings_Admin_Page___update_country_settings__cols_n_values',
1177
-            $cols_n_values
1178
-        );
1179
-
1180
-        // where values
1181
-        $where_cols_n_values = [['CNT_ISO' => $CNT_ISO]];
1182
-        // run the update
1183
-        $success = EEM_Country::instance()->update($cols_n_values, $where_cols_n_values);
1184
-
1185
-        // allow filtering of states data
1186
-        $states = apply_filters(
1187
-            'FHEE__General_Settings_Admin_Page___update_country_settings__states',
1188
-            $this->request->getRequestParam('states', [], DataType::STRING, true)
1189
-        );
1190
-
1191
-        if (! empty($states) && $success !== false) {
1192
-            // loop thru state data ( looks like : states[75][STA_name] )
1193
-            foreach ($states as $STA_ID => $state) {
1194
-                $cols_n_values = [
1195
-                    'CNT_ISO'    => $CNT_ISO,
1196
-                    'STA_abbrev' => sanitize_text_field($state['STA_abbrev']),
1197
-                    'STA_name'   => sanitize_text_field($state['STA_name']),
1198
-                    'STA_active' => filter_var($state['STA_active'], FILTER_VALIDATE_BOOLEAN),
1199
-                ];
1200
-                // where values
1201
-                $where_cols_n_values = [['STA_ID' => $STA_ID]];
1202
-                // run the update
1203
-                $success = EEM_State::instance()->update($cols_n_values, $where_cols_n_values);
1204
-                if ($success !== false) {
1205
-                    do_action(
1206
-                        'AHEE__General_Settings_Admin_Page__update_country_settings__state_saved',
1207
-                        $CNT_ISO,
1208
-                        $STA_ID,
1209
-                        $cols_n_values
1210
-                    );
1211
-                }
1212
-            }
1213
-        }
1214
-        // check if country being edited matches org option country, and if so, then  update EE_Config with new settings
1215
-        if (
1216
-            isset(EE_Registry::instance()->CFG->organization->CNT_ISO)
1217
-            && $CNT_ISO == EE_Registry::instance()->CFG->organization->CNT_ISO
1218
-        ) {
1219
-            EE_Registry::instance()->CFG->currency = new EE_Currency_Config($CNT_ISO);
1220
-            EE_Registry::instance()->CFG->update_espresso_config();
1221
-        }
1222
-
1223
-        if ($success !== false) {
1224
-            EE_Error::add_success(
1225
-                esc_html__('Country Settings updated successfully.', 'event_espresso')
1226
-            );
1227
-        }
1228
-        $this->_redirect_after_action(
1229
-            $success,
1230
-            '',
1231
-            '',
1232
-            ['action' => 'country_settings', 'country' => $CNT_ISO],
1233
-            true
1234
-        );
1235
-    }
1236
-
1237
-
1238
-    /**
1239
-     * form_form_field_label_wrap
1240
-     *
1241
-     * @param string $label
1242
-     * @return string
1243
-     */
1244
-    public function country_form_field_label_wrap(string $label): string
1245
-    {
1246
-        return '
23
+	/**
24
+	 * @var EE_Core_Config
25
+	 */
26
+	public $core_config;
27
+
28
+
29
+	/**
30
+	 * Initialize basic properties.
31
+	 */
32
+	protected function _init_page_props()
33
+	{
34
+		$this->page_slug        = GEN_SET_PG_SLUG;
35
+		$this->page_label       = GEN_SET_LABEL;
36
+		$this->_admin_base_url  = GEN_SET_ADMIN_URL;
37
+		$this->_admin_base_path = GEN_SET_ADMIN;
38
+
39
+		$this->core_config = EE_Registry::instance()->CFG->core;
40
+	}
41
+
42
+
43
+	/**
44
+	 * Set ajax hooks
45
+	 */
46
+	protected function _ajax_hooks()
47
+	{
48
+		add_action('wp_ajax_espresso_display_country_settings', [$this, 'display_country_settings']);
49
+		add_action('wp_ajax_espresso_display_country_states', [$this, 'display_country_states']);
50
+		add_action('wp_ajax_espresso_delete_state', [$this, 'delete_state'], 10, 3);
51
+		add_action('wp_ajax_espresso_add_new_state', [$this, 'add_new_state']);
52
+	}
53
+
54
+
55
+	/**
56
+	 * More page properties initialization.
57
+	 */
58
+	protected function _define_page_props()
59
+	{
60
+		$this->_admin_page_title = GEN_SET_LABEL;
61
+		$this->_labels           = ['publishbox' => esc_html__('Update Settings', 'event_espresso')];
62
+	}
63
+
64
+
65
+	/**
66
+	 * Set page routes property.
67
+	 */
68
+	protected function _set_page_routes()
69
+	{
70
+		$this->_page_routes = [
71
+			'critical_pages'                => [
72
+				'func'       => '_espresso_page_settings',
73
+				'capability' => 'manage_options',
74
+			],
75
+			'update_espresso_page_settings' => [
76
+				'func'       => '_update_espresso_page_settings',
77
+				'capability' => 'manage_options',
78
+				'noheader'   => true,
79
+			],
80
+			'default'                       => [
81
+				'func'       => '_your_organization_settings',
82
+				'capability' => 'manage_options',
83
+			],
84
+
85
+			'update_your_organization_settings' => [
86
+				'func'       => '_update_your_organization_settings',
87
+				'capability' => 'manage_options',
88
+				'noheader'   => true,
89
+			],
90
+
91
+			'admin_option_settings' => [
92
+				'func'       => '_admin_option_settings',
93
+				'capability' => 'manage_options',
94
+			],
95
+
96
+			'update_admin_option_settings' => [
97
+				'func'       => '_update_admin_option_settings',
98
+				'capability' => 'manage_options',
99
+				'noheader'   => true,
100
+			],
101
+
102
+			'country_settings' => [
103
+				'func'       => '_country_settings',
104
+				'capability' => 'manage_options',
105
+			],
106
+
107
+			'update_country_settings' => [
108
+				'func'       => '_update_country_settings',
109
+				'capability' => 'manage_options',
110
+				'noheader'   => true,
111
+			],
112
+
113
+			'display_country_settings' => [
114
+				'func'       => 'display_country_settings',
115
+				'capability' => 'manage_options',
116
+				'noheader'   => true,
117
+			],
118
+
119
+			'add_new_state' => [
120
+				'func'       => 'add_new_state',
121
+				'capability' => 'manage_options',
122
+				'noheader'   => true,
123
+			],
124
+
125
+			'delete_state'            => [
126
+				'func'       => 'delete_state',
127
+				'capability' => 'manage_options',
128
+				'noheader'   => true,
129
+			],
130
+			'privacy_settings'        => [
131
+				'func'       => 'privacySettings',
132
+				'capability' => 'manage_options',
133
+			],
134
+			'update_privacy_settings' => [
135
+				'func'               => 'updatePrivacySettings',
136
+				'capability'         => 'manage_options',
137
+				'noheader'           => true,
138
+				'headers_sent_route' => 'privacy_settings',
139
+			],
140
+		];
141
+	}
142
+
143
+
144
+	/**
145
+	 * Set page configuration property
146
+	 */
147
+	protected function _set_page_config()
148
+	{
149
+		$this->_page_config = [
150
+			'critical_pages'        => [
151
+				'nav'           => [
152
+					'label' => esc_html__('Critical Pages', 'event_espresso'),
153
+					'order' => 50,
154
+				],
155
+				'metaboxes'     => array_merge($this->_default_espresso_metaboxes, ['_publish_post_box']),
156
+				'help_tabs'     => [
157
+					'general_settings_critical_pages_help_tab' => [
158
+						'title'    => esc_html__('Critical Pages', 'event_espresso'),
159
+						'filename' => 'general_settings_critical_pages',
160
+					],
161
+				],
162
+				'require_nonce' => false,
163
+			],
164
+			'default'               => [
165
+				'nav'           => [
166
+					'label' => esc_html__('Your Organization', 'event_espresso'),
167
+					'order' => 20,
168
+				],
169
+				'help_tabs'     => [
170
+					'general_settings_your_organization_help_tab' => [
171
+						'title'    => esc_html__('Your Organization', 'event_espresso'),
172
+						'filename' => 'general_settings_your_organization',
173
+					],
174
+				],
175
+				'metaboxes'     => array_merge($this->_default_espresso_metaboxes, ['_publish_post_box']),
176
+				'require_nonce' => false,
177
+			],
178
+			'admin_option_settings' => [
179
+				'nav'           => [
180
+					'label' => esc_html__('Admin Options', 'event_espresso'),
181
+					'order' => 60,
182
+				],
183
+				'metaboxes'     => array_merge($this->_default_espresso_metaboxes, ['_publish_post_box']),
184
+				'help_tabs'     => [
185
+					'general_settings_admin_options_help_tab' => [
186
+						'title'    => esc_html__('Admin Options', 'event_espresso'),
187
+						'filename' => 'general_settings_admin_options',
188
+					],
189
+				],
190
+				'require_nonce' => false,
191
+			],
192
+			'country_settings'      => [
193
+				'nav'           => [
194
+					'label' => esc_html__('Countries', 'event_espresso'),
195
+					'order' => 70,
196
+				],
197
+				'help_tabs'     => [
198
+					'general_settings_countries_help_tab' => [
199
+						'title'    => esc_html__('Countries', 'event_espresso'),
200
+						'filename' => 'general_settings_countries',
201
+					],
202
+				],
203
+				'require_nonce' => false,
204
+			],
205
+			'privacy_settings'      => [
206
+				'nav'           => [
207
+					'label' => esc_html__('Privacy', 'event_espresso'),
208
+					'order' => 80,
209
+				],
210
+				'metaboxes'     => array_merge($this->_default_espresso_metaboxes, ['_publish_post_box']),
211
+				'require_nonce' => false,
212
+			],
213
+		];
214
+	}
215
+
216
+
217
+	protected function _add_screen_options()
218
+	{
219
+	}
220
+
221
+
222
+	protected function _add_feature_pointers()
223
+	{
224
+	}
225
+
226
+
227
+	/**
228
+	 * Enqueue global scripts and styles for all routes in the General Settings Admin Pages.
229
+	 */
230
+	public function load_scripts_styles()
231
+	{
232
+		// styles
233
+		wp_enqueue_style('espresso-ui-theme');
234
+		// scripts
235
+		wp_enqueue_script('ee_admin_js');
236
+	}
237
+
238
+
239
+	/**
240
+	 * Execute logic running on `admin_init`
241
+	 */
242
+	public function admin_init()
243
+	{
244
+		EE_Registry::$i18n_js_strings['invalid_server_response'] = wp_strip_all_tags(
245
+			esc_html__(
246
+				'An error occurred! Your request may have been processed, but a valid response from the server was not received. Please refresh the page and try again.',
247
+				'event_espresso'
248
+			)
249
+		);
250
+		EE_Registry::$i18n_js_strings['error_occurred']          = wp_strip_all_tags(
251
+			esc_html__(
252
+				'An error occurred! Please refresh the page and try again.',
253
+				'event_espresso'
254
+			)
255
+		);
256
+		EE_Registry::$i18n_js_strings['confirm_delete_state']    = wp_strip_all_tags(
257
+			esc_html__(
258
+				'Are you sure you want to delete this State / Province?',
259
+				'event_espresso'
260
+			)
261
+		);
262
+		EE_Registry::$i18n_js_strings['ajax_url']                = admin_url(
263
+			'admin-ajax.php?page=espresso_general_settings',
264
+			is_ssl() ? 'https://' : 'http://'
265
+		);
266
+	}
267
+
268
+
269
+	public function admin_notices()
270
+	{
271
+	}
272
+
273
+
274
+	public function admin_footer_scripts()
275
+	{
276
+	}
277
+
278
+
279
+	/**
280
+	 * Enqueue scripts and styles for the default route.
281
+	 */
282
+	public function load_scripts_styles_default()
283
+	{
284
+		// styles
285
+		wp_enqueue_style('thickbox');
286
+		// scripts
287
+		wp_enqueue_script('media-upload');
288
+		wp_enqueue_script('thickbox');
289
+		wp_register_script(
290
+			'organization_settings',
291
+			GEN_SET_ASSETS_URL . 'your_organization_settings.js',
292
+			['jquery', 'media-upload', 'thickbox'],
293
+			EVENT_ESPRESSO_VERSION,
294
+			true
295
+		);
296
+		wp_register_style('organization-css', GEN_SET_ASSETS_URL . 'organization.css', [], EVENT_ESPRESSO_VERSION);
297
+		wp_enqueue_script('organization_settings');
298
+		wp_enqueue_style('organization-css');
299
+		$confirm_image_delete = [
300
+			'text' => wp_strip_all_tags(
301
+				esc_html__(
302
+					'Do you really want to delete this image? Please remember to save your settings to complete the removal.',
303
+					'event_espresso'
304
+				)
305
+			),
306
+		];
307
+		wp_localize_script('organization_settings', 'confirm_image_delete', $confirm_image_delete);
308
+	}
309
+
310
+
311
+	/**
312
+	 * Enqueue scripts and styles for the country settings route.
313
+	 */
314
+	public function load_scripts_styles_country_settings()
315
+	{
316
+		// scripts
317
+		wp_register_script(
318
+			'gen_settings_countries',
319
+			GEN_SET_ASSETS_URL . 'gen_settings_countries.js',
320
+			['ee_admin_js'],
321
+			EVENT_ESPRESSO_VERSION,
322
+			true
323
+		);
324
+		wp_register_style('organization-css', GEN_SET_ASSETS_URL . 'organization.css', [], EVENT_ESPRESSO_VERSION);
325
+		wp_enqueue_script('gen_settings_countries');
326
+		wp_enqueue_style('organization-css');
327
+	}
328
+
329
+
330
+	/*************        Espresso Pages        *************/
331
+	/**
332
+	 * _espresso_page_settings
333
+	 *
334
+	 * @throws EE_Error
335
+	 * @throws DomainException
336
+	 * @throws DomainException
337
+	 * @throws InvalidDataTypeException
338
+	 * @throws InvalidArgumentException
339
+	 */
340
+	protected function _espresso_page_settings()
341
+	{
342
+		// Check to make sure all of the main pages are set up properly,
343
+		// if not create the default pages and display an admin notice
344
+		EEH_Activation::verify_default_pages_exist();
345
+		$this->_transient_garbage_collection();
346
+
347
+		$this->_template_args['values'] = $this->_yes_no_values;
348
+
349
+		$this->_template_args['reg_page_id']  = $this->core_config->reg_page_id ?? null;
350
+		$this->_template_args['reg_page_obj'] = isset($this->core_config->reg_page_id)
351
+			? get_post($this->core_config->reg_page_id)
352
+			: false;
353
+
354
+		$this->_template_args['txn_page_id']  = $this->core_config->txn_page_id ?? null;
355
+		$this->_template_args['txn_page_obj'] = isset($this->core_config->txn_page_id)
356
+			? get_post($this->core_config->txn_page_id)
357
+			: false;
358
+
359
+		$this->_template_args['thank_you_page_id']  = $this->core_config->thank_you_page_id ?? null;
360
+		$this->_template_args['thank_you_page_obj'] = isset($this->core_config->thank_you_page_id)
361
+			? get_post($this->core_config->thank_you_page_id)
362
+			: false;
363
+
364
+		$this->_template_args['cancel_page_id']  = $this->core_config->cancel_page_id ?? null;
365
+		$this->_template_args['cancel_page_obj'] = isset($this->core_config->cancel_page_id)
366
+			? get_post($this->core_config->cancel_page_id)
367
+			: false;
368
+
369
+		$this->_set_add_edit_form_tags('update_espresso_page_settings');
370
+		$this->_set_publish_post_box_vars(null, false, false, null, false);
371
+		$this->_template_args['admin_page_content'] = EEH_Template::display_template(
372
+			GEN_SET_TEMPLATE_PATH . 'espresso_page_settings.template.php',
373
+			$this->_template_args,
374
+			true
375
+		);
376
+		$this->display_admin_page_with_sidebar();
377
+	}
378
+
379
+
380
+	/**
381
+	 * Handler for updating espresso page settings.
382
+	 *
383
+	 * @throws EE_Error
384
+	 */
385
+	protected function _update_espresso_page_settings()
386
+	{
387
+		// capture incoming request data && set page IDs
388
+		$this->core_config->reg_page_id       = $this->request->getRequestParam(
389
+			'reg_page_id',
390
+			$this->core_config->reg_page_id,
391
+			DataType::INT
392
+		);
393
+		$this->core_config->txn_page_id       = $this->request->getRequestParam(
394
+			'txn_page_id',
395
+			$this->core_config->txn_page_id,
396
+			DataType::INT
397
+		);
398
+		$this->core_config->thank_you_page_id = $this->request->getRequestParam(
399
+			'thank_you_page_id',
400
+			$this->core_config->thank_you_page_id,
401
+			DataType::INT
402
+		);
403
+		$this->core_config->cancel_page_id    = $this->request->getRequestParam(
404
+			'cancel_page_id',
405
+			$this->core_config->cancel_page_id,
406
+			DataType::INT
407
+		);
408
+
409
+		$this->core_config = apply_filters(
410
+			'FHEE__General_Settings_Admin_Page___update_espresso_page_settings__CFG_core',
411
+			$this->core_config,
412
+			$this->request->requestParams()
413
+		);
414
+
415
+		$what = esc_html__('Critical Pages & Shortcodes', 'event_espresso');
416
+		$this->_redirect_after_action(
417
+			$this->_update_espresso_configuration(
418
+				$what,
419
+				$this->core_config,
420
+				__FILE__,
421
+				__FUNCTION__,
422
+				__LINE__
423
+			),
424
+			$what,
425
+			'',
426
+			[
427
+				'action' => 'critical_pages',
428
+			],
429
+			true
430
+		);
431
+	}
432
+
433
+
434
+	/*************        Your Organization        *************/
435
+
436
+
437
+	/**
438
+	 * @throws DomainException
439
+	 * @throws EE_Error
440
+	 * @throws InvalidArgumentException
441
+	 * @throws InvalidDataTypeException
442
+	 * @throws InvalidInterfaceException
443
+	 */
444
+	protected function _your_organization_settings()
445
+	{
446
+		$this->_template_args['admin_page_content'] = '';
447
+		try {
448
+			/** @var OrganizationSettings $organization_settings_form */
449
+			$organization_settings_form = $this->loader->getShared(OrganizationSettings::class);
450
+
451
+			$this->_template_args['admin_page_content'] = EEH_HTML::div(
452
+				$organization_settings_form->display(),
453
+				'',
454
+				'padding'
455
+			);
456
+		} catch (Exception $e) {
457
+			EE_Error::add_error($e->getMessage(), __FILE__, __FUNCTION__, __LINE__);
458
+		}
459
+		$this->_set_add_edit_form_tags('update_your_organization_settings');
460
+		$this->_set_publish_post_box_vars(null, false, false, null, false);
461
+		$this->display_admin_page_with_sidebar();
462
+	}
463
+
464
+
465
+	/**
466
+	 * Handler for updating organization settings.
467
+	 *
468
+	 * @throws EE_Error
469
+	 */
470
+	protected function _update_your_organization_settings()
471
+	{
472
+		try {
473
+			/** @var OrganizationSettings $organization_settings_form */
474
+			$organization_settings_form = $this->loader->getShared(OrganizationSettings::class);
475
+
476
+			$success = $organization_settings_form->process($this->request->requestParams());
477
+
478
+			EE_Registry::instance()->CFG = apply_filters(
479
+				'FHEE__General_Settings_Admin_Page___update_your_organization_settings__CFG',
480
+				EE_Registry::instance()->CFG
481
+			);
482
+		} catch (Exception $e) {
483
+			EE_Error::add_error($e->getMessage(), __FILE__, __FUNCTION__, __LINE__);
484
+			$success = false;
485
+		}
486
+
487
+		if ($success) {
488
+			$success = $this->_update_espresso_configuration(
489
+				esc_html__('Your Organization Settings', 'event_espresso'),
490
+				EE_Registry::instance()->CFG,
491
+				__FILE__,
492
+				__FUNCTION__,
493
+				__LINE__
494
+			);
495
+		}
496
+
497
+		$this->_redirect_after_action($success, '', '', ['action' => 'default'], true);
498
+	}
499
+
500
+
501
+
502
+	/*************        Admin Options        *************/
503
+
504
+
505
+	/**
506
+	 * _admin_option_settings
507
+	 *
508
+	 * @throws EE_Error
509
+	 * @throws LogicException
510
+	 */
511
+	protected function _admin_option_settings()
512
+	{
513
+		$this->_template_args['admin_page_content'] = '';
514
+		try {
515
+			$admin_options_settings_form = new AdminOptionsSettings(EE_Registry::instance());
516
+			// still need this for the old school form in Extend_General_Settings_Admin_Page
517
+			$this->_template_args['values'] = $this->_yes_no_values;
518
+			// also need to account for the do_action that was in the old template
519
+			$admin_options_settings_form->setTemplateArgs($this->_template_args);
520
+			$this->_template_args['admin_page_content'] = $admin_options_settings_form->display();
521
+		} catch (Exception $e) {
522
+			EE_Error::add_error($e->getMessage(), __FILE__, __FUNCTION__, __LINE__);
523
+		}
524
+		$this->_set_add_edit_form_tags('update_admin_option_settings');
525
+		$this->_set_publish_post_box_vars(null, false, false, null, false);
526
+		$this->display_admin_page_with_sidebar();
527
+	}
528
+
529
+
530
+	/**
531
+	 * _update_admin_option_settings
532
+	 *
533
+	 * @throws EE_Error
534
+	 * @throws InvalidDataTypeException
535
+	 * @throws InvalidFormSubmissionException
536
+	 * @throws InvalidArgumentException
537
+	 * @throws LogicException
538
+	 */
539
+	protected function _update_admin_option_settings()
540
+	{
541
+		try {
542
+			$admin_options_settings_form = new AdminOptionsSettings(EE_Registry::instance());
543
+			$admin_options_settings_form->process(
544
+				$this->request->getRequestParam(
545
+					$admin_options_settings_form->slug(),
546
+					[],
547
+					DataType::OBJECT // need to change this to ARRAY after min PHP version gets bumped to 7+
548
+				)
549
+			);
550
+			EE_Registry::instance()->CFG->admin = apply_filters(
551
+				'FHEE__General_Settings_Admin_Page___update_admin_option_settings__CFG_admin',
552
+				EE_Registry::instance()->CFG->admin
553
+			);
554
+		} catch (Exception $e) {
555
+			EE_Error::add_error($e->getMessage(), __FILE__, __FUNCTION__, __LINE__);
556
+		}
557
+		$this->_redirect_after_action(
558
+			apply_filters(
559
+				'FHEE__General_Settings_Admin_Page___update_admin_option_settings__success',
560
+				$this->_update_espresso_configuration(
561
+					esc_html__('Admin Options', 'event_espresso'),
562
+					EE_Registry::instance()->CFG->admin,
563
+					__FILE__,
564
+					__FUNCTION__,
565
+					__LINE__
566
+				)
567
+			),
568
+			esc_html__('Admin Options', 'event_espresso'),
569
+			'updated',
570
+			['action' => 'admin_option_settings']
571
+		);
572
+	}
573
+
574
+
575
+	/*************        Countries        *************/
576
+
577
+
578
+	/**
579
+	 * @param string|null $default
580
+	 * @return string
581
+	 */
582
+	protected function getCountryISO(?string $default = null): string
583
+	{
584
+		$default = $default ?? $this->getCountryIsoForSite();
585
+		$CNT_ISO = $this->request->getRequestParam('country', $default);
586
+		$CNT_ISO = $this->request->getRequestParam('CNT_ISO', $CNT_ISO);
587
+		return strtoupper($CNT_ISO);
588
+	}
589
+
590
+
591
+	/**
592
+	 * @return string
593
+	 */
594
+	protected function getCountryIsoForSite(): string
595
+	{
596
+		return ! empty(EE_Registry::instance()->CFG->organization->CNT_ISO)
597
+			? EE_Registry::instance()->CFG->organization->CNT_ISO
598
+			: 'US';
599
+	}
600
+
601
+
602
+	/**
603
+	 * @param string          $CNT_ISO
604
+	 * @param EE_Country|null $country
605
+	 * @return EE_Base_Class|EE_Country
606
+	 * @throws EE_Error
607
+	 * @throws InvalidArgumentException
608
+	 * @throws InvalidDataTypeException
609
+	 * @throws InvalidInterfaceException
610
+	 * @throws ReflectionException
611
+	 */
612
+	protected function verifyOrGetCountryFromIso(string $CNT_ISO, ?EE_Country $country = null)
613
+	{
614
+		/** @var EE_Country $country */
615
+		return $country instanceof EE_Country && $country->ID() === $CNT_ISO
616
+			? $country
617
+			: EEM_Country::instance()->get_one_by_ID($CNT_ISO);
618
+	}
619
+
620
+
621
+	/**
622
+	 * Output Country Settings view.
623
+	 *
624
+	 * @throws DomainException
625
+	 * @throws EE_Error
626
+	 * @throws InvalidArgumentException
627
+	 * @throws InvalidDataTypeException
628
+	 * @throws InvalidInterfaceException
629
+	 * @throws ReflectionException
630
+	 */
631
+	protected function _country_settings()
632
+	{
633
+		$CNT_ISO = $this->getCountryISO();
634
+
635
+		$this->_template_args['values']    = $this->_yes_no_values;
636
+		$this->_template_args['countries'] = new EE_Question_Form_Input(
637
+			EE_Question::new_instance(
638
+				[
639
+					'QST_ID'           => 0,
640
+					'QST_display_text' => esc_html__('Select Country', 'event_espresso'),
641
+					'QST_system'       => 'admin-country',
642
+				]
643
+			),
644
+			EE_Answer::new_instance(
645
+				[
646
+					'ANS_ID'    => 0,
647
+					'ANS_value' => $CNT_ISO,
648
+				]
649
+			),
650
+			[
651
+				'input_id'       => 'country',
652
+				'input_name'     => 'country',
653
+				'input_prefix'   => '',
654
+				'append_qstn_id' => false,
655
+			]
656
+		);
657
+
658
+		$country = $this->verifyOrGetCountryFromIso($CNT_ISO);
659
+		add_filter('FHEE__EEH_Form_Fields__label_html', [$this, 'country_form_field_label_wrap'], 10);
660
+		add_filter('FHEE__EEH_Form_Fields__input_html', [$this, 'country_form_field_input__wrap'], 10);
661
+		$this->_template_args['country_details_settings'] = $this->display_country_settings(
662
+			$country->ID(),
663
+			$country
664
+		);
665
+		$this->_template_args['country_states_settings']  = $this->display_country_states(
666
+			$country->ID(),
667
+			$country
668
+		);
669
+		$this->_template_args['CNT_name_for_site']        = $country->name();
670
+
671
+		$this->_set_add_edit_form_tags('update_country_settings');
672
+		$this->_set_publish_post_box_vars(null, false, false, null, false);
673
+		$this->_template_args['admin_page_content'] = EEH_Template::display_template(
674
+			GEN_SET_TEMPLATE_PATH . 'countries_settings.template.php',
675
+			$this->_template_args,
676
+			true
677
+		);
678
+		$this->display_admin_page_with_no_sidebar();
679
+	}
680
+
681
+
682
+	/**
683
+	 * @param string          $CNT_ISO
684
+	 * @param EE_Country|null $country
685
+	 * @return string
686
+	 * @throws DomainException
687
+	 * @throws EE_Error
688
+	 * @throws InvalidArgumentException
689
+	 * @throws InvalidDataTypeException
690
+	 * @throws InvalidInterfaceException
691
+	 * @throws ReflectionException
692
+	 */
693
+	public function display_country_settings(string $CNT_ISO = '', ?EE_Country $country = null): string
694
+	{
695
+		$CNT_ISO          = $this->getCountryISO($CNT_ISO);
696
+		$CNT_ISO_for_site = $this->getCountryIsoForSite();
697
+
698
+		if (! $CNT_ISO) {
699
+			return '';
700
+		}
701
+
702
+		// for ajax
703
+		remove_all_filters('FHEE__EEH_Form_Fields__label_html');
704
+		remove_all_filters('FHEE__EEH_Form_Fields__input_html');
705
+		add_filter('FHEE__EEH_Form_Fields__label_html', [$this, 'country_form_field_label_wrap'], 10, 2);
706
+		add_filter('FHEE__EEH_Form_Fields__input_html', [$this, 'country_form_field_input__wrap'], 10, 2);
707
+		$country                                  = $this->verifyOrGetCountryFromIso($CNT_ISO, $country);
708
+		$CNT_cur_disabled                         = $CNT_ISO !== $CNT_ISO_for_site;
709
+		$this->_template_args['CNT_cur_disabled'] = $CNT_cur_disabled;
710
+
711
+		$country_input_types            = [
712
+			'CNT_active'      => [
713
+				'type'             => 'RADIO_BTN',
714
+				'input_name'       => 'cntry[' . $CNT_ISO . ']',
715
+				'class'            => '',
716
+				'options'          => $this->_yes_no_values,
717
+				'use_desc_4_label' => true,
718
+			],
719
+			'CNT_ISO'         => [
720
+				'type'       => 'TEXT',
721
+				'input_name' => 'cntry[' . $CNT_ISO . ']',
722
+				'class'      => 'small-text',
723
+			],
724
+			'CNT_ISO3'        => [
725
+				'type'       => 'TEXT',
726
+				'input_name' => 'cntry[' . $CNT_ISO . ']',
727
+				'class'      => 'small-text',
728
+			],
729
+			// 'RGN_ID'          => [
730
+			//     'type'       => 'TEXT',
731
+			//     'input_name' => 'cntry[' . $CNT_ISO . ']',
732
+			//     'class'      => 'ee-input-size--small',
733
+			// ],
734
+			'CNT_name'        => [
735
+				'type'       => 'TEXT',
736
+				'input_name' => 'cntry[' . $CNT_ISO . ']',
737
+				'class'      => 'regular-text',
738
+			],
739
+			'CNT_cur_code'    => [
740
+				'type'       => 'TEXT',
741
+				'input_name' => 'cntry[' . $CNT_ISO . ']',
742
+				'class'      => 'small-text',
743
+				'disabled'   => $CNT_cur_disabled,
744
+			],
745
+			'CNT_cur_single'  => [
746
+				'type'       => 'TEXT',
747
+				'input_name' => 'cntry[' . $CNT_ISO . ']',
748
+				'class'      => 'medium-text',
749
+				'disabled'   => $CNT_cur_disabled,
750
+			],
751
+			'CNT_cur_plural'  => [
752
+				'type'       => 'TEXT',
753
+				'input_name' => 'cntry[' . $CNT_ISO . ']',
754
+				'class'      => 'medium-text',
755
+				'disabled'   => $CNT_cur_disabled,
756
+			],
757
+			'CNT_cur_sign'    => [
758
+				'type'         => 'TEXT',
759
+				'input_name'   => 'cntry[' . $CNT_ISO . ']',
760
+				'class'        => 'small-text',
761
+				'htmlentities' => false,
762
+				'disabled'     => $CNT_cur_disabled,
763
+			],
764
+			'CNT_cur_sign_b4' => [
765
+				'type'             => 'RADIO_BTN',
766
+				'input_name'       => 'cntry[' . $CNT_ISO . ']',
767
+				'class'            => '',
768
+				'options'          => $this->_yes_no_values,
769
+				'use_desc_4_label' => true,
770
+				'disabled'         => $CNT_cur_disabled,
771
+			],
772
+			'CNT_cur_dec_plc' => [
773
+				'type'       => 'RADIO_BTN',
774
+				'input_name' => 'cntry[' . $CNT_ISO . ']',
775
+				'class'      => '',
776
+				'options'    => [
777
+					['id' => 0, 'text' => ''],
778
+					['id' => 1, 'text' => ''],
779
+					['id' => 2, 'text' => ''],
780
+					['id' => 3, 'text' => ''],
781
+				],
782
+				'disabled'   => $CNT_cur_disabled,
783
+			],
784
+			'CNT_cur_dec_mrk' => [
785
+				'type'             => 'RADIO_BTN',
786
+				'input_name'       => 'cntry[' . $CNT_ISO . ']',
787
+				'class'            => '',
788
+				'options'          => [
789
+					[
790
+						'id'   => ',',
791
+						'text' => esc_html__(', (comma)', 'event_espresso'),
792
+					],
793
+					['id' => '.', 'text' => esc_html__('. (decimal)', 'event_espresso')],
794
+				],
795
+				'use_desc_4_label' => true,
796
+				'disabled'         => $CNT_cur_disabled,
797
+			],
798
+			'CNT_cur_thsnds'  => [
799
+				'type'             => 'RADIO_BTN',
800
+				'input_name'       => 'cntry[' . $CNT_ISO . ']',
801
+				'class'            => '',
802
+				'options'          => [
803
+					[
804
+						'id'   => ',',
805
+						'text' => esc_html__(', (comma)', 'event_espresso'),
806
+					],
807
+					[
808
+						'id'   => '.',
809
+						'text' => esc_html__('. (decimal)', 'event_espresso'),
810
+					],
811
+					[
812
+						'id'   => '&nbsp;',
813
+						'text' => esc_html__('(space)', 'event_espresso'),
814
+					],
815
+					[
816
+						'id'   => '_',
817
+						'text' => esc_html__('_ (underscore)', 'event_espresso'),
818
+					],
819
+					[
820
+						'id'   => "'",
821
+						'text' => esc_html__("' (apostrophe)", 'event_espresso'),
822
+					],
823
+				],
824
+				'use_desc_4_label' => true,
825
+				'disabled'         => $CNT_cur_disabled,
826
+			],
827
+			'CNT_tel_code'    => [
828
+				'type'       => 'TEXT',
829
+				'input_name' => 'cntry[' . $CNT_ISO . ']',
830
+				'class'      => 'small-text',
831
+			],
832
+			'CNT_is_EU'       => [
833
+				'type'             => 'RADIO_BTN',
834
+				'input_name'       => 'cntry[' . $CNT_ISO . ']',
835
+				'class'            => '',
836
+				'options'          => $this->_yes_no_values,
837
+				'use_desc_4_label' => true,
838
+			],
839
+		];
840
+		$this->_template_args['inputs'] = EE_Question_Form_Input::generate_question_form_inputs_for_object(
841
+			$country,
842
+			$country_input_types
843
+		);
844
+		$country_details_settings       = EEH_Template::display_template(
845
+			GEN_SET_TEMPLATE_PATH . 'country_details_settings.template.php',
846
+			$this->_template_args,
847
+			true
848
+		);
849
+
850
+		if (defined('DOING_AJAX')) {
851
+			$notices = EE_Error::get_notices(false, false, false);
852
+			echo wp_json_encode(
853
+				[
854
+					'return_data' => $country_details_settings,
855
+					'success'     => $notices['success'],
856
+					'errors'      => $notices['errors'],
857
+				]
858
+			);
859
+			die();
860
+		}
861
+		return $country_details_settings;
862
+	}
863
+
864
+
865
+	/**
866
+	 * @param string          $CNT_ISO
867
+	 * @param EE_Country|null $country
868
+	 * @return string
869
+	 * @throws DomainException
870
+	 * @throws EE_Error
871
+	 * @throws InvalidArgumentException
872
+	 * @throws InvalidDataTypeException
873
+	 * @throws InvalidInterfaceException
874
+	 * @throws ReflectionException
875
+	 */
876
+	public function display_country_states(string $CNT_ISO = '', ?EE_Country $country = null): string
877
+	{
878
+		$CNT_ISO = $this->getCountryISO($CNT_ISO);
879
+		if (! $CNT_ISO) {
880
+			return '';
881
+		}
882
+		// for ajax
883
+		remove_all_filters('FHEE__EEH_Form_Fields__label_html');
884
+		remove_all_filters('FHEE__EEH_Form_Fields__input_html');
885
+		add_filter('FHEE__EEH_Form_Fields__label_html', [$this, 'state_form_field_label_wrap'], 10, 2);
886
+		add_filter('FHEE__EEH_Form_Fields__input_html', [$this, 'state_form_field_input__wrap'], 10);
887
+		$states = EEM_State::instance()->get_all_states_for_these_countries([$CNT_ISO => $CNT_ISO]);
888
+		if (empty($states)) {
889
+			/** @var EventEspresso\core\services\address\CountrySubRegionDao $countrySubRegionDao */
890
+			$countrySubRegionDao = $this->loader->getShared(
891
+				'EventEspresso\core\services\address\CountrySubRegionDao'
892
+			);
893
+			if ($countrySubRegionDao instanceof EventEspresso\core\services\address\CountrySubRegionDao) {
894
+				$country = $this->verifyOrGetCountryFromIso($CNT_ISO, $country);
895
+				if ($countrySubRegionDao->saveCountrySubRegions($country)) {
896
+					$states = EEM_State::instance()->get_all_states_for_these_countries([$CNT_ISO => $CNT_ISO]);
897
+				}
898
+			}
899
+		}
900
+		if (is_array($states)) {
901
+			foreach ($states as $STA_ID => $state) {
902
+				if ($state instanceof EE_State) {
903
+					$inputs = EE_Question_Form_Input::generate_question_form_inputs_for_object(
904
+						$state,
905
+						[
906
+							'STA_abbrev' => [
907
+								'type'             => 'TEXT',
908
+								'label'            => esc_html__('Code', 'event_espresso'),
909
+								'input_name'       => 'states[' . $STA_ID . ']',
910
+								'class'            => 'small-text',
911
+								'add_mobile_label' => true,
912
+							],
913
+							'STA_name'   => [
914
+								'type'             => 'TEXT',
915
+								'label'            => esc_html__('Name', 'event_espresso'),
916
+								'input_name'       => 'states[' . $STA_ID . ']',
917
+								'class'            => 'regular-text',
918
+								'add_mobile_label' => true,
919
+							],
920
+							'STA_active' => [
921
+								'type'             => 'RADIO_BTN',
922
+								'label'            => esc_html__(
923
+									'State Appears in Dropdown Select Lists',
924
+									'event_espresso'
925
+								),
926
+								'input_name'       => 'states[' . $STA_ID . ']',
927
+								'options'          => $this->_yes_no_values,
928
+								'use_desc_4_label' => true,
929
+								'add_mobile_label' => true,
930
+							],
931
+						]
932
+					);
933
+
934
+					$delete_state_url = EE_Admin_Page::add_query_args_and_nonce(
935
+						[
936
+							'action'     => 'delete_state',
937
+							'STA_ID'     => $STA_ID,
938
+							'CNT_ISO'    => $CNT_ISO,
939
+							'STA_abbrev' => $state->abbrev(),
940
+						],
941
+						GEN_SET_ADMIN_URL
942
+					);
943
+
944
+					$this->_template_args['states'][ $STA_ID ]['inputs']           = $inputs;
945
+					$this->_template_args['states'][ $STA_ID ]['delete_state_url'] = $delete_state_url;
946
+				}
947
+			}
948
+		} else {
949
+			$this->_template_args['states'] = false;
950
+		}
951
+
952
+		$this->_template_args['add_new_state_url'] = EE_Admin_Page::add_query_args_and_nonce(
953
+			['action' => 'add_new_state'],
954
+			GEN_SET_ADMIN_URL
955
+		);
956
+
957
+		$state_details_settings = EEH_Template::display_template(
958
+			GEN_SET_TEMPLATE_PATH . 'state_details_settings.template.php',
959
+			$this->_template_args,
960
+			true
961
+		);
962
+
963
+		if (defined('DOING_AJAX')) {
964
+			$notices = EE_Error::get_notices(false, false, false);
965
+			echo wp_json_encode(
966
+				[
967
+					'return_data' => $state_details_settings,
968
+					'success'     => $notices['success'],
969
+					'errors'      => $notices['errors'],
970
+				]
971
+			);
972
+			die();
973
+		}
974
+		return $state_details_settings;
975
+	}
976
+
977
+
978
+	/**
979
+	 * @return void
980
+	 * @throws EE_Error
981
+	 * @throws InvalidArgumentException
982
+	 * @throws InvalidDataTypeException
983
+	 * @throws InvalidInterfaceException
984
+	 * @throws ReflectionException
985
+	 */
986
+	public function add_new_state()
987
+	{
988
+		$success = true;
989
+		$CNT_ISO = $this->getCountryISO('');
990
+		if (! $CNT_ISO) {
991
+			EE_Error::add_error(
992
+				esc_html__('No Country ISO code or an invalid Country ISO code was received.', 'event_espresso'),
993
+				__FILE__,
994
+				__FUNCTION__,
995
+				__LINE__
996
+			);
997
+			$success = false;
998
+		}
999
+		$STA_abbrev = $this->request->getRequestParam('STA_abbrev');
1000
+		if (! $STA_abbrev) {
1001
+			EE_Error::add_error(
1002
+				esc_html__('No State ISO code or an invalid State ISO code was received.', 'event_espresso'),
1003
+				__FILE__,
1004
+				__FUNCTION__,
1005
+				__LINE__
1006
+			);
1007
+			$success = false;
1008
+		}
1009
+		$STA_name = $this->request->getRequestParam('STA_name');
1010
+		if (! $STA_name) {
1011
+			EE_Error::add_error(
1012
+				esc_html__('No State name or an invalid State name was received.', 'event_espresso'),
1013
+				__FILE__,
1014
+				__FUNCTION__,
1015
+				__LINE__
1016
+			);
1017
+			$success = false;
1018
+		}
1019
+
1020
+		if ($success) {
1021
+			$cols_n_values = [
1022
+				'CNT_ISO'    => $CNT_ISO,
1023
+				'STA_abbrev' => $STA_abbrev,
1024
+				'STA_name'   => $STA_name,
1025
+				'STA_active' => true,
1026
+			];
1027
+			$success       = EEM_State::instance()->insert($cols_n_values);
1028
+			EE_Error::add_success(esc_html__('The State was added successfully.', 'event_espresso'));
1029
+		}
1030
+
1031
+		if (defined('DOING_AJAX')) {
1032
+			$notices = EE_Error::get_notices(false, false, false);
1033
+			echo wp_json_encode(array_merge($notices, ['return_data' => $CNT_ISO]));
1034
+			die();
1035
+		} else {
1036
+			$this->_redirect_after_action(
1037
+				$success,
1038
+				esc_html__('State', 'event_espresso'),
1039
+				'added',
1040
+				['action' => 'country_settings']
1041
+			);
1042
+		}
1043
+	}
1044
+
1045
+
1046
+	/**
1047
+	 * @return void
1048
+	 * @throws EE_Error
1049
+	 * @throws InvalidArgumentException
1050
+	 * @throws InvalidDataTypeException
1051
+	 * @throws InvalidInterfaceException
1052
+	 * @throws ReflectionException
1053
+	 */
1054
+	public function delete_state()
1055
+	{
1056
+		$CNT_ISO    = $this->getCountryISO();
1057
+		$STA_ID     = $this->request->getRequestParam('STA_ID');
1058
+		$STA_abbrev = $this->request->getRequestParam('STA_abbrev');
1059
+
1060
+		if (! $STA_ID) {
1061
+			EE_Error::add_error(
1062
+				esc_html__('No State ID or an invalid State ID was received.', 'event_espresso'),
1063
+				__FILE__,
1064
+				__FUNCTION__,
1065
+				__LINE__
1066
+			);
1067
+			return;
1068
+		}
1069
+
1070
+		$success = EEM_State::instance()->delete_by_ID($STA_ID);
1071
+		if ($success !== false) {
1072
+			do_action(
1073
+				'AHEE__General_Settings_Admin_Page__delete_state__state_deleted',
1074
+				$CNT_ISO,
1075
+				$STA_ID,
1076
+				['STA_abbrev' => $STA_abbrev]
1077
+			);
1078
+			EE_Error::add_success(esc_html__('The State was deleted successfully.', 'event_espresso'));
1079
+		}
1080
+		if (defined('DOING_AJAX')) {
1081
+			$notices                = EE_Error::get_notices(false);
1082
+			$notices['return_data'] = true;
1083
+			echo wp_json_encode($notices);
1084
+			die();
1085
+		} else {
1086
+			$this->_redirect_after_action(
1087
+				$success,
1088
+				esc_html__('State', 'event_espresso'),
1089
+				'deleted',
1090
+				['action' => 'country_settings']
1091
+			);
1092
+		}
1093
+	}
1094
+
1095
+
1096
+	/**
1097
+	 *        _update_country_settings
1098
+	 *
1099
+	 * @return void
1100
+	 * @throws EE_Error
1101
+	 * @throws InvalidArgumentException
1102
+	 * @throws InvalidDataTypeException
1103
+	 * @throws InvalidInterfaceException
1104
+	 * @throws ReflectionException
1105
+	 */
1106
+	protected function _update_country_settings()
1107
+	{
1108
+		$CNT_ISO = $this->getCountryISO();
1109
+		if (! $CNT_ISO) {
1110
+			EE_Error::add_error(
1111
+				esc_html__('No Country ISO code or an invalid Country ISO code was received.', 'event_espresso'),
1112
+				__FILE__,
1113
+				__FUNCTION__,
1114
+				__LINE__
1115
+			);
1116
+			return;
1117
+		}
1118
+
1119
+		$country = $this->verifyOrGetCountryFromIso($CNT_ISO);
1120
+
1121
+		$cols_n_values                    = [];
1122
+		$cols_n_values['CNT_ISO3']        = strtoupper(
1123
+			$this->request->getRequestParam('cntry', $country->ISO3())
1124
+		);
1125
+		$cols_n_values['CNT_name']        = $this->request->getRequestParam(
1126
+			"cntry[$CNT_ISO][CNT_name]",
1127
+			$country->name()
1128
+		);
1129
+		$cols_n_values['CNT_cur_code']    = strtoupper(
1130
+			$this->request->getRequestParam(
1131
+				"cntry[$CNT_ISO][CNT_cur_code]",
1132
+				$country->currency_code()
1133
+			)
1134
+		);
1135
+		$cols_n_values['CNT_cur_single']  = $this->request->getRequestParam(
1136
+			"cntry[$CNT_ISO][CNT_cur_single]",
1137
+			$country->currency_name_single()
1138
+		);
1139
+		$cols_n_values['CNT_cur_plural']  = $this->request->getRequestParam(
1140
+			"cntry[$CNT_ISO][CNT_cur_plural]",
1141
+			$country->currency_name_plural()
1142
+		);
1143
+		$cols_n_values['CNT_cur_sign']    = $this->request->getRequestParam(
1144
+			"cntry[$CNT_ISO][CNT_cur_sign]",
1145
+			$country->currency_sign()
1146
+		);
1147
+		$cols_n_values['CNT_cur_sign_b4'] = $this->request->getRequestParam(
1148
+			"cntry[$CNT_ISO][CNT_cur_sign_b4]",
1149
+			$country->currency_sign_before(),
1150
+			DataType::BOOL
1151
+		);
1152
+		$cols_n_values['CNT_cur_dec_plc'] = $this->request->getRequestParam(
1153
+			"cntry[$CNT_ISO][CNT_cur_dec_plc]",
1154
+			$country->currency_decimal_places()
1155
+		);
1156
+		$cols_n_values['CNT_cur_dec_mrk'] = $this->request->getRequestParam(
1157
+			"cntry[$CNT_ISO][CNT_cur_dec_mrk]",
1158
+			$country->currency_decimal_mark()
1159
+		);
1160
+		$cols_n_values['CNT_cur_thsnds']  = $this->request->getRequestParam(
1161
+			"cntry[$CNT_ISO][CNT_cur_thsnds]",
1162
+			$country->currency_thousands_separator()
1163
+		);
1164
+		$cols_n_values['CNT_tel_code']    = $this->request->getRequestParam(
1165
+			"cntry[$CNT_ISO][CNT_tel_code]",
1166
+			$country->telephoneCode()
1167
+		);
1168
+		$cols_n_values['CNT_active']      = $this->request->getRequestParam(
1169
+			"cntry[$CNT_ISO][CNT_active]",
1170
+			$country->isActive(),
1171
+			DataType::BOOL
1172
+		);
1173
+
1174
+		// allow filtering of country data
1175
+		$cols_n_values = apply_filters(
1176
+			'FHEE__General_Settings_Admin_Page___update_country_settings__cols_n_values',
1177
+			$cols_n_values
1178
+		);
1179
+
1180
+		// where values
1181
+		$where_cols_n_values = [['CNT_ISO' => $CNT_ISO]];
1182
+		// run the update
1183
+		$success = EEM_Country::instance()->update($cols_n_values, $where_cols_n_values);
1184
+
1185
+		// allow filtering of states data
1186
+		$states = apply_filters(
1187
+			'FHEE__General_Settings_Admin_Page___update_country_settings__states',
1188
+			$this->request->getRequestParam('states', [], DataType::STRING, true)
1189
+		);
1190
+
1191
+		if (! empty($states) && $success !== false) {
1192
+			// loop thru state data ( looks like : states[75][STA_name] )
1193
+			foreach ($states as $STA_ID => $state) {
1194
+				$cols_n_values = [
1195
+					'CNT_ISO'    => $CNT_ISO,
1196
+					'STA_abbrev' => sanitize_text_field($state['STA_abbrev']),
1197
+					'STA_name'   => sanitize_text_field($state['STA_name']),
1198
+					'STA_active' => filter_var($state['STA_active'], FILTER_VALIDATE_BOOLEAN),
1199
+				];
1200
+				// where values
1201
+				$where_cols_n_values = [['STA_ID' => $STA_ID]];
1202
+				// run the update
1203
+				$success = EEM_State::instance()->update($cols_n_values, $where_cols_n_values);
1204
+				if ($success !== false) {
1205
+					do_action(
1206
+						'AHEE__General_Settings_Admin_Page__update_country_settings__state_saved',
1207
+						$CNT_ISO,
1208
+						$STA_ID,
1209
+						$cols_n_values
1210
+					);
1211
+				}
1212
+			}
1213
+		}
1214
+		// check if country being edited matches org option country, and if so, then  update EE_Config with new settings
1215
+		if (
1216
+			isset(EE_Registry::instance()->CFG->organization->CNT_ISO)
1217
+			&& $CNT_ISO == EE_Registry::instance()->CFG->organization->CNT_ISO
1218
+		) {
1219
+			EE_Registry::instance()->CFG->currency = new EE_Currency_Config($CNT_ISO);
1220
+			EE_Registry::instance()->CFG->update_espresso_config();
1221
+		}
1222
+
1223
+		if ($success !== false) {
1224
+			EE_Error::add_success(
1225
+				esc_html__('Country Settings updated successfully.', 'event_espresso')
1226
+			);
1227
+		}
1228
+		$this->_redirect_after_action(
1229
+			$success,
1230
+			'',
1231
+			'',
1232
+			['action' => 'country_settings', 'country' => $CNT_ISO],
1233
+			true
1234
+		);
1235
+	}
1236
+
1237
+
1238
+	/**
1239
+	 * form_form_field_label_wrap
1240
+	 *
1241
+	 * @param string $label
1242
+	 * @return string
1243
+	 */
1244
+	public function country_form_field_label_wrap(string $label): string
1245
+	{
1246
+		return '
1247 1247
 			<tr>
1248 1248
 				<th>
1249 1249
 					' . $label . '
1250 1250
 				</th>';
1251
-    }
1252
-
1253
-
1254
-    /**
1255
-     * form_form_field_input__wrap
1256
-     *
1257
-     * @param string $input
1258
-     * @return string
1259
-     */
1260
-    public function country_form_field_input__wrap(string $input): string
1261
-    {
1262
-        return '
1251
+	}
1252
+
1253
+
1254
+	/**
1255
+	 * form_form_field_input__wrap
1256
+	 *
1257
+	 * @param string $input
1258
+	 * @return string
1259
+	 */
1260
+	public function country_form_field_input__wrap(string $input): string
1261
+	{
1262
+		return '
1263 1263
 				<td class="general-settings-country-input-td">
1264 1264
 					' . $input . '
1265 1265
 				</td>
1266 1266
 			</tr>';
1267
-    }
1268
-
1269
-
1270
-    /**
1271
-     * form_form_field_label_wrap
1272
-     *
1273
-     * @param string $label
1274
-     * @param string $required_text
1275
-     * @return string
1276
-     */
1277
-    public function state_form_field_label_wrap(string $label, string $required_text): string
1278
-    {
1279
-        return $required_text;
1280
-    }
1281
-
1282
-
1283
-    /**
1284
-     * form_form_field_input__wrap
1285
-     *
1286
-     * @param string $input
1287
-     * @return string
1288
-     */
1289
-    public function state_form_field_input__wrap(string $input): string
1290
-    {
1291
-        return '
1267
+	}
1268
+
1269
+
1270
+	/**
1271
+	 * form_form_field_label_wrap
1272
+	 *
1273
+	 * @param string $label
1274
+	 * @param string $required_text
1275
+	 * @return string
1276
+	 */
1277
+	public function state_form_field_label_wrap(string $label, string $required_text): string
1278
+	{
1279
+		return $required_text;
1280
+	}
1281
+
1282
+
1283
+	/**
1284
+	 * form_form_field_input__wrap
1285
+	 *
1286
+	 * @param string $input
1287
+	 * @return string
1288
+	 */
1289
+	public function state_form_field_input__wrap(string $input): string
1290
+	{
1291
+		return '
1292 1292
 				<td class="general-settings-country-state-input-td">
1293 1293
 					' . $input . '
1294 1294
 				</td>';
1295
-    }
1296
-
1297
-
1298
-    /***********/
1299
-
1300
-
1301
-    /**
1302
-     * displays edit and view links for critical EE pages
1303
-     *
1304
-     * @param int $ee_page_id
1305
-     * @return string
1306
-     */
1307
-    public static function edit_view_links(int $ee_page_id): string
1308
-    {
1309
-        $edit_url = add_query_arg(
1310
-            ['post' => $ee_page_id, 'action' => 'edit'],
1311
-            admin_url('post.php')
1312
-        );
1313
-        $links    = '<a href="' . esc_url_raw($edit_url) . '" >' . esc_html__('Edit', 'event_espresso') . '</a>';
1314
-        $links    .= ' &nbsp;|&nbsp; ';
1315
-        $links    .= '<a href="' . get_permalink($ee_page_id) . '" >' . esc_html__('View', 'event_espresso') . '</a>';
1316
-
1317
-        return $links;
1318
-    }
1319
-
1320
-
1321
-    /**
1322
-     * displays page and shortcode status for critical EE pages
1323
-     *
1324
-     * @param WP_Post $ee_page
1325
-     * @param string  $shortcode
1326
-     * @return string
1327
-     */
1328
-    public static function page_and_shortcode_status(WP_Post $ee_page, string $shortcode): string
1329
-    {
1330
-        // page status
1331
-        if (isset($ee_page->post_status) && $ee_page->post_status == 'publish') {
1332
-            $pg_colour = 'green';
1333
-            $pg_status = sprintf(esc_html__('Page%sStatus%sOK', 'event_espresso'), '&nbsp;', '&nbsp;');
1334
-        } else {
1335
-            $pg_colour = 'red';
1336
-            $pg_status = sprintf(esc_html__('Page%sVisibility%sProblem', 'event_espresso'), '&nbsp;', '&nbsp;');
1337
-        }
1338
-
1339
-        // shortcode status
1340
-        if (isset($ee_page->post_content) && strpos($ee_page->post_content, $shortcode) !== false) {
1341
-            $sc_colour = 'green';
1342
-            $sc_status = sprintf(esc_html__('Shortcode%sOK', 'event_espresso'), '&nbsp;');
1343
-        } else {
1344
-            $sc_colour = 'red';
1345
-            $sc_status = sprintf(esc_html__('Shortcode%sProblem', 'event_espresso'), '&nbsp;');
1346
-        }
1347
-
1348
-        return '<span style="color:' . $pg_colour . '; margin-right:2em;"><strong>'
1349
-               . $pg_status
1350
-               . '</strong></span><span style="color:' . $sc_colour . '"><strong>' . $sc_status . '</strong></span>';
1351
-    }
1352
-
1353
-
1354
-    /**
1355
-     * generates a dropdown of all parent pages - copied from WP core
1356
-     *
1357
-     * @param int  $default
1358
-     * @param int  $parent
1359
-     * @param int  $level
1360
-     * @param bool $echo
1361
-     * @return string;
1362
-     */
1363
-    public static function page_settings_dropdown(
1364
-        int $default = 0,
1365
-        int $parent = 0,
1366
-        int $level = 0,
1367
-        bool $echo = true
1368
-    ): string {
1369
-        global $wpdb;
1370
-        $items  = $wpdb->get_results(
1371
-            $wpdb->prepare(
1372
-                "SELECT ID, post_parent, post_title FROM $wpdb->posts WHERE post_parent = %d AND post_type = 'page' AND post_status != 'trash' ORDER BY menu_order",
1373
-                $parent
1374
-            )
1375
-        );
1376
-        $output = '';
1377
-
1378
-        if ($items) {
1379
-            $level = absint($level);
1380
-            foreach ($items as $item) {
1381
-                $ID         = absint($item->ID);
1382
-                $post_title = wp_strip_all_tags($item->post_title);
1383
-                $pad        = str_repeat('&nbsp;', $level * 3);
1384
-                $option     = "\n\t";
1385
-                $option     .= '<option class="level-' . $level . '" ';
1386
-                $option     .= 'value="' . $ID . '" ';
1387
-                $option     .= $ID === absint($default) ? ' selected' : '';
1388
-                $option     .= '>';
1389
-                $option     .= "$pad {$post_title}";
1390
-                $option     .= '</option>';
1391
-                $output     .= $option;
1392
-                ob_start();
1393
-                parent_dropdown($default, $item->ID, $level + 1);
1394
-                $output .= ob_get_clean();
1395
-            }
1396
-        }
1397
-        if ($echo) {
1398
-            echo wp_kses($output, AllowedTags::getWithFormTags());
1399
-            return '';
1400
-        }
1401
-        return $output;
1402
-    }
1403
-
1404
-
1405
-    /**
1406
-     * Loads the scripts for the privacy settings form
1407
-     */
1408
-    public function load_scripts_styles_privacy_settings()
1409
-    {
1410
-        $form_handler = $this->loader->getShared(
1411
-            'EventEspresso\core\domain\services\admin\privacy\forms\PrivacySettingsFormHandler'
1412
-        );
1413
-        $form_handler->enqueueStylesAndScripts();
1414
-    }
1415
-
1416
-
1417
-    /**
1418
-     * display the privacy settings form
1419
-     *
1420
-     * @throws EE_Error
1421
-     */
1422
-    public function privacySettings()
1423
-    {
1424
-        $this->_set_add_edit_form_tags('update_privacy_settings');
1425
-        $this->_set_publish_post_box_vars(null, false, false, null, false);
1426
-        $form_handler                               = $this->loader->getShared(
1427
-            'EventEspresso\core\domain\services\admin\privacy\forms\PrivacySettingsFormHandler'
1428
-        );
1429
-        $this->_template_args['admin_page_content'] = EEH_HTML::div(
1430
-            $form_handler->display(),
1431
-            '',
1432
-            'padding'
1433
-        );
1434
-        $this->display_admin_page_with_sidebar();
1435
-    }
1436
-
1437
-
1438
-    /**
1439
-     * Update the privacy settings from form data
1440
-     *
1441
-     * @throws EE_Error
1442
-     */
1443
-    public function updatePrivacySettings()
1444
-    {
1445
-        $form_handler = $this->loader->getShared(
1446
-            'EventEspresso\core\domain\services\admin\privacy\forms\PrivacySettingsFormHandler'
1447
-        );
1448
-        $success      = $form_handler->process($this->get_request_data());
1449
-        $this->_redirect_after_action(
1450
-            $success,
1451
-            esc_html__('Registration Form Options', 'event_espresso'),
1452
-            'updated',
1453
-            ['action' => 'privacy_settings']
1454
-        );
1455
-    }
1295
+	}
1296
+
1297
+
1298
+	/***********/
1299
+
1300
+
1301
+	/**
1302
+	 * displays edit and view links for critical EE pages
1303
+	 *
1304
+	 * @param int $ee_page_id
1305
+	 * @return string
1306
+	 */
1307
+	public static function edit_view_links(int $ee_page_id): string
1308
+	{
1309
+		$edit_url = add_query_arg(
1310
+			['post' => $ee_page_id, 'action' => 'edit'],
1311
+			admin_url('post.php')
1312
+		);
1313
+		$links    = '<a href="' . esc_url_raw($edit_url) . '" >' . esc_html__('Edit', 'event_espresso') . '</a>';
1314
+		$links    .= ' &nbsp;|&nbsp; ';
1315
+		$links    .= '<a href="' . get_permalink($ee_page_id) . '" >' . esc_html__('View', 'event_espresso') . '</a>';
1316
+
1317
+		return $links;
1318
+	}
1319
+
1320
+
1321
+	/**
1322
+	 * displays page and shortcode status for critical EE pages
1323
+	 *
1324
+	 * @param WP_Post $ee_page
1325
+	 * @param string  $shortcode
1326
+	 * @return string
1327
+	 */
1328
+	public static function page_and_shortcode_status(WP_Post $ee_page, string $shortcode): string
1329
+	{
1330
+		// page status
1331
+		if (isset($ee_page->post_status) && $ee_page->post_status == 'publish') {
1332
+			$pg_colour = 'green';
1333
+			$pg_status = sprintf(esc_html__('Page%sStatus%sOK', 'event_espresso'), '&nbsp;', '&nbsp;');
1334
+		} else {
1335
+			$pg_colour = 'red';
1336
+			$pg_status = sprintf(esc_html__('Page%sVisibility%sProblem', 'event_espresso'), '&nbsp;', '&nbsp;');
1337
+		}
1338
+
1339
+		// shortcode status
1340
+		if (isset($ee_page->post_content) && strpos($ee_page->post_content, $shortcode) !== false) {
1341
+			$sc_colour = 'green';
1342
+			$sc_status = sprintf(esc_html__('Shortcode%sOK', 'event_espresso'), '&nbsp;');
1343
+		} else {
1344
+			$sc_colour = 'red';
1345
+			$sc_status = sprintf(esc_html__('Shortcode%sProblem', 'event_espresso'), '&nbsp;');
1346
+		}
1347
+
1348
+		return '<span style="color:' . $pg_colour . '; margin-right:2em;"><strong>'
1349
+			   . $pg_status
1350
+			   . '</strong></span><span style="color:' . $sc_colour . '"><strong>' . $sc_status . '</strong></span>';
1351
+	}
1352
+
1353
+
1354
+	/**
1355
+	 * generates a dropdown of all parent pages - copied from WP core
1356
+	 *
1357
+	 * @param int  $default
1358
+	 * @param int  $parent
1359
+	 * @param int  $level
1360
+	 * @param bool $echo
1361
+	 * @return string;
1362
+	 */
1363
+	public static function page_settings_dropdown(
1364
+		int $default = 0,
1365
+		int $parent = 0,
1366
+		int $level = 0,
1367
+		bool $echo = true
1368
+	): string {
1369
+		global $wpdb;
1370
+		$items  = $wpdb->get_results(
1371
+			$wpdb->prepare(
1372
+				"SELECT ID, post_parent, post_title FROM $wpdb->posts WHERE post_parent = %d AND post_type = 'page' AND post_status != 'trash' ORDER BY menu_order",
1373
+				$parent
1374
+			)
1375
+		);
1376
+		$output = '';
1377
+
1378
+		if ($items) {
1379
+			$level = absint($level);
1380
+			foreach ($items as $item) {
1381
+				$ID         = absint($item->ID);
1382
+				$post_title = wp_strip_all_tags($item->post_title);
1383
+				$pad        = str_repeat('&nbsp;', $level * 3);
1384
+				$option     = "\n\t";
1385
+				$option     .= '<option class="level-' . $level . '" ';
1386
+				$option     .= 'value="' . $ID . '" ';
1387
+				$option     .= $ID === absint($default) ? ' selected' : '';
1388
+				$option     .= '>';
1389
+				$option     .= "$pad {$post_title}";
1390
+				$option     .= '</option>';
1391
+				$output     .= $option;
1392
+				ob_start();
1393
+				parent_dropdown($default, $item->ID, $level + 1);
1394
+				$output .= ob_get_clean();
1395
+			}
1396
+		}
1397
+		if ($echo) {
1398
+			echo wp_kses($output, AllowedTags::getWithFormTags());
1399
+			return '';
1400
+		}
1401
+		return $output;
1402
+	}
1403
+
1404
+
1405
+	/**
1406
+	 * Loads the scripts for the privacy settings form
1407
+	 */
1408
+	public function load_scripts_styles_privacy_settings()
1409
+	{
1410
+		$form_handler = $this->loader->getShared(
1411
+			'EventEspresso\core\domain\services\admin\privacy\forms\PrivacySettingsFormHandler'
1412
+		);
1413
+		$form_handler->enqueueStylesAndScripts();
1414
+	}
1415
+
1416
+
1417
+	/**
1418
+	 * display the privacy settings form
1419
+	 *
1420
+	 * @throws EE_Error
1421
+	 */
1422
+	public function privacySettings()
1423
+	{
1424
+		$this->_set_add_edit_form_tags('update_privacy_settings');
1425
+		$this->_set_publish_post_box_vars(null, false, false, null, false);
1426
+		$form_handler                               = $this->loader->getShared(
1427
+			'EventEspresso\core\domain\services\admin\privacy\forms\PrivacySettingsFormHandler'
1428
+		);
1429
+		$this->_template_args['admin_page_content'] = EEH_HTML::div(
1430
+			$form_handler->display(),
1431
+			'',
1432
+			'padding'
1433
+		);
1434
+		$this->display_admin_page_with_sidebar();
1435
+	}
1436
+
1437
+
1438
+	/**
1439
+	 * Update the privacy settings from form data
1440
+	 *
1441
+	 * @throws EE_Error
1442
+	 */
1443
+	public function updatePrivacySettings()
1444
+	{
1445
+		$form_handler = $this->loader->getShared(
1446
+			'EventEspresso\core\domain\services\admin\privacy\forms\PrivacySettingsFormHandler'
1447
+		);
1448
+		$success      = $form_handler->process($this->get_request_data());
1449
+		$this->_redirect_after_action(
1450
+			$success,
1451
+			esc_html__('Registration Form Options', 'event_espresso'),
1452
+			'updated',
1453
+			['action' => 'privacy_settings']
1454
+		);
1455
+	}
1456 1456
 }
Please login to merge, or discard this patch.