Completed
Branch master (aa4b32)
by
unknown
23:55 queued 17:35
created
espresso.php 1 patch
Indentation   +107 added lines, -107 removed lines patch added patch discarded remove patch
@@ -37,138 +37,138 @@
 block discarded – undo
37 37
  * @since       4.0
38 38
  */
39 39
 if (function_exists('espresso_version')) {
40
-    if (! function_exists('espresso_duplicate_plugin_error')) {
41
-        /**
42
-         *    espresso_duplicate_plugin_error
43
-         *    displays if more than one version of EE is activated at the same time.
44
-         */
45
-        function espresso_duplicate_plugin_error()
46
-        {
47
-            ?>
40
+	if (! function_exists('espresso_duplicate_plugin_error')) {
41
+		/**
42
+		 *    espresso_duplicate_plugin_error
43
+		 *    displays if more than one version of EE is activated at the same time.
44
+		 */
45
+		function espresso_duplicate_plugin_error()
46
+		{
47
+			?>
48 48
 <div class="error">
49 49
     <p>
50 50
         <?php
51
-                    echo esc_html__(
52
-                        '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.',
53
-                        'event_espresso'
54
-                    ); ?>
51
+					echo esc_html__(
52
+						'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.',
53
+						'event_espresso'
54
+					); ?>
55 55
     </p>
56 56
 </div>
57 57
 <?php
58
-            espresso_deactivate_plugin(plugin_basename(__FILE__));
59
-        }
60
-    }
61
-    add_action('admin_notices', 'espresso_duplicate_plugin_error', 1);
58
+			espresso_deactivate_plugin(plugin_basename(__FILE__));
59
+		}
60
+	}
61
+	add_action('admin_notices', 'espresso_duplicate_plugin_error', 1);
62 62
 } else {
63
-    define('EE_MIN_PHP_VER_REQUIRED', '7.4.0');
64
-    if (! version_compare(PHP_VERSION, EE_MIN_PHP_VER_REQUIRED, '>=')) {
65
-        /**
66
-         * espresso_minimum_php_version_error
67
-         *
68
-         * @return void
69
-         */
70
-        function espresso_minimum_php_version_error()
71
-        {
72
-            ?>
63
+	define('EE_MIN_PHP_VER_REQUIRED', '7.4.0');
64
+	if (! version_compare(PHP_VERSION, EE_MIN_PHP_VER_REQUIRED, '>=')) {
65
+		/**
66
+		 * espresso_minimum_php_version_error
67
+		 *
68
+		 * @return void
69
+		 */
70
+		function espresso_minimum_php_version_error()
71
+		{
72
+			?>
73 73
 <div class="error">
74 74
     <p>
75 75
         <?php
76
-                    printf(
77
-                        esc_html__(
78
-                            '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.',
79
-                            'event_espresso'
80
-                        ),
81
-                        EE_MIN_PHP_VER_REQUIRED,
82
-                        PHP_VERSION,
83
-                        '<br/>',
84
-                        '<a href="https://www.php.net/downloads.php">https://php.net/downloads.php</a>'
85
-                    );
86
-        ?>
76
+					printf(
77
+						esc_html__(
78
+							'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.',
79
+							'event_espresso'
80
+						),
81
+						EE_MIN_PHP_VER_REQUIRED,
82
+						PHP_VERSION,
83
+						'<br/>',
84
+						'<a href="https://www.php.net/downloads.php">https://php.net/downloads.php</a>'
85
+					);
86
+		?>
87 87
     </p>
88 88
 </div>
89 89
 <?php
90
-            espresso_deactivate_plugin(plugin_basename(__FILE__));
91
-        }
90
+			espresso_deactivate_plugin(plugin_basename(__FILE__));
91
+		}
92 92
 
93
-        add_action('admin_notices', 'espresso_minimum_php_version_error', 1);
94
-    } else {
95
-        define('EVENT_ESPRESSO_MAIN_FILE', __FILE__);
93
+		add_action('admin_notices', 'espresso_minimum_php_version_error', 1);
94
+	} else {
95
+		define('EVENT_ESPRESSO_MAIN_FILE', __FILE__);
96 96
 
97
-        require_once __DIR__ . '/vendor/autoload.php';
97
+		require_once __DIR__ . '/vendor/autoload.php';
98 98
 
99
-        /**
100
-         * espresso_version
101
-         * Returns the plugin version
102
-         *
103
-         * @return string
104
-         */
105
-        function espresso_version(): string
106
-        {
107
-            return apply_filters('FHEE__espresso__espresso_version', '5.0.32.rc.000');
108
-        }
99
+		/**
100
+		 * espresso_version
101
+		 * Returns the plugin version
102
+		 *
103
+		 * @return string
104
+		 */
105
+		function espresso_version(): string
106
+		{
107
+			return apply_filters('FHEE__espresso__espresso_version', '5.0.32.rc.000');
108
+		}
109 109
 
110
-        /**
111
-         * espresso_plugin_activation
112
-         * adds a wp-option to indicate that EE has been activated via the WP admin plugins page
113
-         */
114
-        function espresso_plugin_activation()
115
-        {
116
-            update_option('ee_espresso_activation', true);
117
-            update_option('event-espresso-core_allow_tracking', 'no');
118
-            update_option('event-espresso-core_tracking_notice', 'hide');
119
-            // Run WP GraphQL activation callback
120
-            espressoLoadWpGraphQL();
121
-            graphql_activation_callback();
122
-        }
110
+		/**
111
+		 * espresso_plugin_activation
112
+		 * adds a wp-option to indicate that EE has been activated via the WP admin plugins page
113
+		 */
114
+		function espresso_plugin_activation()
115
+		{
116
+			update_option('ee_espresso_activation', true);
117
+			update_option('event-espresso-core_allow_tracking', 'no');
118
+			update_option('event-espresso-core_tracking_notice', 'hide');
119
+			// Run WP GraphQL activation callback
120
+			espressoLoadWpGraphQL();
121
+			graphql_activation_callback();
122
+		}
123 123
 
124
-        register_activation_hook(EVENT_ESPRESSO_MAIN_FILE, 'espresso_plugin_activation');
124
+		register_activation_hook(EVENT_ESPRESSO_MAIN_FILE, 'espresso_plugin_activation');
125 125
 
126
-        /**
127
-         * espresso_plugin_deactivation
128
-         */
129
-        function espresso_plugin_deactivation()
130
-        {
131
-            // Run WP GraphQL deactivation callback
132
-            espressoLoadWpGraphQL();
133
-            graphql_deactivation_callback();
134
-            delete_option('event-espresso-core_allow_tracking');
135
-            delete_option('event-espresso-core_tracking_notice');
136
-        }
137
-        register_deactivation_hook(EVENT_ESPRESSO_MAIN_FILE, 'espresso_plugin_deactivation');
126
+		/**
127
+		 * espresso_plugin_deactivation
128
+		 */
129
+		function espresso_plugin_deactivation()
130
+		{
131
+			// Run WP GraphQL deactivation callback
132
+			espressoLoadWpGraphQL();
133
+			graphql_deactivation_callback();
134
+			delete_option('event-espresso-core_allow_tracking');
135
+			delete_option('event-espresso-core_tracking_notice');
136
+		}
137
+		register_deactivation_hook(EVENT_ESPRESSO_MAIN_FILE, 'espresso_plugin_deactivation');
138 138
 
139
-        require_once __DIR__ . '/core/bootstrap_espresso.php';
140
-        bootstrap_espresso();
141
-    }
139
+		require_once __DIR__ . '/core/bootstrap_espresso.php';
140
+		bootstrap_espresso();
141
+	}
142 142
 }
143 143
 
144 144
 if (! function_exists('espresso_deactivate_plugin')) {
145
-    /**
146
-     *    deactivate_plugin
147
-     * usage:  espresso_deactivate_plugin( plugin_basename( __FILE__ ));
148
-     *
149
-     * @access public
150
-     * @param string $plugin_basename - the results of plugin_basename( __FILE__ ) for the plugin's main file
151
-     * @return    void
152
-     */
153
-    function espresso_deactivate_plugin(string $plugin_basename = '')
154
-    {
155
-        if (! function_exists('deactivate_plugins')) {
156
-            require_once ABSPATH . 'wp-admin/includes/plugin.php';
157
-        }
158
-        unset($_GET['activate'], $_REQUEST['activate']);
159
-        deactivate_plugins($plugin_basename);
160
-    }
145
+	/**
146
+	 *    deactivate_plugin
147
+	 * usage:  espresso_deactivate_plugin( plugin_basename( __FILE__ ));
148
+	 *
149
+	 * @access public
150
+	 * @param string $plugin_basename - the results of plugin_basename( __FILE__ ) for the plugin's main file
151
+	 * @return    void
152
+	 */
153
+	function espresso_deactivate_plugin(string $plugin_basename = '')
154
+	{
155
+		if (! function_exists('deactivate_plugins')) {
156
+			require_once ABSPATH . 'wp-admin/includes/plugin.php';
157
+		}
158
+		unset($_GET['activate'], $_REQUEST['activate']);
159
+		deactivate_plugins($plugin_basename);
160
+	}
161 161
 }
162 162
 
163 163
 
164 164
 if (! function_exists('espressoLoadWpGraphQL')) {
165
-    function espressoLoadWpGraphQL()
166
-    {
167
-        if (
168
-            ! class_exists('WPGraphQL')
169
-            && is_readable(__DIR__ . '/vendor/wp-graphql/wp-graphql/wp-graphql.php')
170
-        ) {
171
-            require_once __DIR__ . '/vendor/wp-graphql/wp-graphql/wp-graphql.php';
172
-        }
173
-    }
165
+	function espressoLoadWpGraphQL()
166
+	{
167
+		if (
168
+			! class_exists('WPGraphQL')
169
+			&& is_readable(__DIR__ . '/vendor/wp-graphql/wp-graphql/wp-graphql.php')
170
+		) {
171
+			require_once __DIR__ . '/vendor/wp-graphql/wp-graphql/wp-graphql.php';
172
+		}
173
+	}
174 174
 }
Please login to merge, or discard this patch.
admin_pages/general_settings/General_Settings_Admin_Page.core.php 2 patches
Indentation   +1463 added lines, -1463 removed lines patch added patch discarded remove patch
@@ -22,1480 +22,1480 @@
 block discarded – undo
22 22
  */
23 23
 class General_Settings_Admin_Page extends EE_Admin_Page
24 24
 {
25
-    /**
26
-     * @var EE_Core_Config
27
-     */
28
-    public $core_config;
29
-
30
-
31
-    /**
32
-     * Initialize basic properties.
33
-     */
34
-    protected function _init_page_props()
35
-    {
36
-        $this->page_slug        = GEN_SET_PG_SLUG;
37
-        $this->page_label       = GEN_SET_LABEL;
38
-        $this->_admin_base_url  = GEN_SET_ADMIN_URL;
39
-        $this->_admin_base_path = GEN_SET_ADMIN;
40
-
41
-        $this->core_config = EE_Registry::instance()->CFG->core;
42
-    }
43
-
44
-
45
-    /**
46
-     * Set ajax hooks
47
-     */
48
-    protected function _ajax_hooks()
49
-    {
50
-        add_action('wp_ajax_espresso_display_country_settings', [$this, 'display_country_settings']);
51
-        add_action('wp_ajax_espresso_display_country_states', [$this, 'display_country_states']);
52
-        add_action('wp_ajax_espresso_delete_state', [$this, 'delete_state'], 10, 3);
53
-        add_action('wp_ajax_espresso_add_new_state', [$this, 'add_new_state']);
54
-    }
55
-
56
-
57
-    /**
58
-     * More page properties initialization.
59
-     */
60
-    protected function _define_page_props()
61
-    {
62
-        $this->_admin_page_title = GEN_SET_LABEL;
63
-        $this->_labels           = ['publishbox' => esc_html__('Update Settings', 'event_espresso')];
64
-    }
65
-
66
-
67
-    /**
68
-     * Set page routes property.
69
-     */
70
-    protected function _set_page_routes()
71
-    {
72
-        $this->_page_routes = [
73
-            'critical_pages'                => [
74
-                'func'       => [$this, '_espresso_page_settings'],
75
-                'capability' => 'manage_options',
76
-            ],
77
-            'update_espresso_page_settings' => [
78
-                'func'       => [$this, '_update_espresso_page_settings'],
79
-                'capability' => 'manage_options',
80
-                'noheader'   => true,
81
-            ],
82
-            'default'                       => [
83
-                'func'       => [$this, '_your_organization_settings'],
84
-                'capability' => 'manage_options',
85
-            ],
86
-
87
-            'update_your_organization_settings' => [
88
-                'func'       => [$this, '_update_your_organization_settings'],
89
-                'capability' => 'manage_options',
90
-                'noheader'   => true,
91
-            ],
92
-
93
-            'admin_option_settings' => [
94
-                'func'       => [$this, '_admin_option_settings'],
95
-                'capability' => 'manage_options',
96
-            ],
97
-
98
-            'update_admin_option_settings' => [
99
-                'func'       => [$this, '_update_admin_option_settings'],
100
-                'capability' => 'manage_options',
101
-                'noheader'   => true,
102
-            ],
103
-
104
-            'country_settings' => [
105
-                'func'       => [$this, '_country_settings'],
106
-                'capability' => 'manage_options',
107
-            ],
108
-
109
-            'update_country_settings' => [
110
-                'func'          => [$this, '_update_country_settings'],
111
-                'capability'    => 'manage_options',
112
-                'noheader'      => true,
113
-                'require_nonce' => true,
114
-            ],
115
-
116
-            'display_country_settings' => [
117
-                'func'       => [$this, 'display_country_settings'],
118
-                'capability' => 'manage_options',
119
-                'noheader'   => true,
120
-            ],
121
-
122
-            'add_new_state' => [
123
-                'func'          => [$this, 'add_new_state'],
124
-                'capability'    => 'manage_options',
125
-                'noheader'      => true,
126
-                'require_nonce' => true,
127
-            ],
128
-
129
-            'delete_state' => [
130
-                'func'          => [$this, 'delete_state'],
131
-                'capability'    => 'manage_options',
132
-                'noheader'      => true,
133
-                'require_nonce' => true,
134
-            ],
135
-
136
-            'privacy_settings' => [
137
-                'func'       => [$this, 'privacySettings'],
138
-                'capability' => 'manage_options',
139
-            ],
140
-
141
-            'update_privacy_settings' => [
142
-                'func'               => [$this, 'updatePrivacySettings'],
143
-                'capability'         => 'manage_options',
144
-                'noheader'           => true,
145
-                'headers_sent_route' => 'privacy_settings',
146
-            ],
147
-
148
-            'set_font_size'            => [
149
-                'func'       => [$this, 'setFontSize'],
150
-                'noheader'   => true,
151
-            ],
152
-        ];
153
-    }
154
-
155
-
156
-    /**
157
-     * Set page configuration property
158
-     */
159
-    protected function _set_page_config()
160
-    {
161
-        $this->_page_config = [
162
-            'critical_pages'        => [
163
-                'nav'           => [
164
-                    'label' => esc_html__('Critical Pages', 'event_espresso'),
165
-                    'icon' => 'dashicons-warning',
166
-                    'order' => 50,
167
-                ],
168
-                'metaboxes'     => array_merge($this->_default_espresso_metaboxes, ['_publish_post_box']),
169
-                'help_tabs'     => [
170
-                    'general_settings_critical_pages_help_tab' => [
171
-                        'title'    => esc_html__('Critical Pages', 'event_espresso'),
172
-                        'filename' => 'general_settings_critical_pages',
173
-                    ],
174
-                ],
175
-                'require_nonce' => false,
176
-            ],
177
-            'default'               => [
178
-                'nav'           => [
179
-                    'label' => esc_html__('Your Organization', 'event_espresso'),
180
-                    'icon' => 'dashicons-admin-home',
181
-                    'order' => 20,
182
-                ],
183
-                'help_tabs'     => [
184
-                    'general_settings_your_organization_help_tab' => [
185
-                        'title'    => esc_html__('Your Organization', 'event_espresso'),
186
-                        'filename' => 'general_settings_your_organization',
187
-                    ],
188
-                ],
189
-                'metaboxes'     => array_merge($this->_default_espresso_metaboxes, ['_publish_post_box']),
190
-                'require_nonce' => false,
191
-            ],
192
-            'admin_option_settings' => [
193
-                'nav'           => [
194
-                    'label' => esc_html__('Admin Options', 'event_espresso'),
195
-                    'icon' => 'dashicons-admin-settings',
196
-                    'order' => 60,
197
-                ],
198
-                'metaboxes'     => array_merge($this->_default_espresso_metaboxes, ['_publish_post_box']),
199
-                'help_tabs'     => [
200
-                    'general_settings_admin_options_help_tab' => [
201
-                        'title'    => esc_html__('Admin Options', 'event_espresso'),
202
-                        'filename' => 'general_settings_admin_options',
203
-                    ],
204
-                ],
205
-                'require_nonce' => false,
206
-            ],
207
-            'country_settings'      => [
208
-                'nav'           => [
209
-                    'label' => esc_html__('Countries', 'event_espresso'),
210
-                    'icon' => 'dashicons-admin-site',
211
-                    'order' => 70,
212
-                ],
213
-                'help_tabs'     => [
214
-                    'general_settings_countries_help_tab' => [
215
-                        'title'    => esc_html__('Countries', 'event_espresso'),
216
-                        'filename' => 'general_settings_countries',
217
-                    ],
218
-                ],
219
-                'require_nonce' => false,
220
-            ],
221
-            'privacy_settings'      => [
222
-                'nav'           => [
223
-                    'label' => esc_html__('Privacy', 'event_espresso'),
224
-                    'icon' => 'dashicons-privacy',
225
-                    'order' => 80,
226
-                ],
227
-                'metaboxes'     => array_merge($this->_default_espresso_metaboxes, ['_publish_post_box']),
228
-                'require_nonce' => false,
229
-            ],
230
-        ];
231
-    }
232
-
233
-
234
-    protected function _add_screen_options()
235
-    {
236
-    }
237
-
238
-
239
-    protected function _add_feature_pointers()
240
-    {
241
-    }
242
-
243
-
244
-    /**
245
-     * Enqueue global scripts and styles for all routes in the General Settings Admin Pages.
246
-     */
247
-    public function load_scripts_styles()
248
-    {
249
-        // styles
250
-        wp_enqueue_style('espresso-ui-theme');
251
-        // scripts
252
-        wp_enqueue_script('ee_admin_js');
253
-    }
254
-
255
-
256
-    /**
257
-     * Execute logic running on `admin_init`
258
-     */
259
-    public function admin_init()
260
-    {
261
-        EE_Registry::$i18n_js_strings['invalid_server_response'] = wp_strip_all_tags(
262
-            esc_html__(
263
-                '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.',
264
-                'event_espresso'
265
-            )
266
-        );
267
-        EE_Registry::$i18n_js_strings['error_occurred']          = wp_strip_all_tags(
268
-            esc_html__(
269
-                'An error occurred! Please refresh the page and try again.',
270
-                'event_espresso'
271
-            )
272
-        );
273
-        EE_Registry::$i18n_js_strings['confirm_delete_state']    = wp_strip_all_tags(
274
-            esc_html__(
275
-                'Are you sure you want to delete this State / Province?',
276
-                'event_espresso'
277
-            )
278
-        );
279
-        EE_Registry::$i18n_js_strings['ajax_url']                = admin_url(
280
-            'admin-ajax.php?page=espresso_general_settings',
281
-            is_ssl() ? 'https://' : 'http://'
282
-        );
283
-    }
284
-
285
-
286
-    public function admin_notices()
287
-    {
288
-    }
289
-
290
-
291
-    public function admin_footer_scripts()
292
-    {
293
-    }
294
-
295
-
296
-    /**
297
-     * Enqueue scripts and styles for the default route.
298
-     */
299
-    public function load_scripts_styles_default()
300
-    {
301
-        // styles
302
-        wp_enqueue_style('thickbox');
303
-        // scripts
304
-        wp_enqueue_script('media-upload');
305
-        wp_enqueue_script('thickbox');
306
-        wp_register_script(
307
-            'organization_settings',
308
-            GEN_SET_ASSETS_URL . 'your_organization_settings.js',
309
-            ['jquery', 'media-upload', 'thickbox'],
310
-            EVENT_ESPRESSO_VERSION,
311
-            true
312
-        );
313
-        wp_register_style('organization-css', GEN_SET_ASSETS_URL . 'organization.css', [], EVENT_ESPRESSO_VERSION);
314
-        wp_enqueue_script('organization_settings');
315
-        wp_enqueue_style('organization-css');
316
-        $confirm_image_delete = [
317
-            'text' => wp_strip_all_tags(
318
-                esc_html__(
319
-                    'Do you really want to delete this image? Please remember to save your settings to complete the removal.',
320
-                    'event_espresso'
321
-                )
322
-            ),
323
-        ];
324
-        wp_localize_script('organization_settings', 'confirm_image_delete', $confirm_image_delete);
325
-    }
326
-
327
-
328
-    /**
329
-     * Enqueue scripts and styles for the country settings route.
330
-     */
331
-    public function load_scripts_styles_country_settings()
332
-    {
333
-        // scripts
334
-        wp_register_script(
335
-            'gen_settings_countries',
336
-            GEN_SET_ASSETS_URL . 'gen_settings_countries.js',
337
-            ['ee_admin_js'],
338
-            EVENT_ESPRESSO_VERSION,
339
-            true
340
-        );
341
-        wp_register_style('organization-css', GEN_SET_ASSETS_URL . 'organization.css', [], EVENT_ESPRESSO_VERSION);
342
-        wp_enqueue_script('gen_settings_countries');
343
-        wp_enqueue_style('organization-css');
344
-    }
345
-
346
-
347
-    /*************        Espresso Pages        *************/
348
-    /**
349
-     * _espresso_page_settings
350
-     *
351
-     * @throws EE_Error
352
-     * @throws DomainException
353
-     * @throws DomainException
354
-     * @throws InvalidDataTypeException
355
-     * @throws InvalidArgumentException
356
-     */
357
-    protected function _espresso_page_settings()
358
-    {
359
-        // Check to make sure all of the main pages are set up properly,
360
-        // if not create the default pages and display an admin notice
361
-        EEH_Activation::verify_default_pages_exist();
362
-        $this->_transient_garbage_collection();
363
-
364
-        $this->_template_args['values'] = $this->_yes_no_values;
365
-
366
-        $this->_template_args['reg_page_id']  = $this->core_config->reg_page_id ?? null;
367
-        $this->_template_args['reg_page_obj'] = isset($this->core_config->reg_page_id)
368
-            ? get_post($this->core_config->reg_page_id)
369
-            : false;
370
-
371
-        $this->_template_args['txn_page_id']  = $this->core_config->txn_page_id ?? null;
372
-        $this->_template_args['txn_page_obj'] = isset($this->core_config->txn_page_id)
373
-            ? get_post($this->core_config->txn_page_id)
374
-            : false;
375
-
376
-        $this->_template_args['thank_you_page_id']  = $this->core_config->thank_you_page_id ?? null;
377
-        $this->_template_args['thank_you_page_obj'] = isset($this->core_config->thank_you_page_id)
378
-            ? get_post($this->core_config->thank_you_page_id)
379
-            : false;
380
-
381
-        $this->_template_args['cancel_page_id']  = $this->core_config->cancel_page_id ?? null;
382
-        $this->_template_args['cancel_page_obj'] = isset($this->core_config->cancel_page_id)
383
-            ? get_post($this->core_config->cancel_page_id)
384
-            : false;
385
-
386
-        $this->_set_add_edit_form_tags('update_espresso_page_settings');
387
-        $this->_set_publish_post_box_vars();
388
-        $this->_template_args['admin_page_content'] = EEH_Template::display_template(
389
-            GEN_SET_TEMPLATE_PATH . 'espresso_page_settings.template.php',
390
-            $this->_template_args,
391
-            true
392
-        );
393
-        $this->display_admin_page_with_sidebar();
394
-    }
395
-
396
-
397
-    /**
398
-     * Handler for updating espresso page settings.
399
-     *
400
-     * @throws EE_Error
401
-     */
402
-    protected function _update_espresso_page_settings()
403
-    {
404
-        $this->core_config = EE_Registry::instance()->CFG->core;
405
-        // capture incoming request data && set page IDs
406
-        $this->core_config->reg_page_id       = $this->request->getRequestParam(
407
-            'reg_page_id',
408
-            $this->core_config->reg_page_id,
409
-            DataType::INT
410
-        );
411
-        $this->core_config->txn_page_id       = $this->request->getRequestParam(
412
-            'txn_page_id',
413
-            $this->core_config->txn_page_id,
414
-            DataType::INT
415
-        );
416
-        $this->core_config->thank_you_page_id = $this->request->getRequestParam(
417
-            'thank_you_page_id',
418
-            $this->core_config->thank_you_page_id,
419
-            DataType::INT
420
-        );
421
-        $this->core_config->cancel_page_id    = $this->request->getRequestParam(
422
-            'cancel_page_id',
423
-            $this->core_config->cancel_page_id,
424
-            DataType::INT
425
-        );
426
-
427
-        $this->core_config = apply_filters(
428
-            'FHEE__General_Settings_Admin_Page___update_espresso_page_settings__CFG_core',
429
-            $this->core_config,
430
-            $this->request->requestParams()
431
-        );
432
-
433
-        $what = esc_html__('Critical Pages & Shortcodes', 'event_espresso');
434
-        $this->_redirect_after_action(
435
-            $this->_update_espresso_configuration(
436
-                $what,
437
-                $this->core_config,
438
-                __FILE__,
439
-                __FUNCTION__,
440
-                __LINE__
441
-            ),
442
-            $what,
443
-            '',
444
-            [
445
-                'action' => 'critical_pages',
446
-            ],
447
-            true
448
-        );
449
-    }
450
-
451
-
452
-    /*************        Your Organization        *************/
453
-
454
-
455
-    /**
456
-     * @throws DomainException
457
-     * @throws EE_Error
458
-     * @throws InvalidArgumentException
459
-     * @throws InvalidDataTypeException
460
-     * @throws InvalidInterfaceException
461
-     */
462
-    protected function _your_organization_settings()
463
-    {
464
-        $this->_template_args['admin_page_content'] = '';
465
-        try {
466
-            /** @var OrganizationSettings $organization_settings_form */
467
-            $organization_settings_form = $this->loader->getShared(OrganizationSettings::class);
468
-
469
-            $this->_template_args['admin_page_content'] = EEH_HTML::div(
470
-                $organization_settings_form->display(),
471
-                '',
472
-                'padding'
473
-            );
474
-        } catch (Exception $e) {
475
-            EE_Error::add_error($e->getMessage(), __FILE__, __FUNCTION__, __LINE__);
476
-        }
477
-        $this->_set_add_edit_form_tags('update_your_organization_settings');
478
-        $this->_set_publish_post_box_vars();
479
-        $this->display_admin_page_with_sidebar();
480
-    }
481
-
482
-
483
-    /**
484
-     * Handler for updating organization settings.
485
-     *
486
-     * @throws EE_Error
487
-     */
488
-    protected function _update_your_organization_settings()
489
-    {
490
-        try {
491
-            /** @var OrganizationSettings $organization_settings_form */
492
-            $organization_settings_form = $this->loader->getShared(OrganizationSettings::class);
493
-
494
-            $success = $organization_settings_form->process($this->request->requestParams());
495
-
496
-            EE_Registry::instance()->CFG = apply_filters(
497
-                'FHEE__General_Settings_Admin_Page___update_your_organization_settings__CFG',
498
-                EE_Registry::instance()->CFG
499
-            );
500
-        } catch (Exception $e) {
501
-            EE_Error::add_error($e->getMessage(), __FILE__, __FUNCTION__, __LINE__);
502
-            $success = false;
503
-        }
504
-
505
-        if ($success) {
506
-            $success = $this->_update_espresso_configuration(
507
-                esc_html__('Your Organization Settings', 'event_espresso'),
508
-                EE_Registry::instance()->CFG,
509
-                __FILE__,
510
-                __FUNCTION__,
511
-                __LINE__
512
-            );
513
-        }
514
-
515
-        $this->_redirect_after_action($success, '', '', ['action' => 'default'], true);
516
-    }
517
-
518
-
519
-
520
-    /*************        Admin Options        *************/
521
-
522
-
523
-    /**
524
-     * _admin_option_settings
525
-     *
526
-     * @throws EE_Error
527
-     * @throws LogicException
528
-     */
529
-    protected function _admin_option_settings()
530
-    {
531
-        $this->_template_args['admin_page_content'] = '';
532
-        try {
533
-            $admin_options_settings_form = new AdminOptionsSettings(EE_Registry::instance());
534
-            // still need this for the old school form in Extend_General_Settings_Admin_Page
535
-            $this->_template_args['values'] = $this->_yes_no_values;
536
-            // also need to account for the do_action that was in the old template
537
-            $admin_options_settings_form->setTemplateArgs($this->_template_args);
538
-            $this->_template_args['admin_page_content'] = EEH_HTML::div(
539
-                $admin_options_settings_form->display(),
540
-                '',
541
-                'padding'
542
-            );
543
-        } catch (Exception $e) {
544
-            EE_Error::add_error($e->getMessage(), __FILE__, __FUNCTION__, __LINE__);
545
-        }
546
-        $this->_set_add_edit_form_tags('update_admin_option_settings');
547
-        $this->_set_publish_post_box_vars();
548
-        $this->display_admin_page_with_sidebar();
549
-    }
550
-
551
-
552
-    /**
553
-     * _update_admin_option_settings
554
-     *
555
-     * @throws EE_Error
556
-     * @throws InvalidDataTypeException
557
-     * @throws InvalidFormSubmissionException
558
-     * @throws InvalidArgumentException
559
-     * @throws LogicException
560
-     */
561
-    protected function _update_admin_option_settings()
562
-    {
563
-        try {
564
-            $admin_options_settings_form = new AdminOptionsSettings(EE_Registry::instance());
565
-            $admin_options_settings_form->process(
566
-                $this->request->getRequestParam(
567
-                    $admin_options_settings_form->slug(),
568
-                    [],
569
-                    DataType::STRING,
570
-                    true
571
-                )
572
-            );
573
-            EE_Registry::instance()->CFG->admin = apply_filters(
574
-                'FHEE__General_Settings_Admin_Page___update_admin_option_settings__CFG_admin',
575
-                EE_Registry::instance()->CFG->admin
576
-            );
577
-        } catch (Exception $e) {
578
-            EE_Error::add_error($e->getMessage(), __FILE__, __FUNCTION__, __LINE__);
579
-        }
580
-        $this->_redirect_after_action(
581
-            apply_filters(
582
-                'FHEE__General_Settings_Admin_Page___update_admin_option_settings__success',
583
-                $this->_update_espresso_configuration(
584
-                    esc_html__('Admin Options', 'event_espresso'),
585
-                    EE_Registry::instance()->CFG->admin,
586
-                    __FILE__,
587
-                    __FUNCTION__,
588
-                    __LINE__
589
-                )
590
-            ),
591
-            esc_html__('Admin Options', 'event_espresso'),
592
-            'updated',
593
-            ['action' => 'admin_option_settings']
594
-        );
595
-    }
596
-
597
-
598
-    /*************        Countries        *************/
599
-
600
-
601
-    /**
602
-     * @param string|null $default
603
-     * @return string
604
-     */
605
-    protected function getCountryISO(?string $default = null): string
606
-    {
607
-        $default = $default ?? $this->getCountryIsoForSite();
608
-        $CNT_ISO = $this->request->getRequestParam('country', $default);
609
-        $CNT_ISO = $this->request->getRequestParam('CNT_ISO', $CNT_ISO);
610
-        return strtoupper($CNT_ISO);
611
-    }
612
-
613
-
614
-    /**
615
-     * @return string
616
-     */
617
-    protected function getCountryIsoForSite(): string
618
-    {
619
-        return ! empty(EE_Registry::instance()->CFG->organization->CNT_ISO)
620
-            ? EE_Registry::instance()->CFG->organization->CNT_ISO
621
-            : 'US';
622
-    }
623
-
624
-
625
-    /**
626
-     * @param string          $CNT_ISO
627
-     * @param EE_Country|null $country
628
-     * @return EE_Base_Class|EE_Country
629
-     * @throws EE_Error
630
-     * @throws InvalidArgumentException
631
-     * @throws InvalidDataTypeException
632
-     * @throws InvalidInterfaceException
633
-     * @throws ReflectionException
634
-     */
635
-    protected function verifyOrGetCountryFromIso(string $CNT_ISO, ?EE_Country $country = null)
636
-    {
637
-        /** @var EE_Country $country */
638
-        return $country instanceof EE_Country && $country->ID() === $CNT_ISO
639
-            ? $country
640
-            : EEM_Country::instance()->get_one_by_ID($CNT_ISO);
641
-    }
642
-
643
-
644
-    /**
645
-     * Output Country Settings view.
646
-     *
647
-     * @throws DomainException
648
-     * @throws EE_Error
649
-     * @throws InvalidArgumentException
650
-     * @throws InvalidDataTypeException
651
-     * @throws InvalidInterfaceException
652
-     * @throws ReflectionException
653
-     */
654
-    protected function _country_settings()
655
-    {
656
-        $CNT_ISO = $this->getCountryISO();
657
-
658
-        $this->_template_args['values']    = $this->_yes_no_values;
659
-        $this->_template_args['countries'] = new EE_Question_Form_Input(
660
-            EE_Question::new_instance(
661
-                [
662
-                  'QST_ID'           => 0,
663
-                  'QST_display_text' => esc_html__('Select Country', 'event_espresso'),
664
-                  'QST_system'       => 'admin-country',
665
-                ]
666
-            ),
667
-            EE_Answer::new_instance(
668
-                [
669
-                    'ANS_ID'    => 0,
670
-                    'ANS_value' => $CNT_ISO,
671
-                ]
672
-            ),
673
-            [
674
-                'input_id'       => 'country',
675
-                'input_name'     => 'country',
676
-                'input_prefix'   => '',
677
-                'append_qstn_id' => false,
678
-            ]
679
-        );
680
-
681
-        $country = $this->verifyOrGetCountryFromIso($CNT_ISO);
682
-        add_filter('FHEE__EEH_Form_Fields__label_html', [$this, 'country_form_field_label_wrap'], 10);
683
-        add_filter('FHEE__EEH_Form_Fields__input_html', [$this, 'country_form_field_input__wrap'], 10);
684
-        $this->_template_args['country_details_settings'] = $this->display_country_settings(
685
-            $country->ID(),
686
-            $country
687
-        );
688
-        $this->_template_args['country_states_settings']  = $this->display_country_states(
689
-            $country->ID(),
690
-            $country
691
-        );
692
-        $this->_template_args['CNT_name_for_site']        = $country->name();
693
-
694
-        $this->_set_add_edit_form_tags('update_country_settings');
695
-        $this->_set_publish_post_box_vars();
696
-        $this->_template_args['admin_page_content'] = EEH_Template::display_template(
697
-            GEN_SET_TEMPLATE_PATH . 'countries_settings.template.php',
698
-            $this->_template_args,
699
-            true
700
-        );
701
-        $this->display_admin_page_with_no_sidebar();
702
-    }
703
-
704
-
705
-    /**
706
-     * @param string          $CNT_ISO
707
-     * @param EE_Country|null $country
708
-     * @return string
709
-     * @throws DomainException
710
-     * @throws EE_Error
711
-     * @throws InvalidArgumentException
712
-     * @throws InvalidDataTypeException
713
-     * @throws InvalidInterfaceException
714
-     * @throws ReflectionException
715
-     */
716
-    public function display_country_settings(string $CNT_ISO = '', ?EE_Country $country = null): string
717
-    {
718
-        $CNT_ISO          = $this->getCountryISO($CNT_ISO);
719
-        $CNT_ISO_for_site = $this->getCountryIsoForSite();
720
-
721
-        if (! $CNT_ISO) {
722
-            return '';
723
-        }
724
-
725
-        // for ajax
726
-        remove_all_filters('FHEE__EEH_Form_Fields__label_html');
727
-        remove_all_filters('FHEE__EEH_Form_Fields__input_html');
728
-        add_filter('FHEE__EEH_Form_Fields__label_html', [$this, 'country_form_field_label_wrap'], 10, 2);
729
-        add_filter('FHEE__EEH_Form_Fields__input_html', [$this, 'country_form_field_input__wrap'], 10, 2);
730
-        $country                                  = $this->verifyOrGetCountryFromIso($CNT_ISO, $country);
731
-        $CNT_cur_disabled                         = $CNT_ISO !== $CNT_ISO_for_site;
732
-        $this->_template_args['CNT_cur_disabled'] = $CNT_cur_disabled;
733
-
734
-        $country_input_types            = [
735
-            'CNT_active'      => [
736
-                'type'             => 'RADIO_BTN',
737
-                'input_name'       => "cntry[$CNT_ISO]",
738
-                'class'            => '',
739
-                'options'          => $this->_yes_no_values,
740
-                'use_desc_4_label' => true,
741
-            ],
742
-            'CNT_ISO'         => [
743
-                'type'       => 'TEXT',
744
-                'input_name' => "cntry[$CNT_ISO]",
745
-                'class'      => 'ee-input-width--small',
746
-            ],
747
-            'CNT_ISO3'        => [
748
-                'type'       => 'TEXT',
749
-                'input_name' => "cntry[$CNT_ISO]",
750
-                'class'      => 'ee-input-width--small',
751
-            ],
752
-            // 'RGN_ID'          => [
753
-            //     'type'       => 'TEXT',
754
-            //     'input_name' => "cntry[$CNT_ISO]",
755
-            //     'class'      => 'ee-input-width--small',
756
-            // ],
757
-            'CNT_name'        => [
758
-                'type'       => 'TEXT',
759
-                'input_name' => "cntry[$CNT_ISO]",
760
-                'class'      => 'ee-input-width--big',
761
-            ],
762
-            'CNT_cur_code'    => [
763
-                'type'       => 'TEXT',
764
-                'input_name' => "cntry[$CNT_ISO]",
765
-                'class'      => 'ee-input-width--small',
766
-                'disabled'   => $CNT_cur_disabled,
767
-            ],
768
-            'CNT_cur_single'  => [
769
-                'type'       => 'TEXT',
770
-                'input_name' => "cntry[$CNT_ISO]",
771
-                'class'      => 'ee-input-width--reg',
772
-                'disabled'   => $CNT_cur_disabled,
773
-            ],
774
-            'CNT_cur_plural'  => [
775
-                'type'       => 'TEXT',
776
-                'input_name' => "cntry[$CNT_ISO]",
777
-                'class'      => 'ee-input-width--reg',
778
-                'disabled'   => $CNT_cur_disabled,
779
-            ],
780
-            'CNT_cur_sign'    => [
781
-                'type'         => 'TEXT',
782
-                'input_name'   => "cntry[$CNT_ISO]",
783
-                'class'        => 'ee-input-width--small',
784
-                'htmlentities' => false,
785
-                'disabled'     => $CNT_cur_disabled,
786
-            ],
787
-            'CNT_cur_sign_b4' => [
788
-                'type'             => 'RADIO_BTN',
789
-                'input_name'       => "cntry[$CNT_ISO]",
790
-                'class'            => '',
791
-                'options'          => $this->_yes_no_values,
792
-                'use_desc_4_label' => true,
793
-                'disabled'         => $CNT_cur_disabled,
794
-            ],
795
-            'CNT_cur_dec_plc' => [
796
-                'type'       => 'RADIO_BTN',
797
-                'input_name' => "cntry[$CNT_ISO]",
798
-                'class'      => '',
799
-                'options'    => [
800
-                    ['id' => 0, 'text' => ''],
801
-                    ['id' => 1, 'text' => ''],
802
-                    ['id' => 2, 'text' => ''],
803
-                    ['id' => 3, 'text' => ''],
804
-                ],
805
-                'disabled'   => $CNT_cur_disabled,
806
-            ],
807
-            'CNT_cur_dec_mrk' => [
808
-                'type'             => 'RADIO_BTN',
809
-                'input_name'       => "cntry[$CNT_ISO]",
810
-                'class'            => '',
811
-                'options'          => [
812
-                    [
813
-                        'id'   => ',',
814
-                        'text' => esc_html__(', (comma)', 'event_espresso'),
815
-                    ],
816
-                    ['id' => '.', 'text' => esc_html__('. (decimal)', 'event_espresso')],
817
-                ],
818
-                'use_desc_4_label' => true,
819
-                'disabled'         => $CNT_cur_disabled,
820
-            ],
821
-            'CNT_cur_thsnds'  => [
822
-                'type'             => 'RADIO_BTN',
823
-                'input_name'       => "cntry[$CNT_ISO]",
824
-                'class'            => '',
825
-                'options'          => [
826
-                    [
827
-                        'id'   => ',',
828
-                        'text' => esc_html__(', (comma)', 'event_espresso'),
829
-                    ],
830
-                    [
831
-                        'id'   => '.',
832
-                        'text' => esc_html__('. (decimal)', 'event_espresso'),
833
-                    ],
834
-                    [
835
-                        'id'   => '&nbsp;',
836
-                        'text' => esc_html__('(space)', 'event_espresso'),
837
-                    ],
838
-                    [
839
-                        'id'   => '_',
840
-                        'text' => esc_html__('_ (underscore)', 'event_espresso'),
841
-                    ],
842
-                    [
843
-                        'id'   => "'",
844
-                        'text' => esc_html__("' (apostrophe)", 'event_espresso'),
845
-                    ],
846
-                    [
847
-                        'id'   => "",
848
-                        'text' => esc_html__(" (nothing)", 'event_espresso'),
849
-                    ],
850
-                ],
851
-                'use_desc_4_label' => true,
852
-                'disabled'         => $CNT_cur_disabled,
853
-            ],
854
-            'CNT_tel_code'    => [
855
-                'type'       => 'TEXT',
856
-                'input_name' => "cntry[$CNT_ISO]",
857
-                'class'      => 'ee-input-width--small',
858
-            ],
859
-            'CNT_is_EU'       => [
860
-                'type'             => 'RADIO_BTN',
861
-                'input_name'       => "cntry[$CNT_ISO]",
862
-                'class'            => '',
863
-                'options'          => $this->_yes_no_values,
864
-                'use_desc_4_label' => true,
865
-            ],
866
-        ];
867
-        $this->_template_args['inputs'] = EE_Question_Form_Input::generate_question_form_inputs_for_object(
868
-            $country,
869
-            $country_input_types
870
-        );
871
-        $country_details_settings       = EEH_Template::display_template(
872
-            GEN_SET_TEMPLATE_PATH . 'country_details_settings.template.php',
873
-            $this->_template_args,
874
-            true
875
-        );
876
-
877
-        if (defined('DOING_AJAX')) {
878
-            $notices = EE_Error::get_notices(false, false, false);
879
-            echo wp_json_encode(
880
-                [
881
-                    'return_data' => $country_details_settings,
882
-                    'success'     => $notices['success'],
883
-                    'errors'      => $notices['errors'],
884
-                ]
885
-            );
886
-            die();
887
-        }
888
-        return $country_details_settings;
889
-    }
890
-
891
-
892
-    /**
893
-     * @param string          $CNT_ISO
894
-     * @param EE_Country|null $country
895
-     * @return string
896
-     * @throws DomainException
897
-     * @throws EE_Error
898
-     * @throws InvalidArgumentException
899
-     * @throws InvalidDataTypeException
900
-     * @throws InvalidInterfaceException
901
-     * @throws ReflectionException
902
-     */
903
-    public function display_country_states(string $CNT_ISO = '', ?EE_Country $country = null): string
904
-    {
905
-        $CNT_ISO = $this->getCountryISO($CNT_ISO);
906
-        if (! $CNT_ISO) {
907
-            return '';
908
-        }
909
-        // for ajax
910
-        remove_all_filters('FHEE__EEH_Form_Fields__label_html');
911
-        remove_all_filters('FHEE__EEH_Form_Fields__input_html');
912
-        add_filter('FHEE__EEH_Form_Fields__label_html', [$this, 'state_form_field_label_wrap'], 10, 2);
913
-        add_filter('FHEE__EEH_Form_Fields__input_html', [$this, 'state_form_field_input__wrap'], 10);
914
-        $states = EEM_State::instance()->get_all_states_for_these_countries([$CNT_ISO => $CNT_ISO]);
915
-        if (empty($states)) {
916
-            /** @var EventEspresso\core\services\address\CountrySubRegionDao $countrySubRegionDao */
917
-            $countrySubRegionDao = $this->loader->getShared(
918
-                'EventEspresso\core\services\address\CountrySubRegionDao'
919
-            );
920
-            if ($countrySubRegionDao instanceof EventEspresso\core\services\address\CountrySubRegionDao) {
921
-                $country = $this->verifyOrGetCountryFromIso($CNT_ISO, $country);
922
-                if ($countrySubRegionDao->saveCountrySubRegions($country)) {
923
-                    $states = EEM_State::instance()->get_all_states_for_these_countries([$CNT_ISO => $CNT_ISO]);
924
-                }
925
-            }
926
-        }
927
-        foreach ($states as $STA_ID => $state) {
928
-            if ($state instanceof EE_State) {
929
-                $inputs = EE_Question_Form_Input::generate_question_form_inputs_for_object(
930
-                    $state,
931
-                    [
932
-                        'STA_abbrev' => [
933
-                            'type'             => 'TEXT',
934
-                            'label'            => esc_html__('Code', 'event_espresso'),
935
-                            'input_name'       => "states[$STA_ID]",
936
-                            'class'            => 'ee-input-width--tiny',
937
-                            'add_mobile_label' => true,
938
-                        ],
939
-                        'STA_name'   => [
940
-                            'type'             => 'TEXT',
941
-                            'label'            => esc_html__('Name', 'event_espresso'),
942
-                            'input_name'       => "states[$STA_ID]",
943
-                            'class'            => 'ee-input-width--big',
944
-                            'add_mobile_label' => true,
945
-                        ],
946
-                        'STA_active' => [
947
-                            'type'             => 'RADIO_BTN',
948
-                            'label'            => esc_html__(
949
-                                'State Appears in Dropdown Select Lists',
950
-                                'event_espresso'
951
-                            ),
952
-                            'input_name'       => "states[$STA_ID]",
953
-                            'options'          => $this->_yes_no_values,
954
-                            'use_desc_4_label' => true,
955
-                            'add_mobile_label' => true,
956
-                        ],
957
-                    ]
958
-                );
959
-
960
-                $delete_state_url = EE_Admin_Page::add_query_args_and_nonce(
961
-                    [
962
-                        'action'     => 'delete_state',
963
-                        'STA_ID'     => $STA_ID,
964
-                        'CNT_ISO'    => $CNT_ISO,
965
-                        'STA_abbrev' => $state->abbrev(),
966
-                    ],
967
-                    GEN_SET_ADMIN_URL
968
-                );
969
-
970
-                $this->_template_args['states'][ $STA_ID ]['inputs']           = $inputs;
971
-                $this->_template_args['states'][ $STA_ID ]['delete_state_url'] = $delete_state_url;
972
-            }
973
-        }
974
-
975
-        $this->_template_args['add_new_state_nonce'] = wp_create_nonce('espresso_add_new_state');
976
-        $this->_template_args['delete_state_nonce'] = wp_create_nonce('espresso_delete_state');
977
-
978
-        $state_details_settings = EEH_Template::display_template(
979
-            GEN_SET_TEMPLATE_PATH . 'state_details_settings.template.php',
980
-            $this->_template_args,
981
-            true
982
-        );
983
-
984
-        if (defined('DOING_AJAX')) {
985
-            $notices = EE_Error::get_notices(false, false, false);
986
-            echo wp_json_encode(
987
-                [
988
-                    'return_data' => $state_details_settings,
989
-                    'success'     => $notices['success'],
990
-                    'errors'      => $notices['errors'],
991
-                ]
992
-            );
993
-            die();
994
-        }
995
-        return $state_details_settings;
996
-    }
997
-
998
-
999
-    /**
1000
-     * @return void
1001
-     * @throws EE_Error
1002
-     * @throws InvalidArgumentException
1003
-     * @throws InvalidDataTypeException
1004
-     * @throws InvalidInterfaceException
1005
-     * @throws ReflectionException
1006
-     */
1007
-    public function add_new_state()
1008
-    {
1009
-        $this->_verify_nonce();
1010
-        // add_new_state_nonce
1011
-        if (! $this->capabilities->current_user_can('manage_options', __FUNCTION__)) {
1012
-            wp_die(esc_html__('You do not have the required privileges to perform this action', 'event_espresso'));
1013
-        }
1014
-
1015
-        $success = true;
1016
-        $CNT_ISO = $this->getCountryISO('');
1017
-        if (! $CNT_ISO) {
1018
-            EE_Error::add_error(
1019
-                esc_html__('No Country ISO code or an invalid Country ISO code was received.', 'event_espresso'),
1020
-                __FILE__,
1021
-                __FUNCTION__,
1022
-                __LINE__
1023
-            );
1024
-            $success = false;
1025
-        }
1026
-        $STA_abbrev = $this->request->getRequestParam('STA_abbrev');
1027
-        if (! $STA_abbrev) {
1028
-            EE_Error::add_error(
1029
-                esc_html__('No State ISO code or an invalid State ISO code was received.', 'event_espresso'),
1030
-                __FILE__,
1031
-                __FUNCTION__,
1032
-                __LINE__
1033
-            );
1034
-            $success = false;
1035
-        }
1036
-        $STA_name = $this->request->getRequestParam('STA_name');
1037
-        if (! $STA_name) {
1038
-            EE_Error::add_error(
1039
-                esc_html__('No State name or an invalid State name was received.', 'event_espresso'),
1040
-                __FILE__,
1041
-                __FUNCTION__,
1042
-                __LINE__
1043
-            );
1044
-            $success = false;
1045
-        }
1046
-
1047
-        if ($success) {
1048
-            $cols_n_values = [
1049
-                'CNT_ISO'    => $CNT_ISO,
1050
-                'STA_abbrev' => $STA_abbrev,
1051
-                'STA_name'   => $STA_name,
1052
-                'STA_active' => true,
1053
-            ];
1054
-            $success       = EEM_State::instance()->insert($cols_n_values);
1055
-            EE_Error::add_success(esc_html__('The State was added successfully.', 'event_espresso'));
1056
-        }
1057
-
1058
-        if (defined('DOING_AJAX')) {
1059
-            $notices = EE_Error::get_notices(false, false, false);
1060
-            echo wp_json_encode(array_merge($notices, ['return_data' => $CNT_ISO]));
1061
-            die();
1062
-        }
1063
-        $this->_redirect_after_action(
1064
-            $success,
1065
-            esc_html__('State', 'event_espresso'),
1066
-            'added',
1067
-            ['action' => 'country_settings']
1068
-        );
1069
-    }
1070
-
1071
-
1072
-    /**
1073
-     * @return void
1074
-     * @throws EE_Error
1075
-     * @throws InvalidArgumentException
1076
-     * @throws InvalidDataTypeException
1077
-     * @throws InvalidInterfaceException
1078
-     * @throws ReflectionException
1079
-     */
1080
-    public function delete_state()
1081
-    {
1082
-        $this->_verify_nonce();
1083
-        if (! $this->capabilities->current_user_can('manage_options', __FUNCTION__)) {
1084
-            wp_die(esc_html__('You do not have the required privileges to perform this action', 'event_espresso'));
1085
-        }
1086
-
1087
-        $CNT_ISO    = $this->getCountryISO();
1088
-        $STA_ID     = $this->request->getRequestParam('STA_ID');
1089
-        $STA_abbrev = $this->request->getRequestParam('STA_abbrev');
1090
-
1091
-        if (! $STA_ID) {
1092
-            EE_Error::add_error(
1093
-                esc_html__('No State ID or an invalid State ID was received.', 'event_espresso'),
1094
-                __FILE__,
1095
-                __FUNCTION__,
1096
-                __LINE__
1097
-            );
1098
-            return;
1099
-        }
1100
-
1101
-        $success = EEM_State::instance()->delete_by_ID($STA_ID);
1102
-        if ($success !== false) {
1103
-            do_action(
1104
-                'AHEE__General_Settings_Admin_Page__delete_state__state_deleted',
1105
-                $CNT_ISO,
1106
-                $STA_ID,
1107
-                ['STA_abbrev' => $STA_abbrev]
1108
-            );
1109
-            EE_Error::add_success(esc_html__('The State was deleted successfully.', 'event_espresso'));
1110
-        }
1111
-        if (defined('DOING_AJAX')) {
1112
-            $notices                = EE_Error::get_notices(false);
1113
-            $notices['return_data'] = true;
1114
-            echo wp_json_encode($notices);
1115
-            die();
1116
-        }
1117
-        $this->_redirect_after_action(
1118
-            $success,
1119
-            esc_html__('State', 'event_espresso'),
1120
-            'deleted',
1121
-            ['action' => 'country_settings']
1122
-        );
1123
-    }
1124
-
1125
-
1126
-    /**
1127
-     * @return void
1128
-     * @throws EE_Error
1129
-     * @throws InvalidArgumentException
1130
-     * @throws InvalidDataTypeException
1131
-     * @throws InvalidInterfaceException
1132
-     * @throws ReflectionException
1133
-     */
1134
-    protected function _update_country_settings()
1135
-    {
1136
-        $CNT_ISO = $this->getCountryISO();
1137
-        if (! $CNT_ISO) {
1138
-            EE_Error::add_error(
1139
-                esc_html__('No Country ISO code or an invalid Country ISO code was received.', 'event_espresso'),
1140
-                __FILE__,
1141
-                __FUNCTION__,
1142
-                __LINE__
1143
-            );
1144
-            return;
1145
-        }
1146
-
1147
-        $country = $this->verifyOrGetCountryFromIso($CNT_ISO);
1148
-
1149
-        $cols_n_values                    = [];
1150
-        $cols_n_values['CNT_ISO3']        = strtoupper(
1151
-            $this->request->getRequestParam(
1152
-                "cntry[$CNT_ISO][CNT_ISO3]",
1153
-                $country->ISO3()
1154
-            )
1155
-        );
1156
-        $cols_n_values['CNT_name']        = $this->request->getRequestParam(
1157
-            "cntry[$CNT_ISO][CNT_name]",
1158
-            $country->name()
1159
-        );
1160
-        $cols_n_values['CNT_cur_code']    = strtoupper(
1161
-            $this->request->getRequestParam(
1162
-                "cntry[$CNT_ISO][CNT_cur_code]",
1163
-                $country->currency_code()
1164
-            )
1165
-        );
1166
-        $cols_n_values['CNT_cur_single']  = $this->request->getRequestParam(
1167
-            "cntry[$CNT_ISO][CNT_cur_single]",
1168
-            $country->currency_name_single()
1169
-        );
1170
-        $cols_n_values['CNT_cur_plural']  = $this->request->getRequestParam(
1171
-            "cntry[$CNT_ISO][CNT_cur_plural]",
1172
-            $country->currency_name_plural()
1173
-        );
1174
-        $cols_n_values['CNT_cur_sign']    = $this->request->getRequestParam(
1175
-            "cntry[$CNT_ISO][CNT_cur_sign]",
1176
-            $country->currency_sign()
1177
-        );
1178
-        $cols_n_values['CNT_cur_sign_b4'] = $this->request->getRequestParam(
1179
-            "cntry[$CNT_ISO][CNT_cur_sign_b4]",
1180
-            $country->currency_sign_before(),
1181
-            DataType::BOOL
1182
-        );
1183
-        $cols_n_values['CNT_cur_dec_plc'] = $this->request->getRequestParam(
1184
-            "cntry[$CNT_ISO][CNT_cur_dec_plc]",
1185
-            $country->currency_decimal_places()
1186
-        );
1187
-        $cols_n_values['CNT_cur_dec_mrk'] = $this->request->getRequestParam(
1188
-            "cntry[$CNT_ISO][CNT_cur_dec_mrk]",
1189
-            $country->currency_decimal_mark()
1190
-        );
1191
-        $cols_n_values['CNT_cur_thsnds']  = $this->request->getRequestParam(
1192
-            "cntry[$CNT_ISO][CNT_cur_thsnds]",
1193
-            $country->currency_thousands_separator()
1194
-        );
1195
-        $cols_n_values['CNT_tel_code']    = $this->request->getRequestParam(
1196
-            "cntry[$CNT_ISO][CNT_tel_code]",
1197
-            $country->telephoneCode()
1198
-        );
1199
-        $cols_n_values['CNT_active']      = $this->request->getRequestParam(
1200
-            "cntry[$CNT_ISO][CNT_active]",
1201
-            $country->isActive(),
1202
-            DataType::BOOL
1203
-        );
1204
-        $cols_n_values['CNT_is_EU']      = $this->request->getRequestParam(
1205
-            "cntry[$CNT_ISO][CNT_is_EU]",
1206
-            $country->isEU(),
1207
-            DataType::BOOL
1208
-        );
1209
-
1210
-        // allow filtering of country data
1211
-        $cols_n_values = apply_filters(
1212
-            'FHEE__General_Settings_Admin_Page___update_country_settings__cols_n_values',
1213
-            $cols_n_values
1214
-        );
1215
-
1216
-        // where values
1217
-        $where_cols_n_values = [['CNT_ISO' => $CNT_ISO]];
1218
-        // run the update
1219
-        $success = EEM_Country::instance()->update($cols_n_values, $where_cols_n_values);
1220
-
1221
-        // allow filtering of states data
1222
-        $states = apply_filters(
1223
-            'FHEE__General_Settings_Admin_Page___update_country_settings__states',
1224
-            $this->request->getRequestParam('states', [], DataType::STRING, true)
1225
-        );
1226
-
1227
-        if (! empty($states) && $success !== false) {
1228
-            // loop thru state data ( looks like : states[75][STA_name] )
1229
-            foreach ($states as $STA_ID => $state) {
1230
-                $cols_n_values = [
1231
-                    'CNT_ISO'    => $CNT_ISO,
1232
-                    'STA_abbrev' => sanitize_text_field($state['STA_abbrev']),
1233
-                    'STA_name'   => sanitize_text_field($state['STA_name']),
1234
-                    'STA_active' => filter_var($state['STA_active'], FILTER_VALIDATE_BOOLEAN),
1235
-                ];
1236
-                // where values
1237
-                $where_cols_n_values = [['STA_ID' => $STA_ID]];
1238
-                // run the update
1239
-                $success = EEM_State::instance()->update($cols_n_values, $where_cols_n_values);
1240
-                if ($success !== false) {
1241
-                    do_action(
1242
-                        'AHEE__General_Settings_Admin_Page__update_country_settings__state_saved',
1243
-                        $CNT_ISO,
1244
-                        $STA_ID,
1245
-                        $cols_n_values
1246
-                    );
1247
-                }
1248
-            }
1249
-        }
1250
-        // check if country being edited matches org option country, and if so, then  update EE_Config with new settings
1251
-        if (
1252
-            isset(EE_Registry::instance()->CFG->organization->CNT_ISO)
1253
-            && $CNT_ISO == EE_Registry::instance()->CFG->organization->CNT_ISO
1254
-        ) {
1255
-            EE_Registry::instance()->CFG->currency = new EE_Currency_Config($CNT_ISO);
1256
-            EE_Registry::instance()->CFG->update_espresso_config();
1257
-        }
1258
-
1259
-        if ($success !== false) {
1260
-            EE_Error::add_success(
1261
-                esc_html__('Country Settings updated successfully.', 'event_espresso')
1262
-            );
1263
-        }
1264
-        $this->_redirect_after_action(
1265
-            $success,
1266
-            '',
1267
-            '',
1268
-            ['action' => 'country_settings', 'country' => $CNT_ISO],
1269
-            true
1270
-        );
1271
-    }
1272
-
1273
-
1274
-    /**
1275
-     * form_form_field_label_wrap
1276
-     *
1277
-     * @param string $label
1278
-     * @return string
1279
-     */
1280
-    public function country_form_field_label_wrap(string $label): string
1281
-    {
1282
-        return '
25
+	/**
26
+	 * @var EE_Core_Config
27
+	 */
28
+	public $core_config;
29
+
30
+
31
+	/**
32
+	 * Initialize basic properties.
33
+	 */
34
+	protected function _init_page_props()
35
+	{
36
+		$this->page_slug        = GEN_SET_PG_SLUG;
37
+		$this->page_label       = GEN_SET_LABEL;
38
+		$this->_admin_base_url  = GEN_SET_ADMIN_URL;
39
+		$this->_admin_base_path = GEN_SET_ADMIN;
40
+
41
+		$this->core_config = EE_Registry::instance()->CFG->core;
42
+	}
43
+
44
+
45
+	/**
46
+	 * Set ajax hooks
47
+	 */
48
+	protected function _ajax_hooks()
49
+	{
50
+		add_action('wp_ajax_espresso_display_country_settings', [$this, 'display_country_settings']);
51
+		add_action('wp_ajax_espresso_display_country_states', [$this, 'display_country_states']);
52
+		add_action('wp_ajax_espresso_delete_state', [$this, 'delete_state'], 10, 3);
53
+		add_action('wp_ajax_espresso_add_new_state', [$this, 'add_new_state']);
54
+	}
55
+
56
+
57
+	/**
58
+	 * More page properties initialization.
59
+	 */
60
+	protected function _define_page_props()
61
+	{
62
+		$this->_admin_page_title = GEN_SET_LABEL;
63
+		$this->_labels           = ['publishbox' => esc_html__('Update Settings', 'event_espresso')];
64
+	}
65
+
66
+
67
+	/**
68
+	 * Set page routes property.
69
+	 */
70
+	protected function _set_page_routes()
71
+	{
72
+		$this->_page_routes = [
73
+			'critical_pages'                => [
74
+				'func'       => [$this, '_espresso_page_settings'],
75
+				'capability' => 'manage_options',
76
+			],
77
+			'update_espresso_page_settings' => [
78
+				'func'       => [$this, '_update_espresso_page_settings'],
79
+				'capability' => 'manage_options',
80
+				'noheader'   => true,
81
+			],
82
+			'default'                       => [
83
+				'func'       => [$this, '_your_organization_settings'],
84
+				'capability' => 'manage_options',
85
+			],
86
+
87
+			'update_your_organization_settings' => [
88
+				'func'       => [$this, '_update_your_organization_settings'],
89
+				'capability' => 'manage_options',
90
+				'noheader'   => true,
91
+			],
92
+
93
+			'admin_option_settings' => [
94
+				'func'       => [$this, '_admin_option_settings'],
95
+				'capability' => 'manage_options',
96
+			],
97
+
98
+			'update_admin_option_settings' => [
99
+				'func'       => [$this, '_update_admin_option_settings'],
100
+				'capability' => 'manage_options',
101
+				'noheader'   => true,
102
+			],
103
+
104
+			'country_settings' => [
105
+				'func'       => [$this, '_country_settings'],
106
+				'capability' => 'manage_options',
107
+			],
108
+
109
+			'update_country_settings' => [
110
+				'func'          => [$this, '_update_country_settings'],
111
+				'capability'    => 'manage_options',
112
+				'noheader'      => true,
113
+				'require_nonce' => true,
114
+			],
115
+
116
+			'display_country_settings' => [
117
+				'func'       => [$this, 'display_country_settings'],
118
+				'capability' => 'manage_options',
119
+				'noheader'   => true,
120
+			],
121
+
122
+			'add_new_state' => [
123
+				'func'          => [$this, 'add_new_state'],
124
+				'capability'    => 'manage_options',
125
+				'noheader'      => true,
126
+				'require_nonce' => true,
127
+			],
128
+
129
+			'delete_state' => [
130
+				'func'          => [$this, 'delete_state'],
131
+				'capability'    => 'manage_options',
132
+				'noheader'      => true,
133
+				'require_nonce' => true,
134
+			],
135
+
136
+			'privacy_settings' => [
137
+				'func'       => [$this, 'privacySettings'],
138
+				'capability' => 'manage_options',
139
+			],
140
+
141
+			'update_privacy_settings' => [
142
+				'func'               => [$this, 'updatePrivacySettings'],
143
+				'capability'         => 'manage_options',
144
+				'noheader'           => true,
145
+				'headers_sent_route' => 'privacy_settings',
146
+			],
147
+
148
+			'set_font_size'            => [
149
+				'func'       => [$this, 'setFontSize'],
150
+				'noheader'   => true,
151
+			],
152
+		];
153
+	}
154
+
155
+
156
+	/**
157
+	 * Set page configuration property
158
+	 */
159
+	protected function _set_page_config()
160
+	{
161
+		$this->_page_config = [
162
+			'critical_pages'        => [
163
+				'nav'           => [
164
+					'label' => esc_html__('Critical Pages', 'event_espresso'),
165
+					'icon' => 'dashicons-warning',
166
+					'order' => 50,
167
+				],
168
+				'metaboxes'     => array_merge($this->_default_espresso_metaboxes, ['_publish_post_box']),
169
+				'help_tabs'     => [
170
+					'general_settings_critical_pages_help_tab' => [
171
+						'title'    => esc_html__('Critical Pages', 'event_espresso'),
172
+						'filename' => 'general_settings_critical_pages',
173
+					],
174
+				],
175
+				'require_nonce' => false,
176
+			],
177
+			'default'               => [
178
+				'nav'           => [
179
+					'label' => esc_html__('Your Organization', 'event_espresso'),
180
+					'icon' => 'dashicons-admin-home',
181
+					'order' => 20,
182
+				],
183
+				'help_tabs'     => [
184
+					'general_settings_your_organization_help_tab' => [
185
+						'title'    => esc_html__('Your Organization', 'event_espresso'),
186
+						'filename' => 'general_settings_your_organization',
187
+					],
188
+				],
189
+				'metaboxes'     => array_merge($this->_default_espresso_metaboxes, ['_publish_post_box']),
190
+				'require_nonce' => false,
191
+			],
192
+			'admin_option_settings' => [
193
+				'nav'           => [
194
+					'label' => esc_html__('Admin Options', 'event_espresso'),
195
+					'icon' => 'dashicons-admin-settings',
196
+					'order' => 60,
197
+				],
198
+				'metaboxes'     => array_merge($this->_default_espresso_metaboxes, ['_publish_post_box']),
199
+				'help_tabs'     => [
200
+					'general_settings_admin_options_help_tab' => [
201
+						'title'    => esc_html__('Admin Options', 'event_espresso'),
202
+						'filename' => 'general_settings_admin_options',
203
+					],
204
+				],
205
+				'require_nonce' => false,
206
+			],
207
+			'country_settings'      => [
208
+				'nav'           => [
209
+					'label' => esc_html__('Countries', 'event_espresso'),
210
+					'icon' => 'dashicons-admin-site',
211
+					'order' => 70,
212
+				],
213
+				'help_tabs'     => [
214
+					'general_settings_countries_help_tab' => [
215
+						'title'    => esc_html__('Countries', 'event_espresso'),
216
+						'filename' => 'general_settings_countries',
217
+					],
218
+				],
219
+				'require_nonce' => false,
220
+			],
221
+			'privacy_settings'      => [
222
+				'nav'           => [
223
+					'label' => esc_html__('Privacy', 'event_espresso'),
224
+					'icon' => 'dashicons-privacy',
225
+					'order' => 80,
226
+				],
227
+				'metaboxes'     => array_merge($this->_default_espresso_metaboxes, ['_publish_post_box']),
228
+				'require_nonce' => false,
229
+			],
230
+		];
231
+	}
232
+
233
+
234
+	protected function _add_screen_options()
235
+	{
236
+	}
237
+
238
+
239
+	protected function _add_feature_pointers()
240
+	{
241
+	}
242
+
243
+
244
+	/**
245
+	 * Enqueue global scripts and styles for all routes in the General Settings Admin Pages.
246
+	 */
247
+	public function load_scripts_styles()
248
+	{
249
+		// styles
250
+		wp_enqueue_style('espresso-ui-theme');
251
+		// scripts
252
+		wp_enqueue_script('ee_admin_js');
253
+	}
254
+
255
+
256
+	/**
257
+	 * Execute logic running on `admin_init`
258
+	 */
259
+	public function admin_init()
260
+	{
261
+		EE_Registry::$i18n_js_strings['invalid_server_response'] = wp_strip_all_tags(
262
+			esc_html__(
263
+				'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.',
264
+				'event_espresso'
265
+			)
266
+		);
267
+		EE_Registry::$i18n_js_strings['error_occurred']          = wp_strip_all_tags(
268
+			esc_html__(
269
+				'An error occurred! Please refresh the page and try again.',
270
+				'event_espresso'
271
+			)
272
+		);
273
+		EE_Registry::$i18n_js_strings['confirm_delete_state']    = wp_strip_all_tags(
274
+			esc_html__(
275
+				'Are you sure you want to delete this State / Province?',
276
+				'event_espresso'
277
+			)
278
+		);
279
+		EE_Registry::$i18n_js_strings['ajax_url']                = admin_url(
280
+			'admin-ajax.php?page=espresso_general_settings',
281
+			is_ssl() ? 'https://' : 'http://'
282
+		);
283
+	}
284
+
285
+
286
+	public function admin_notices()
287
+	{
288
+	}
289
+
290
+
291
+	public function admin_footer_scripts()
292
+	{
293
+	}
294
+
295
+
296
+	/**
297
+	 * Enqueue scripts and styles for the default route.
298
+	 */
299
+	public function load_scripts_styles_default()
300
+	{
301
+		// styles
302
+		wp_enqueue_style('thickbox');
303
+		// scripts
304
+		wp_enqueue_script('media-upload');
305
+		wp_enqueue_script('thickbox');
306
+		wp_register_script(
307
+			'organization_settings',
308
+			GEN_SET_ASSETS_URL . 'your_organization_settings.js',
309
+			['jquery', 'media-upload', 'thickbox'],
310
+			EVENT_ESPRESSO_VERSION,
311
+			true
312
+		);
313
+		wp_register_style('organization-css', GEN_SET_ASSETS_URL . 'organization.css', [], EVENT_ESPRESSO_VERSION);
314
+		wp_enqueue_script('organization_settings');
315
+		wp_enqueue_style('organization-css');
316
+		$confirm_image_delete = [
317
+			'text' => wp_strip_all_tags(
318
+				esc_html__(
319
+					'Do you really want to delete this image? Please remember to save your settings to complete the removal.',
320
+					'event_espresso'
321
+				)
322
+			),
323
+		];
324
+		wp_localize_script('organization_settings', 'confirm_image_delete', $confirm_image_delete);
325
+	}
326
+
327
+
328
+	/**
329
+	 * Enqueue scripts and styles for the country settings route.
330
+	 */
331
+	public function load_scripts_styles_country_settings()
332
+	{
333
+		// scripts
334
+		wp_register_script(
335
+			'gen_settings_countries',
336
+			GEN_SET_ASSETS_URL . 'gen_settings_countries.js',
337
+			['ee_admin_js'],
338
+			EVENT_ESPRESSO_VERSION,
339
+			true
340
+		);
341
+		wp_register_style('organization-css', GEN_SET_ASSETS_URL . 'organization.css', [], EVENT_ESPRESSO_VERSION);
342
+		wp_enqueue_script('gen_settings_countries');
343
+		wp_enqueue_style('organization-css');
344
+	}
345
+
346
+
347
+	/*************        Espresso Pages        *************/
348
+	/**
349
+	 * _espresso_page_settings
350
+	 *
351
+	 * @throws EE_Error
352
+	 * @throws DomainException
353
+	 * @throws DomainException
354
+	 * @throws InvalidDataTypeException
355
+	 * @throws InvalidArgumentException
356
+	 */
357
+	protected function _espresso_page_settings()
358
+	{
359
+		// Check to make sure all of the main pages are set up properly,
360
+		// if not create the default pages and display an admin notice
361
+		EEH_Activation::verify_default_pages_exist();
362
+		$this->_transient_garbage_collection();
363
+
364
+		$this->_template_args['values'] = $this->_yes_no_values;
365
+
366
+		$this->_template_args['reg_page_id']  = $this->core_config->reg_page_id ?? null;
367
+		$this->_template_args['reg_page_obj'] = isset($this->core_config->reg_page_id)
368
+			? get_post($this->core_config->reg_page_id)
369
+			: false;
370
+
371
+		$this->_template_args['txn_page_id']  = $this->core_config->txn_page_id ?? null;
372
+		$this->_template_args['txn_page_obj'] = isset($this->core_config->txn_page_id)
373
+			? get_post($this->core_config->txn_page_id)
374
+			: false;
375
+
376
+		$this->_template_args['thank_you_page_id']  = $this->core_config->thank_you_page_id ?? null;
377
+		$this->_template_args['thank_you_page_obj'] = isset($this->core_config->thank_you_page_id)
378
+			? get_post($this->core_config->thank_you_page_id)
379
+			: false;
380
+
381
+		$this->_template_args['cancel_page_id']  = $this->core_config->cancel_page_id ?? null;
382
+		$this->_template_args['cancel_page_obj'] = isset($this->core_config->cancel_page_id)
383
+			? get_post($this->core_config->cancel_page_id)
384
+			: false;
385
+
386
+		$this->_set_add_edit_form_tags('update_espresso_page_settings');
387
+		$this->_set_publish_post_box_vars();
388
+		$this->_template_args['admin_page_content'] = EEH_Template::display_template(
389
+			GEN_SET_TEMPLATE_PATH . 'espresso_page_settings.template.php',
390
+			$this->_template_args,
391
+			true
392
+		);
393
+		$this->display_admin_page_with_sidebar();
394
+	}
395
+
396
+
397
+	/**
398
+	 * Handler for updating espresso page settings.
399
+	 *
400
+	 * @throws EE_Error
401
+	 */
402
+	protected function _update_espresso_page_settings()
403
+	{
404
+		$this->core_config = EE_Registry::instance()->CFG->core;
405
+		// capture incoming request data && set page IDs
406
+		$this->core_config->reg_page_id       = $this->request->getRequestParam(
407
+			'reg_page_id',
408
+			$this->core_config->reg_page_id,
409
+			DataType::INT
410
+		);
411
+		$this->core_config->txn_page_id       = $this->request->getRequestParam(
412
+			'txn_page_id',
413
+			$this->core_config->txn_page_id,
414
+			DataType::INT
415
+		);
416
+		$this->core_config->thank_you_page_id = $this->request->getRequestParam(
417
+			'thank_you_page_id',
418
+			$this->core_config->thank_you_page_id,
419
+			DataType::INT
420
+		);
421
+		$this->core_config->cancel_page_id    = $this->request->getRequestParam(
422
+			'cancel_page_id',
423
+			$this->core_config->cancel_page_id,
424
+			DataType::INT
425
+		);
426
+
427
+		$this->core_config = apply_filters(
428
+			'FHEE__General_Settings_Admin_Page___update_espresso_page_settings__CFG_core',
429
+			$this->core_config,
430
+			$this->request->requestParams()
431
+		);
432
+
433
+		$what = esc_html__('Critical Pages & Shortcodes', 'event_espresso');
434
+		$this->_redirect_after_action(
435
+			$this->_update_espresso_configuration(
436
+				$what,
437
+				$this->core_config,
438
+				__FILE__,
439
+				__FUNCTION__,
440
+				__LINE__
441
+			),
442
+			$what,
443
+			'',
444
+			[
445
+				'action' => 'critical_pages',
446
+			],
447
+			true
448
+		);
449
+	}
450
+
451
+
452
+	/*************        Your Organization        *************/
453
+
454
+
455
+	/**
456
+	 * @throws DomainException
457
+	 * @throws EE_Error
458
+	 * @throws InvalidArgumentException
459
+	 * @throws InvalidDataTypeException
460
+	 * @throws InvalidInterfaceException
461
+	 */
462
+	protected function _your_organization_settings()
463
+	{
464
+		$this->_template_args['admin_page_content'] = '';
465
+		try {
466
+			/** @var OrganizationSettings $organization_settings_form */
467
+			$organization_settings_form = $this->loader->getShared(OrganizationSettings::class);
468
+
469
+			$this->_template_args['admin_page_content'] = EEH_HTML::div(
470
+				$organization_settings_form->display(),
471
+				'',
472
+				'padding'
473
+			);
474
+		} catch (Exception $e) {
475
+			EE_Error::add_error($e->getMessage(), __FILE__, __FUNCTION__, __LINE__);
476
+		}
477
+		$this->_set_add_edit_form_tags('update_your_organization_settings');
478
+		$this->_set_publish_post_box_vars();
479
+		$this->display_admin_page_with_sidebar();
480
+	}
481
+
482
+
483
+	/**
484
+	 * Handler for updating organization settings.
485
+	 *
486
+	 * @throws EE_Error
487
+	 */
488
+	protected function _update_your_organization_settings()
489
+	{
490
+		try {
491
+			/** @var OrganizationSettings $organization_settings_form */
492
+			$organization_settings_form = $this->loader->getShared(OrganizationSettings::class);
493
+
494
+			$success = $organization_settings_form->process($this->request->requestParams());
495
+
496
+			EE_Registry::instance()->CFG = apply_filters(
497
+				'FHEE__General_Settings_Admin_Page___update_your_organization_settings__CFG',
498
+				EE_Registry::instance()->CFG
499
+			);
500
+		} catch (Exception $e) {
501
+			EE_Error::add_error($e->getMessage(), __FILE__, __FUNCTION__, __LINE__);
502
+			$success = false;
503
+		}
504
+
505
+		if ($success) {
506
+			$success = $this->_update_espresso_configuration(
507
+				esc_html__('Your Organization Settings', 'event_espresso'),
508
+				EE_Registry::instance()->CFG,
509
+				__FILE__,
510
+				__FUNCTION__,
511
+				__LINE__
512
+			);
513
+		}
514
+
515
+		$this->_redirect_after_action($success, '', '', ['action' => 'default'], true);
516
+	}
517
+
518
+
519
+
520
+	/*************        Admin Options        *************/
521
+
522
+
523
+	/**
524
+	 * _admin_option_settings
525
+	 *
526
+	 * @throws EE_Error
527
+	 * @throws LogicException
528
+	 */
529
+	protected function _admin_option_settings()
530
+	{
531
+		$this->_template_args['admin_page_content'] = '';
532
+		try {
533
+			$admin_options_settings_form = new AdminOptionsSettings(EE_Registry::instance());
534
+			// still need this for the old school form in Extend_General_Settings_Admin_Page
535
+			$this->_template_args['values'] = $this->_yes_no_values;
536
+			// also need to account for the do_action that was in the old template
537
+			$admin_options_settings_form->setTemplateArgs($this->_template_args);
538
+			$this->_template_args['admin_page_content'] = EEH_HTML::div(
539
+				$admin_options_settings_form->display(),
540
+				'',
541
+				'padding'
542
+			);
543
+		} catch (Exception $e) {
544
+			EE_Error::add_error($e->getMessage(), __FILE__, __FUNCTION__, __LINE__);
545
+		}
546
+		$this->_set_add_edit_form_tags('update_admin_option_settings');
547
+		$this->_set_publish_post_box_vars();
548
+		$this->display_admin_page_with_sidebar();
549
+	}
550
+
551
+
552
+	/**
553
+	 * _update_admin_option_settings
554
+	 *
555
+	 * @throws EE_Error
556
+	 * @throws InvalidDataTypeException
557
+	 * @throws InvalidFormSubmissionException
558
+	 * @throws InvalidArgumentException
559
+	 * @throws LogicException
560
+	 */
561
+	protected function _update_admin_option_settings()
562
+	{
563
+		try {
564
+			$admin_options_settings_form = new AdminOptionsSettings(EE_Registry::instance());
565
+			$admin_options_settings_form->process(
566
+				$this->request->getRequestParam(
567
+					$admin_options_settings_form->slug(),
568
+					[],
569
+					DataType::STRING,
570
+					true
571
+				)
572
+			);
573
+			EE_Registry::instance()->CFG->admin = apply_filters(
574
+				'FHEE__General_Settings_Admin_Page___update_admin_option_settings__CFG_admin',
575
+				EE_Registry::instance()->CFG->admin
576
+			);
577
+		} catch (Exception $e) {
578
+			EE_Error::add_error($e->getMessage(), __FILE__, __FUNCTION__, __LINE__);
579
+		}
580
+		$this->_redirect_after_action(
581
+			apply_filters(
582
+				'FHEE__General_Settings_Admin_Page___update_admin_option_settings__success',
583
+				$this->_update_espresso_configuration(
584
+					esc_html__('Admin Options', 'event_espresso'),
585
+					EE_Registry::instance()->CFG->admin,
586
+					__FILE__,
587
+					__FUNCTION__,
588
+					__LINE__
589
+				)
590
+			),
591
+			esc_html__('Admin Options', 'event_espresso'),
592
+			'updated',
593
+			['action' => 'admin_option_settings']
594
+		);
595
+	}
596
+
597
+
598
+	/*************        Countries        *************/
599
+
600
+
601
+	/**
602
+	 * @param string|null $default
603
+	 * @return string
604
+	 */
605
+	protected function getCountryISO(?string $default = null): string
606
+	{
607
+		$default = $default ?? $this->getCountryIsoForSite();
608
+		$CNT_ISO = $this->request->getRequestParam('country', $default);
609
+		$CNT_ISO = $this->request->getRequestParam('CNT_ISO', $CNT_ISO);
610
+		return strtoupper($CNT_ISO);
611
+	}
612
+
613
+
614
+	/**
615
+	 * @return string
616
+	 */
617
+	protected function getCountryIsoForSite(): string
618
+	{
619
+		return ! empty(EE_Registry::instance()->CFG->organization->CNT_ISO)
620
+			? EE_Registry::instance()->CFG->organization->CNT_ISO
621
+			: 'US';
622
+	}
623
+
624
+
625
+	/**
626
+	 * @param string          $CNT_ISO
627
+	 * @param EE_Country|null $country
628
+	 * @return EE_Base_Class|EE_Country
629
+	 * @throws EE_Error
630
+	 * @throws InvalidArgumentException
631
+	 * @throws InvalidDataTypeException
632
+	 * @throws InvalidInterfaceException
633
+	 * @throws ReflectionException
634
+	 */
635
+	protected function verifyOrGetCountryFromIso(string $CNT_ISO, ?EE_Country $country = null)
636
+	{
637
+		/** @var EE_Country $country */
638
+		return $country instanceof EE_Country && $country->ID() === $CNT_ISO
639
+			? $country
640
+			: EEM_Country::instance()->get_one_by_ID($CNT_ISO);
641
+	}
642
+
643
+
644
+	/**
645
+	 * Output Country Settings view.
646
+	 *
647
+	 * @throws DomainException
648
+	 * @throws EE_Error
649
+	 * @throws InvalidArgumentException
650
+	 * @throws InvalidDataTypeException
651
+	 * @throws InvalidInterfaceException
652
+	 * @throws ReflectionException
653
+	 */
654
+	protected function _country_settings()
655
+	{
656
+		$CNT_ISO = $this->getCountryISO();
657
+
658
+		$this->_template_args['values']    = $this->_yes_no_values;
659
+		$this->_template_args['countries'] = new EE_Question_Form_Input(
660
+			EE_Question::new_instance(
661
+				[
662
+				  'QST_ID'           => 0,
663
+				  'QST_display_text' => esc_html__('Select Country', 'event_espresso'),
664
+				  'QST_system'       => 'admin-country',
665
+				]
666
+			),
667
+			EE_Answer::new_instance(
668
+				[
669
+					'ANS_ID'    => 0,
670
+					'ANS_value' => $CNT_ISO,
671
+				]
672
+			),
673
+			[
674
+				'input_id'       => 'country',
675
+				'input_name'     => 'country',
676
+				'input_prefix'   => '',
677
+				'append_qstn_id' => false,
678
+			]
679
+		);
680
+
681
+		$country = $this->verifyOrGetCountryFromIso($CNT_ISO);
682
+		add_filter('FHEE__EEH_Form_Fields__label_html', [$this, 'country_form_field_label_wrap'], 10);
683
+		add_filter('FHEE__EEH_Form_Fields__input_html', [$this, 'country_form_field_input__wrap'], 10);
684
+		$this->_template_args['country_details_settings'] = $this->display_country_settings(
685
+			$country->ID(),
686
+			$country
687
+		);
688
+		$this->_template_args['country_states_settings']  = $this->display_country_states(
689
+			$country->ID(),
690
+			$country
691
+		);
692
+		$this->_template_args['CNT_name_for_site']        = $country->name();
693
+
694
+		$this->_set_add_edit_form_tags('update_country_settings');
695
+		$this->_set_publish_post_box_vars();
696
+		$this->_template_args['admin_page_content'] = EEH_Template::display_template(
697
+			GEN_SET_TEMPLATE_PATH . 'countries_settings.template.php',
698
+			$this->_template_args,
699
+			true
700
+		);
701
+		$this->display_admin_page_with_no_sidebar();
702
+	}
703
+
704
+
705
+	/**
706
+	 * @param string          $CNT_ISO
707
+	 * @param EE_Country|null $country
708
+	 * @return string
709
+	 * @throws DomainException
710
+	 * @throws EE_Error
711
+	 * @throws InvalidArgumentException
712
+	 * @throws InvalidDataTypeException
713
+	 * @throws InvalidInterfaceException
714
+	 * @throws ReflectionException
715
+	 */
716
+	public function display_country_settings(string $CNT_ISO = '', ?EE_Country $country = null): string
717
+	{
718
+		$CNT_ISO          = $this->getCountryISO($CNT_ISO);
719
+		$CNT_ISO_for_site = $this->getCountryIsoForSite();
720
+
721
+		if (! $CNT_ISO) {
722
+			return '';
723
+		}
724
+
725
+		// for ajax
726
+		remove_all_filters('FHEE__EEH_Form_Fields__label_html');
727
+		remove_all_filters('FHEE__EEH_Form_Fields__input_html');
728
+		add_filter('FHEE__EEH_Form_Fields__label_html', [$this, 'country_form_field_label_wrap'], 10, 2);
729
+		add_filter('FHEE__EEH_Form_Fields__input_html', [$this, 'country_form_field_input__wrap'], 10, 2);
730
+		$country                                  = $this->verifyOrGetCountryFromIso($CNT_ISO, $country);
731
+		$CNT_cur_disabled                         = $CNT_ISO !== $CNT_ISO_for_site;
732
+		$this->_template_args['CNT_cur_disabled'] = $CNT_cur_disabled;
733
+
734
+		$country_input_types            = [
735
+			'CNT_active'      => [
736
+				'type'             => 'RADIO_BTN',
737
+				'input_name'       => "cntry[$CNT_ISO]",
738
+				'class'            => '',
739
+				'options'          => $this->_yes_no_values,
740
+				'use_desc_4_label' => true,
741
+			],
742
+			'CNT_ISO'         => [
743
+				'type'       => 'TEXT',
744
+				'input_name' => "cntry[$CNT_ISO]",
745
+				'class'      => 'ee-input-width--small',
746
+			],
747
+			'CNT_ISO3'        => [
748
+				'type'       => 'TEXT',
749
+				'input_name' => "cntry[$CNT_ISO]",
750
+				'class'      => 'ee-input-width--small',
751
+			],
752
+			// 'RGN_ID'          => [
753
+			//     'type'       => 'TEXT',
754
+			//     'input_name' => "cntry[$CNT_ISO]",
755
+			//     'class'      => 'ee-input-width--small',
756
+			// ],
757
+			'CNT_name'        => [
758
+				'type'       => 'TEXT',
759
+				'input_name' => "cntry[$CNT_ISO]",
760
+				'class'      => 'ee-input-width--big',
761
+			],
762
+			'CNT_cur_code'    => [
763
+				'type'       => 'TEXT',
764
+				'input_name' => "cntry[$CNT_ISO]",
765
+				'class'      => 'ee-input-width--small',
766
+				'disabled'   => $CNT_cur_disabled,
767
+			],
768
+			'CNT_cur_single'  => [
769
+				'type'       => 'TEXT',
770
+				'input_name' => "cntry[$CNT_ISO]",
771
+				'class'      => 'ee-input-width--reg',
772
+				'disabled'   => $CNT_cur_disabled,
773
+			],
774
+			'CNT_cur_plural'  => [
775
+				'type'       => 'TEXT',
776
+				'input_name' => "cntry[$CNT_ISO]",
777
+				'class'      => 'ee-input-width--reg',
778
+				'disabled'   => $CNT_cur_disabled,
779
+			],
780
+			'CNT_cur_sign'    => [
781
+				'type'         => 'TEXT',
782
+				'input_name'   => "cntry[$CNT_ISO]",
783
+				'class'        => 'ee-input-width--small',
784
+				'htmlentities' => false,
785
+				'disabled'     => $CNT_cur_disabled,
786
+			],
787
+			'CNT_cur_sign_b4' => [
788
+				'type'             => 'RADIO_BTN',
789
+				'input_name'       => "cntry[$CNT_ISO]",
790
+				'class'            => '',
791
+				'options'          => $this->_yes_no_values,
792
+				'use_desc_4_label' => true,
793
+				'disabled'         => $CNT_cur_disabled,
794
+			],
795
+			'CNT_cur_dec_plc' => [
796
+				'type'       => 'RADIO_BTN',
797
+				'input_name' => "cntry[$CNT_ISO]",
798
+				'class'      => '',
799
+				'options'    => [
800
+					['id' => 0, 'text' => ''],
801
+					['id' => 1, 'text' => ''],
802
+					['id' => 2, 'text' => ''],
803
+					['id' => 3, 'text' => ''],
804
+				],
805
+				'disabled'   => $CNT_cur_disabled,
806
+			],
807
+			'CNT_cur_dec_mrk' => [
808
+				'type'             => 'RADIO_BTN',
809
+				'input_name'       => "cntry[$CNT_ISO]",
810
+				'class'            => '',
811
+				'options'          => [
812
+					[
813
+						'id'   => ',',
814
+						'text' => esc_html__(', (comma)', 'event_espresso'),
815
+					],
816
+					['id' => '.', 'text' => esc_html__('. (decimal)', 'event_espresso')],
817
+				],
818
+				'use_desc_4_label' => true,
819
+				'disabled'         => $CNT_cur_disabled,
820
+			],
821
+			'CNT_cur_thsnds'  => [
822
+				'type'             => 'RADIO_BTN',
823
+				'input_name'       => "cntry[$CNT_ISO]",
824
+				'class'            => '',
825
+				'options'          => [
826
+					[
827
+						'id'   => ',',
828
+						'text' => esc_html__(', (comma)', 'event_espresso'),
829
+					],
830
+					[
831
+						'id'   => '.',
832
+						'text' => esc_html__('. (decimal)', 'event_espresso'),
833
+					],
834
+					[
835
+						'id'   => '&nbsp;',
836
+						'text' => esc_html__('(space)', 'event_espresso'),
837
+					],
838
+					[
839
+						'id'   => '_',
840
+						'text' => esc_html__('_ (underscore)', 'event_espresso'),
841
+					],
842
+					[
843
+						'id'   => "'",
844
+						'text' => esc_html__("' (apostrophe)", 'event_espresso'),
845
+					],
846
+					[
847
+						'id'   => "",
848
+						'text' => esc_html__(" (nothing)", 'event_espresso'),
849
+					],
850
+				],
851
+				'use_desc_4_label' => true,
852
+				'disabled'         => $CNT_cur_disabled,
853
+			],
854
+			'CNT_tel_code'    => [
855
+				'type'       => 'TEXT',
856
+				'input_name' => "cntry[$CNT_ISO]",
857
+				'class'      => 'ee-input-width--small',
858
+			],
859
+			'CNT_is_EU'       => [
860
+				'type'             => 'RADIO_BTN',
861
+				'input_name'       => "cntry[$CNT_ISO]",
862
+				'class'            => '',
863
+				'options'          => $this->_yes_no_values,
864
+				'use_desc_4_label' => true,
865
+			],
866
+		];
867
+		$this->_template_args['inputs'] = EE_Question_Form_Input::generate_question_form_inputs_for_object(
868
+			$country,
869
+			$country_input_types
870
+		);
871
+		$country_details_settings       = EEH_Template::display_template(
872
+			GEN_SET_TEMPLATE_PATH . 'country_details_settings.template.php',
873
+			$this->_template_args,
874
+			true
875
+		);
876
+
877
+		if (defined('DOING_AJAX')) {
878
+			$notices = EE_Error::get_notices(false, false, false);
879
+			echo wp_json_encode(
880
+				[
881
+					'return_data' => $country_details_settings,
882
+					'success'     => $notices['success'],
883
+					'errors'      => $notices['errors'],
884
+				]
885
+			);
886
+			die();
887
+		}
888
+		return $country_details_settings;
889
+	}
890
+
891
+
892
+	/**
893
+	 * @param string          $CNT_ISO
894
+	 * @param EE_Country|null $country
895
+	 * @return string
896
+	 * @throws DomainException
897
+	 * @throws EE_Error
898
+	 * @throws InvalidArgumentException
899
+	 * @throws InvalidDataTypeException
900
+	 * @throws InvalidInterfaceException
901
+	 * @throws ReflectionException
902
+	 */
903
+	public function display_country_states(string $CNT_ISO = '', ?EE_Country $country = null): string
904
+	{
905
+		$CNT_ISO = $this->getCountryISO($CNT_ISO);
906
+		if (! $CNT_ISO) {
907
+			return '';
908
+		}
909
+		// for ajax
910
+		remove_all_filters('FHEE__EEH_Form_Fields__label_html');
911
+		remove_all_filters('FHEE__EEH_Form_Fields__input_html');
912
+		add_filter('FHEE__EEH_Form_Fields__label_html', [$this, 'state_form_field_label_wrap'], 10, 2);
913
+		add_filter('FHEE__EEH_Form_Fields__input_html', [$this, 'state_form_field_input__wrap'], 10);
914
+		$states = EEM_State::instance()->get_all_states_for_these_countries([$CNT_ISO => $CNT_ISO]);
915
+		if (empty($states)) {
916
+			/** @var EventEspresso\core\services\address\CountrySubRegionDao $countrySubRegionDao */
917
+			$countrySubRegionDao = $this->loader->getShared(
918
+				'EventEspresso\core\services\address\CountrySubRegionDao'
919
+			);
920
+			if ($countrySubRegionDao instanceof EventEspresso\core\services\address\CountrySubRegionDao) {
921
+				$country = $this->verifyOrGetCountryFromIso($CNT_ISO, $country);
922
+				if ($countrySubRegionDao->saveCountrySubRegions($country)) {
923
+					$states = EEM_State::instance()->get_all_states_for_these_countries([$CNT_ISO => $CNT_ISO]);
924
+				}
925
+			}
926
+		}
927
+		foreach ($states as $STA_ID => $state) {
928
+			if ($state instanceof EE_State) {
929
+				$inputs = EE_Question_Form_Input::generate_question_form_inputs_for_object(
930
+					$state,
931
+					[
932
+						'STA_abbrev' => [
933
+							'type'             => 'TEXT',
934
+							'label'            => esc_html__('Code', 'event_espresso'),
935
+							'input_name'       => "states[$STA_ID]",
936
+							'class'            => 'ee-input-width--tiny',
937
+							'add_mobile_label' => true,
938
+						],
939
+						'STA_name'   => [
940
+							'type'             => 'TEXT',
941
+							'label'            => esc_html__('Name', 'event_espresso'),
942
+							'input_name'       => "states[$STA_ID]",
943
+							'class'            => 'ee-input-width--big',
944
+							'add_mobile_label' => true,
945
+						],
946
+						'STA_active' => [
947
+							'type'             => 'RADIO_BTN',
948
+							'label'            => esc_html__(
949
+								'State Appears in Dropdown Select Lists',
950
+								'event_espresso'
951
+							),
952
+							'input_name'       => "states[$STA_ID]",
953
+							'options'          => $this->_yes_no_values,
954
+							'use_desc_4_label' => true,
955
+							'add_mobile_label' => true,
956
+						],
957
+					]
958
+				);
959
+
960
+				$delete_state_url = EE_Admin_Page::add_query_args_and_nonce(
961
+					[
962
+						'action'     => 'delete_state',
963
+						'STA_ID'     => $STA_ID,
964
+						'CNT_ISO'    => $CNT_ISO,
965
+						'STA_abbrev' => $state->abbrev(),
966
+					],
967
+					GEN_SET_ADMIN_URL
968
+				);
969
+
970
+				$this->_template_args['states'][ $STA_ID ]['inputs']           = $inputs;
971
+				$this->_template_args['states'][ $STA_ID ]['delete_state_url'] = $delete_state_url;
972
+			}
973
+		}
974
+
975
+		$this->_template_args['add_new_state_nonce'] = wp_create_nonce('espresso_add_new_state');
976
+		$this->_template_args['delete_state_nonce'] = wp_create_nonce('espresso_delete_state');
977
+
978
+		$state_details_settings = EEH_Template::display_template(
979
+			GEN_SET_TEMPLATE_PATH . 'state_details_settings.template.php',
980
+			$this->_template_args,
981
+			true
982
+		);
983
+
984
+		if (defined('DOING_AJAX')) {
985
+			$notices = EE_Error::get_notices(false, false, false);
986
+			echo wp_json_encode(
987
+				[
988
+					'return_data' => $state_details_settings,
989
+					'success'     => $notices['success'],
990
+					'errors'      => $notices['errors'],
991
+				]
992
+			);
993
+			die();
994
+		}
995
+		return $state_details_settings;
996
+	}
997
+
998
+
999
+	/**
1000
+	 * @return void
1001
+	 * @throws EE_Error
1002
+	 * @throws InvalidArgumentException
1003
+	 * @throws InvalidDataTypeException
1004
+	 * @throws InvalidInterfaceException
1005
+	 * @throws ReflectionException
1006
+	 */
1007
+	public function add_new_state()
1008
+	{
1009
+		$this->_verify_nonce();
1010
+		// add_new_state_nonce
1011
+		if (! $this->capabilities->current_user_can('manage_options', __FUNCTION__)) {
1012
+			wp_die(esc_html__('You do not have the required privileges to perform this action', 'event_espresso'));
1013
+		}
1014
+
1015
+		$success = true;
1016
+		$CNT_ISO = $this->getCountryISO('');
1017
+		if (! $CNT_ISO) {
1018
+			EE_Error::add_error(
1019
+				esc_html__('No Country ISO code or an invalid Country ISO code was received.', 'event_espresso'),
1020
+				__FILE__,
1021
+				__FUNCTION__,
1022
+				__LINE__
1023
+			);
1024
+			$success = false;
1025
+		}
1026
+		$STA_abbrev = $this->request->getRequestParam('STA_abbrev');
1027
+		if (! $STA_abbrev) {
1028
+			EE_Error::add_error(
1029
+				esc_html__('No State ISO code or an invalid State ISO code was received.', 'event_espresso'),
1030
+				__FILE__,
1031
+				__FUNCTION__,
1032
+				__LINE__
1033
+			);
1034
+			$success = false;
1035
+		}
1036
+		$STA_name = $this->request->getRequestParam('STA_name');
1037
+		if (! $STA_name) {
1038
+			EE_Error::add_error(
1039
+				esc_html__('No State name or an invalid State name was received.', 'event_espresso'),
1040
+				__FILE__,
1041
+				__FUNCTION__,
1042
+				__LINE__
1043
+			);
1044
+			$success = false;
1045
+		}
1046
+
1047
+		if ($success) {
1048
+			$cols_n_values = [
1049
+				'CNT_ISO'    => $CNT_ISO,
1050
+				'STA_abbrev' => $STA_abbrev,
1051
+				'STA_name'   => $STA_name,
1052
+				'STA_active' => true,
1053
+			];
1054
+			$success       = EEM_State::instance()->insert($cols_n_values);
1055
+			EE_Error::add_success(esc_html__('The State was added successfully.', 'event_espresso'));
1056
+		}
1057
+
1058
+		if (defined('DOING_AJAX')) {
1059
+			$notices = EE_Error::get_notices(false, false, false);
1060
+			echo wp_json_encode(array_merge($notices, ['return_data' => $CNT_ISO]));
1061
+			die();
1062
+		}
1063
+		$this->_redirect_after_action(
1064
+			$success,
1065
+			esc_html__('State', 'event_espresso'),
1066
+			'added',
1067
+			['action' => 'country_settings']
1068
+		);
1069
+	}
1070
+
1071
+
1072
+	/**
1073
+	 * @return void
1074
+	 * @throws EE_Error
1075
+	 * @throws InvalidArgumentException
1076
+	 * @throws InvalidDataTypeException
1077
+	 * @throws InvalidInterfaceException
1078
+	 * @throws ReflectionException
1079
+	 */
1080
+	public function delete_state()
1081
+	{
1082
+		$this->_verify_nonce();
1083
+		if (! $this->capabilities->current_user_can('manage_options', __FUNCTION__)) {
1084
+			wp_die(esc_html__('You do not have the required privileges to perform this action', 'event_espresso'));
1085
+		}
1086
+
1087
+		$CNT_ISO    = $this->getCountryISO();
1088
+		$STA_ID     = $this->request->getRequestParam('STA_ID');
1089
+		$STA_abbrev = $this->request->getRequestParam('STA_abbrev');
1090
+
1091
+		if (! $STA_ID) {
1092
+			EE_Error::add_error(
1093
+				esc_html__('No State ID or an invalid State ID was received.', 'event_espresso'),
1094
+				__FILE__,
1095
+				__FUNCTION__,
1096
+				__LINE__
1097
+			);
1098
+			return;
1099
+		}
1100
+
1101
+		$success = EEM_State::instance()->delete_by_ID($STA_ID);
1102
+		if ($success !== false) {
1103
+			do_action(
1104
+				'AHEE__General_Settings_Admin_Page__delete_state__state_deleted',
1105
+				$CNT_ISO,
1106
+				$STA_ID,
1107
+				['STA_abbrev' => $STA_abbrev]
1108
+			);
1109
+			EE_Error::add_success(esc_html__('The State was deleted successfully.', 'event_espresso'));
1110
+		}
1111
+		if (defined('DOING_AJAX')) {
1112
+			$notices                = EE_Error::get_notices(false);
1113
+			$notices['return_data'] = true;
1114
+			echo wp_json_encode($notices);
1115
+			die();
1116
+		}
1117
+		$this->_redirect_after_action(
1118
+			$success,
1119
+			esc_html__('State', 'event_espresso'),
1120
+			'deleted',
1121
+			['action' => 'country_settings']
1122
+		);
1123
+	}
1124
+
1125
+
1126
+	/**
1127
+	 * @return void
1128
+	 * @throws EE_Error
1129
+	 * @throws InvalidArgumentException
1130
+	 * @throws InvalidDataTypeException
1131
+	 * @throws InvalidInterfaceException
1132
+	 * @throws ReflectionException
1133
+	 */
1134
+	protected function _update_country_settings()
1135
+	{
1136
+		$CNT_ISO = $this->getCountryISO();
1137
+		if (! $CNT_ISO) {
1138
+			EE_Error::add_error(
1139
+				esc_html__('No Country ISO code or an invalid Country ISO code was received.', 'event_espresso'),
1140
+				__FILE__,
1141
+				__FUNCTION__,
1142
+				__LINE__
1143
+			);
1144
+			return;
1145
+		}
1146
+
1147
+		$country = $this->verifyOrGetCountryFromIso($CNT_ISO);
1148
+
1149
+		$cols_n_values                    = [];
1150
+		$cols_n_values['CNT_ISO3']        = strtoupper(
1151
+			$this->request->getRequestParam(
1152
+				"cntry[$CNT_ISO][CNT_ISO3]",
1153
+				$country->ISO3()
1154
+			)
1155
+		);
1156
+		$cols_n_values['CNT_name']        = $this->request->getRequestParam(
1157
+			"cntry[$CNT_ISO][CNT_name]",
1158
+			$country->name()
1159
+		);
1160
+		$cols_n_values['CNT_cur_code']    = strtoupper(
1161
+			$this->request->getRequestParam(
1162
+				"cntry[$CNT_ISO][CNT_cur_code]",
1163
+				$country->currency_code()
1164
+			)
1165
+		);
1166
+		$cols_n_values['CNT_cur_single']  = $this->request->getRequestParam(
1167
+			"cntry[$CNT_ISO][CNT_cur_single]",
1168
+			$country->currency_name_single()
1169
+		);
1170
+		$cols_n_values['CNT_cur_plural']  = $this->request->getRequestParam(
1171
+			"cntry[$CNT_ISO][CNT_cur_plural]",
1172
+			$country->currency_name_plural()
1173
+		);
1174
+		$cols_n_values['CNT_cur_sign']    = $this->request->getRequestParam(
1175
+			"cntry[$CNT_ISO][CNT_cur_sign]",
1176
+			$country->currency_sign()
1177
+		);
1178
+		$cols_n_values['CNT_cur_sign_b4'] = $this->request->getRequestParam(
1179
+			"cntry[$CNT_ISO][CNT_cur_sign_b4]",
1180
+			$country->currency_sign_before(),
1181
+			DataType::BOOL
1182
+		);
1183
+		$cols_n_values['CNT_cur_dec_plc'] = $this->request->getRequestParam(
1184
+			"cntry[$CNT_ISO][CNT_cur_dec_plc]",
1185
+			$country->currency_decimal_places()
1186
+		);
1187
+		$cols_n_values['CNT_cur_dec_mrk'] = $this->request->getRequestParam(
1188
+			"cntry[$CNT_ISO][CNT_cur_dec_mrk]",
1189
+			$country->currency_decimal_mark()
1190
+		);
1191
+		$cols_n_values['CNT_cur_thsnds']  = $this->request->getRequestParam(
1192
+			"cntry[$CNT_ISO][CNT_cur_thsnds]",
1193
+			$country->currency_thousands_separator()
1194
+		);
1195
+		$cols_n_values['CNT_tel_code']    = $this->request->getRequestParam(
1196
+			"cntry[$CNT_ISO][CNT_tel_code]",
1197
+			$country->telephoneCode()
1198
+		);
1199
+		$cols_n_values['CNT_active']      = $this->request->getRequestParam(
1200
+			"cntry[$CNT_ISO][CNT_active]",
1201
+			$country->isActive(),
1202
+			DataType::BOOL
1203
+		);
1204
+		$cols_n_values['CNT_is_EU']      = $this->request->getRequestParam(
1205
+			"cntry[$CNT_ISO][CNT_is_EU]",
1206
+			$country->isEU(),
1207
+			DataType::BOOL
1208
+		);
1209
+
1210
+		// allow filtering of country data
1211
+		$cols_n_values = apply_filters(
1212
+			'FHEE__General_Settings_Admin_Page___update_country_settings__cols_n_values',
1213
+			$cols_n_values
1214
+		);
1215
+
1216
+		// where values
1217
+		$where_cols_n_values = [['CNT_ISO' => $CNT_ISO]];
1218
+		// run the update
1219
+		$success = EEM_Country::instance()->update($cols_n_values, $where_cols_n_values);
1220
+
1221
+		// allow filtering of states data
1222
+		$states = apply_filters(
1223
+			'FHEE__General_Settings_Admin_Page___update_country_settings__states',
1224
+			$this->request->getRequestParam('states', [], DataType::STRING, true)
1225
+		);
1226
+
1227
+		if (! empty($states) && $success !== false) {
1228
+			// loop thru state data ( looks like : states[75][STA_name] )
1229
+			foreach ($states as $STA_ID => $state) {
1230
+				$cols_n_values = [
1231
+					'CNT_ISO'    => $CNT_ISO,
1232
+					'STA_abbrev' => sanitize_text_field($state['STA_abbrev']),
1233
+					'STA_name'   => sanitize_text_field($state['STA_name']),
1234
+					'STA_active' => filter_var($state['STA_active'], FILTER_VALIDATE_BOOLEAN),
1235
+				];
1236
+				// where values
1237
+				$where_cols_n_values = [['STA_ID' => $STA_ID]];
1238
+				// run the update
1239
+				$success = EEM_State::instance()->update($cols_n_values, $where_cols_n_values);
1240
+				if ($success !== false) {
1241
+					do_action(
1242
+						'AHEE__General_Settings_Admin_Page__update_country_settings__state_saved',
1243
+						$CNT_ISO,
1244
+						$STA_ID,
1245
+						$cols_n_values
1246
+					);
1247
+				}
1248
+			}
1249
+		}
1250
+		// check if country being edited matches org option country, and if so, then  update EE_Config with new settings
1251
+		if (
1252
+			isset(EE_Registry::instance()->CFG->organization->CNT_ISO)
1253
+			&& $CNT_ISO == EE_Registry::instance()->CFG->organization->CNT_ISO
1254
+		) {
1255
+			EE_Registry::instance()->CFG->currency = new EE_Currency_Config($CNT_ISO);
1256
+			EE_Registry::instance()->CFG->update_espresso_config();
1257
+		}
1258
+
1259
+		if ($success !== false) {
1260
+			EE_Error::add_success(
1261
+				esc_html__('Country Settings updated successfully.', 'event_espresso')
1262
+			);
1263
+		}
1264
+		$this->_redirect_after_action(
1265
+			$success,
1266
+			'',
1267
+			'',
1268
+			['action' => 'country_settings', 'country' => $CNT_ISO],
1269
+			true
1270
+		);
1271
+	}
1272
+
1273
+
1274
+	/**
1275
+	 * form_form_field_label_wrap
1276
+	 *
1277
+	 * @param string $label
1278
+	 * @return string
1279
+	 */
1280
+	public function country_form_field_label_wrap(string $label): string
1281
+	{
1282
+		return '
1283 1283
 			<tr>
1284 1284
 				<th>
1285 1285
 					' . $label . '
1286 1286
 				</th>';
1287
-    }
1288
-
1289
-
1290
-    /**
1291
-     * form_form_field_input__wrap
1292
-     *
1293
-     * @param string $input
1294
-     * @return string
1295
-     */
1296
-    public function country_form_field_input__wrap(string $input): string
1297
-    {
1298
-        return '
1287
+	}
1288
+
1289
+
1290
+	/**
1291
+	 * form_form_field_input__wrap
1292
+	 *
1293
+	 * @param string $input
1294
+	 * @return string
1295
+	 */
1296
+	public function country_form_field_input__wrap(string $input): string
1297
+	{
1298
+		return '
1299 1299
 				<td class="general-settings-country-input-td">
1300 1300
 					' . $input . '
1301 1301
 				</td>
1302 1302
 			</tr>';
1303
-    }
1304
-
1305
-
1306
-    /**
1307
-     * form_form_field_label_wrap
1308
-     *
1309
-     * @param string $label
1310
-     * @param string $required_text
1311
-     * @return string
1312
-     */
1313
-    public function state_form_field_label_wrap(string $label, string $required_text): string
1314
-    {
1315
-        return $required_text;
1316
-    }
1317
-
1318
-
1319
-    /**
1320
-     * form_form_field_input__wrap
1321
-     *
1322
-     * @param string $input
1323
-     * @return string
1324
-     */
1325
-    public function state_form_field_input__wrap(string $input): string
1326
-    {
1327
-        return '
1303
+	}
1304
+
1305
+
1306
+	/**
1307
+	 * form_form_field_label_wrap
1308
+	 *
1309
+	 * @param string $label
1310
+	 * @param string $required_text
1311
+	 * @return string
1312
+	 */
1313
+	public function state_form_field_label_wrap(string $label, string $required_text): string
1314
+	{
1315
+		return $required_text;
1316
+	}
1317
+
1318
+
1319
+	/**
1320
+	 * form_form_field_input__wrap
1321
+	 *
1322
+	 * @param string $input
1323
+	 * @return string
1324
+	 */
1325
+	public function state_form_field_input__wrap(string $input): string
1326
+	{
1327
+		return '
1328 1328
 				<td class="general-settings-country-state-input-td">
1329 1329
 					' . $input . '
1330 1330
 				</td>';
1331
-    }
1332
-
1333
-
1334
-    /***********/
1335
-
1336
-
1337
-    /**
1338
-     * displays edit and view links for critical EE pages
1339
-     *
1340
-     * @param int $ee_page_id
1341
-     * @return string
1342
-     */
1343
-    public static function edit_view_links(int $ee_page_id): string
1344
-    {
1345
-        $edit_url = add_query_arg(
1346
-            ['post' => $ee_page_id, 'action' => 'edit'],
1347
-            admin_url('post.php')
1348
-        );
1349
-        $links    = '<a href="' . esc_url_raw($edit_url) . '" >' . esc_html__('Edit', 'event_espresso') . '</a>';
1350
-        $links    .= ' &nbsp;|&nbsp; ';
1351
-        $links    .= '<a href="' . get_permalink($ee_page_id) . '" >' . esc_html__('View', 'event_espresso') . '</a>';
1352
-
1353
-        return $links;
1354
-    }
1355
-
1356
-
1357
-    /**
1358
-     * displays page and shortcode status for critical EE pages
1359
-     *
1360
-     * @param WP_Post $ee_page
1361
-     * @param string  $shortcode
1362
-     * @return string
1363
-     */
1364
-    public static function page_and_shortcode_status(WP_Post $ee_page, string $shortcode): string
1365
-    {
1366
-        // page status
1367
-        if (isset($ee_page->post_status) && $ee_page->post_status == 'publish') {
1368
-            $pg_class  = 'ee-status-bg--success';
1369
-            $pg_status = sprintf(esc_html__('Page%sStatus%sOK', 'event_espresso'), '&nbsp;', '&nbsp;');
1370
-        } else {
1371
-            $pg_class  = 'ee-status-bg--error';
1372
-            $pg_status = sprintf(esc_html__('Page%sVisibility%sProblem', 'event_espresso'), '&nbsp;', '&nbsp;');
1373
-        }
1374
-
1375
-        // shortcode status
1376
-        if (isset($ee_page->post_content) && strpos($ee_page->post_content, $shortcode) !== false) {
1377
-            $sc_class  = 'ee-status-bg--success';
1378
-            $sc_status = sprintf(esc_html__('Shortcode%sOK', 'event_espresso'), '&nbsp;');
1379
-        } else {
1380
-            $sc_class  = 'ee-status-bg--error';
1381
-            $sc_status = sprintf(esc_html__('Shortcode%sProblem', 'event_espresso'), '&nbsp;');
1382
-        }
1383
-
1384
-        return '
1331
+	}
1332
+
1333
+
1334
+	/***********/
1335
+
1336
+
1337
+	/**
1338
+	 * displays edit and view links for critical EE pages
1339
+	 *
1340
+	 * @param int $ee_page_id
1341
+	 * @return string
1342
+	 */
1343
+	public static function edit_view_links(int $ee_page_id): string
1344
+	{
1345
+		$edit_url = add_query_arg(
1346
+			['post' => $ee_page_id, 'action' => 'edit'],
1347
+			admin_url('post.php')
1348
+		);
1349
+		$links    = '<a href="' . esc_url_raw($edit_url) . '" >' . esc_html__('Edit', 'event_espresso') . '</a>';
1350
+		$links    .= ' &nbsp;|&nbsp; ';
1351
+		$links    .= '<a href="' . get_permalink($ee_page_id) . '" >' . esc_html__('View', 'event_espresso') . '</a>';
1352
+
1353
+		return $links;
1354
+	}
1355
+
1356
+
1357
+	/**
1358
+	 * displays page and shortcode status for critical EE pages
1359
+	 *
1360
+	 * @param WP_Post $ee_page
1361
+	 * @param string  $shortcode
1362
+	 * @return string
1363
+	 */
1364
+	public static function page_and_shortcode_status(WP_Post $ee_page, string $shortcode): string
1365
+	{
1366
+		// page status
1367
+		if (isset($ee_page->post_status) && $ee_page->post_status == 'publish') {
1368
+			$pg_class  = 'ee-status-bg--success';
1369
+			$pg_status = sprintf(esc_html__('Page%sStatus%sOK', 'event_espresso'), '&nbsp;', '&nbsp;');
1370
+		} else {
1371
+			$pg_class  = 'ee-status-bg--error';
1372
+			$pg_status = sprintf(esc_html__('Page%sVisibility%sProblem', 'event_espresso'), '&nbsp;', '&nbsp;');
1373
+		}
1374
+
1375
+		// shortcode status
1376
+		if (isset($ee_page->post_content) && strpos($ee_page->post_content, $shortcode) !== false) {
1377
+			$sc_class  = 'ee-status-bg--success';
1378
+			$sc_status = sprintf(esc_html__('Shortcode%sOK', 'event_espresso'), '&nbsp;');
1379
+		} else {
1380
+			$sc_class  = 'ee-status-bg--error';
1381
+			$sc_status = sprintf(esc_html__('Shortcode%sProblem', 'event_espresso'), '&nbsp;');
1382
+		}
1383
+
1384
+		return '
1385 1385
         <span class="ee-page-status ' . $pg_class . '"><strong>' . $pg_status . '</strong></span>
1386 1386
         <span class="ee-page-status ' . $sc_class . '"><strong>' . $sc_status . '</strong></span>';
1387
-    }
1388
-
1389
-
1390
-    /**
1391
-     * generates a dropdown of all parent pages - copied from WP core
1392
-     *
1393
-     * @param int  $default
1394
-     * @param int  $parent
1395
-     * @param int  $level
1396
-     * @param bool $echo
1397
-     * @return string;
1398
-     */
1399
-    public static function page_settings_dropdown(
1400
-        int $default = 0,
1401
-        int $parent = 0,
1402
-        int $level = 0,
1403
-        bool $echo = true
1404
-    ): string {
1405
-        global $wpdb;
1406
-        $items  = $wpdb->get_results(
1407
-            $wpdb->prepare(
1408
-                "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",
1409
-                $parent
1410
-            )
1411
-        );
1412
-        $output = '';
1413
-
1414
-        if ($items) {
1415
-            $level = absint($level);
1416
-            foreach ($items as $item) {
1417
-                $ID         = absint($item->ID);
1418
-                $post_title = wp_strip_all_tags($item->post_title);
1419
-                $pad        = str_repeat('&nbsp;', $level * 3);
1420
-                $option     = "\n\t";
1421
-                $option     .= '<option class="level-' . $level . '" ';
1422
-                $option     .= 'value="' . $ID . '" ';
1423
-                $option     .= $ID === absint($default) ? ' selected' : '';
1424
-                $option     .= '>';
1425
-                $option     .= "$pad {$post_title}";
1426
-                $option     .= '</option>';
1427
-                $output     .= $option;
1428
-                ob_start();
1429
-                parent_dropdown($default, $item->ID, $level + 1);
1430
-                $output .= ob_get_clean();
1431
-            }
1432
-        }
1433
-        if ($echo) {
1434
-            echo wp_kses($output, AllowedTags::getWithFormTags());
1435
-            return '';
1436
-        }
1437
-        return $output;
1438
-    }
1439
-
1440
-
1441
-    /**
1442
-     * Loads the scripts for the privacy settings form
1443
-     */
1444
-    public function load_scripts_styles_privacy_settings()
1445
-    {
1446
-        $form_handler = $this->loader->getShared(
1447
-            'EventEspresso\core\domain\services\admin\privacy\forms\PrivacySettingsFormHandler'
1448
-        );
1449
-        $form_handler->enqueueStylesAndScripts();
1450
-    }
1451
-
1452
-
1453
-    /**
1454
-     * display the privacy settings form
1455
-     *
1456
-     * @throws EE_Error
1457
-     */
1458
-    public function privacySettings()
1459
-    {
1460
-        $this->_set_add_edit_form_tags('update_privacy_settings');
1461
-        $this->_set_publish_post_box_vars();
1462
-        $form_handler                               = $this->loader->getShared(
1463
-            'EventEspresso\core\domain\services\admin\privacy\forms\PrivacySettingsFormHandler'
1464
-        );
1465
-        $this->_template_args['admin_page_content'] = EEH_HTML::div(
1466
-            $form_handler->display(),
1467
-            '',
1468
-            'padding'
1469
-        );
1470
-        $this->display_admin_page_with_sidebar();
1471
-    }
1472
-
1473
-
1474
-    /**
1475
-     * Update the privacy settings from form data
1476
-     *
1477
-     * @throws EE_Error
1478
-     */
1479
-    public function updatePrivacySettings()
1480
-    {
1481
-        $form_handler = $this->loader->getShared(
1482
-            'EventEspresso\core\domain\services\admin\privacy\forms\PrivacySettingsFormHandler'
1483
-        );
1484
-        $success      = $form_handler->process($this->get_request_data());
1485
-        $this->_redirect_after_action(
1486
-            $success,
1487
-            esc_html__('Registration Form Options', 'event_espresso'),
1488
-            'updated',
1489
-            ['action' => 'privacy_settings']
1490
-        );
1491
-    }
1492
-
1493
-
1494
-    public function setFontSize()
1495
-    {
1496
-        AdminFontSize::setAdminFontSize(
1497
-            $this->request->getRequestParam('font_size', AdminFontSize::FONT_SIZE_DEFAULT)
1498
-        );
1499
-        wp_safe_redirect($this->request->getServerParam('HTTP_REFERER'));
1500
-    }
1387
+	}
1388
+
1389
+
1390
+	/**
1391
+	 * generates a dropdown of all parent pages - copied from WP core
1392
+	 *
1393
+	 * @param int  $default
1394
+	 * @param int  $parent
1395
+	 * @param int  $level
1396
+	 * @param bool $echo
1397
+	 * @return string;
1398
+	 */
1399
+	public static function page_settings_dropdown(
1400
+		int $default = 0,
1401
+		int $parent = 0,
1402
+		int $level = 0,
1403
+		bool $echo = true
1404
+	): string {
1405
+		global $wpdb;
1406
+		$items  = $wpdb->get_results(
1407
+			$wpdb->prepare(
1408
+				"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",
1409
+				$parent
1410
+			)
1411
+		);
1412
+		$output = '';
1413
+
1414
+		if ($items) {
1415
+			$level = absint($level);
1416
+			foreach ($items as $item) {
1417
+				$ID         = absint($item->ID);
1418
+				$post_title = wp_strip_all_tags($item->post_title);
1419
+				$pad        = str_repeat('&nbsp;', $level * 3);
1420
+				$option     = "\n\t";
1421
+				$option     .= '<option class="level-' . $level . '" ';
1422
+				$option     .= 'value="' . $ID . '" ';
1423
+				$option     .= $ID === absint($default) ? ' selected' : '';
1424
+				$option     .= '>';
1425
+				$option     .= "$pad {$post_title}";
1426
+				$option     .= '</option>';
1427
+				$output     .= $option;
1428
+				ob_start();
1429
+				parent_dropdown($default, $item->ID, $level + 1);
1430
+				$output .= ob_get_clean();
1431
+			}
1432
+		}
1433
+		if ($echo) {
1434
+			echo wp_kses($output, AllowedTags::getWithFormTags());
1435
+			return '';
1436
+		}
1437
+		return $output;
1438
+	}
1439
+
1440
+
1441
+	/**
1442
+	 * Loads the scripts for the privacy settings form
1443
+	 */
1444
+	public function load_scripts_styles_privacy_settings()
1445
+	{
1446
+		$form_handler = $this->loader->getShared(
1447
+			'EventEspresso\core\domain\services\admin\privacy\forms\PrivacySettingsFormHandler'
1448
+		);
1449
+		$form_handler->enqueueStylesAndScripts();
1450
+	}
1451
+
1452
+
1453
+	/**
1454
+	 * display the privacy settings form
1455
+	 *
1456
+	 * @throws EE_Error
1457
+	 */
1458
+	public function privacySettings()
1459
+	{
1460
+		$this->_set_add_edit_form_tags('update_privacy_settings');
1461
+		$this->_set_publish_post_box_vars();
1462
+		$form_handler                               = $this->loader->getShared(
1463
+			'EventEspresso\core\domain\services\admin\privacy\forms\PrivacySettingsFormHandler'
1464
+		);
1465
+		$this->_template_args['admin_page_content'] = EEH_HTML::div(
1466
+			$form_handler->display(),
1467
+			'',
1468
+			'padding'
1469
+		);
1470
+		$this->display_admin_page_with_sidebar();
1471
+	}
1472
+
1473
+
1474
+	/**
1475
+	 * Update the privacy settings from form data
1476
+	 *
1477
+	 * @throws EE_Error
1478
+	 */
1479
+	public function updatePrivacySettings()
1480
+	{
1481
+		$form_handler = $this->loader->getShared(
1482
+			'EventEspresso\core\domain\services\admin\privacy\forms\PrivacySettingsFormHandler'
1483
+		);
1484
+		$success      = $form_handler->process($this->get_request_data());
1485
+		$this->_redirect_after_action(
1486
+			$success,
1487
+			esc_html__('Registration Form Options', 'event_espresso'),
1488
+			'updated',
1489
+			['action' => 'privacy_settings']
1490
+		);
1491
+	}
1492
+
1493
+
1494
+	public function setFontSize()
1495
+	{
1496
+		AdminFontSize::setAdminFontSize(
1497
+			$this->request->getRequestParam('font_size', AdminFontSize::FONT_SIZE_DEFAULT)
1498
+		);
1499
+		wp_safe_redirect($this->request->getServerParam('HTTP_REFERER'));
1500
+	}
1501 1501
 }
Please login to merge, or discard this patch.
Spacing   +50 added lines, -50 removed lines patch added patch discarded remove patch
@@ -264,19 +264,19 @@  discard block
 block discarded – undo
264 264
                 'event_espresso'
265 265
             )
266 266
         );
267
-        EE_Registry::$i18n_js_strings['error_occurred']          = wp_strip_all_tags(
267
+        EE_Registry::$i18n_js_strings['error_occurred'] = wp_strip_all_tags(
268 268
             esc_html__(
269 269
                 'An error occurred! Please refresh the page and try again.',
270 270
                 'event_espresso'
271 271
             )
272 272
         );
273
-        EE_Registry::$i18n_js_strings['confirm_delete_state']    = wp_strip_all_tags(
273
+        EE_Registry::$i18n_js_strings['confirm_delete_state'] = wp_strip_all_tags(
274 274
             esc_html__(
275 275
                 'Are you sure you want to delete this State / Province?',
276 276
                 'event_espresso'
277 277
             )
278 278
         );
279
-        EE_Registry::$i18n_js_strings['ajax_url']                = admin_url(
279
+        EE_Registry::$i18n_js_strings['ajax_url'] = admin_url(
280 280
             'admin-ajax.php?page=espresso_general_settings',
281 281
             is_ssl() ? 'https://' : 'http://'
282 282
         );
@@ -305,12 +305,12 @@  discard block
 block discarded – undo
305 305
         wp_enqueue_script('thickbox');
306 306
         wp_register_script(
307 307
             'organization_settings',
308
-            GEN_SET_ASSETS_URL . 'your_organization_settings.js',
308
+            GEN_SET_ASSETS_URL.'your_organization_settings.js',
309 309
             ['jquery', 'media-upload', 'thickbox'],
310 310
             EVENT_ESPRESSO_VERSION,
311 311
             true
312 312
         );
313
-        wp_register_style('organization-css', GEN_SET_ASSETS_URL . 'organization.css', [], EVENT_ESPRESSO_VERSION);
313
+        wp_register_style('organization-css', GEN_SET_ASSETS_URL.'organization.css', [], EVENT_ESPRESSO_VERSION);
314 314
         wp_enqueue_script('organization_settings');
315 315
         wp_enqueue_style('organization-css');
316 316
         $confirm_image_delete = [
@@ -333,12 +333,12 @@  discard block
 block discarded – undo
333 333
         // scripts
334 334
         wp_register_script(
335 335
             'gen_settings_countries',
336
-            GEN_SET_ASSETS_URL . 'gen_settings_countries.js',
336
+            GEN_SET_ASSETS_URL.'gen_settings_countries.js',
337 337
             ['ee_admin_js'],
338 338
             EVENT_ESPRESSO_VERSION,
339 339
             true
340 340
         );
341
-        wp_register_style('organization-css', GEN_SET_ASSETS_URL . 'organization.css', [], EVENT_ESPRESSO_VERSION);
341
+        wp_register_style('organization-css', GEN_SET_ASSETS_URL.'organization.css', [], EVENT_ESPRESSO_VERSION);
342 342
         wp_enqueue_script('gen_settings_countries');
343 343
         wp_enqueue_style('organization-css');
344 344
     }
@@ -386,7 +386,7 @@  discard block
 block discarded – undo
386 386
         $this->_set_add_edit_form_tags('update_espresso_page_settings');
387 387
         $this->_set_publish_post_box_vars();
388 388
         $this->_template_args['admin_page_content'] = EEH_Template::display_template(
389
-            GEN_SET_TEMPLATE_PATH . 'espresso_page_settings.template.php',
389
+            GEN_SET_TEMPLATE_PATH.'espresso_page_settings.template.php',
390 390
             $this->_template_args,
391 391
             true
392 392
         );
@@ -403,12 +403,12 @@  discard block
 block discarded – undo
403 403
     {
404 404
         $this->core_config = EE_Registry::instance()->CFG->core;
405 405
         // capture incoming request data && set page IDs
406
-        $this->core_config->reg_page_id       = $this->request->getRequestParam(
406
+        $this->core_config->reg_page_id = $this->request->getRequestParam(
407 407
             'reg_page_id',
408 408
             $this->core_config->reg_page_id,
409 409
             DataType::INT
410 410
         );
411
-        $this->core_config->txn_page_id       = $this->request->getRequestParam(
411
+        $this->core_config->txn_page_id = $this->request->getRequestParam(
412 412
             'txn_page_id',
413 413
             $this->core_config->txn_page_id,
414 414
             DataType::INT
@@ -418,7 +418,7 @@  discard block
 block discarded – undo
418 418
             $this->core_config->thank_you_page_id,
419 419
             DataType::INT
420 420
         );
421
-        $this->core_config->cancel_page_id    = $this->request->getRequestParam(
421
+        $this->core_config->cancel_page_id = $this->request->getRequestParam(
422 422
             'cancel_page_id',
423 423
             $this->core_config->cancel_page_id,
424 424
             DataType::INT
@@ -685,16 +685,16 @@  discard block
 block discarded – undo
685 685
             $country->ID(),
686 686
             $country
687 687
         );
688
-        $this->_template_args['country_states_settings']  = $this->display_country_states(
688
+        $this->_template_args['country_states_settings'] = $this->display_country_states(
689 689
             $country->ID(),
690 690
             $country
691 691
         );
692
-        $this->_template_args['CNT_name_for_site']        = $country->name();
692
+        $this->_template_args['CNT_name_for_site'] = $country->name();
693 693
 
694 694
         $this->_set_add_edit_form_tags('update_country_settings');
695 695
         $this->_set_publish_post_box_vars();
696 696
         $this->_template_args['admin_page_content'] = EEH_Template::display_template(
697
-            GEN_SET_TEMPLATE_PATH . 'countries_settings.template.php',
697
+            GEN_SET_TEMPLATE_PATH.'countries_settings.template.php',
698 698
             $this->_template_args,
699 699
             true
700 700
         );
@@ -718,7 +718,7 @@  discard block
 block discarded – undo
718 718
         $CNT_ISO          = $this->getCountryISO($CNT_ISO);
719 719
         $CNT_ISO_for_site = $this->getCountryIsoForSite();
720 720
 
721
-        if (! $CNT_ISO) {
721
+        if ( ! $CNT_ISO) {
722 722
             return '';
723 723
         }
724 724
 
@@ -731,7 +731,7 @@  discard block
 block discarded – undo
731 731
         $CNT_cur_disabled                         = $CNT_ISO !== $CNT_ISO_for_site;
732 732
         $this->_template_args['CNT_cur_disabled'] = $CNT_cur_disabled;
733 733
 
734
-        $country_input_types            = [
734
+        $country_input_types = [
735 735
             'CNT_active'      => [
736 736
                 'type'             => 'RADIO_BTN',
737 737
                 'input_name'       => "cntry[$CNT_ISO]",
@@ -868,8 +868,8 @@  discard block
 block discarded – undo
868 868
             $country,
869 869
             $country_input_types
870 870
         );
871
-        $country_details_settings       = EEH_Template::display_template(
872
-            GEN_SET_TEMPLATE_PATH . 'country_details_settings.template.php',
871
+        $country_details_settings = EEH_Template::display_template(
872
+            GEN_SET_TEMPLATE_PATH.'country_details_settings.template.php',
873 873
             $this->_template_args,
874 874
             true
875 875
         );
@@ -903,7 +903,7 @@  discard block
 block discarded – undo
903 903
     public function display_country_states(string $CNT_ISO = '', ?EE_Country $country = null): string
904 904
     {
905 905
         $CNT_ISO = $this->getCountryISO($CNT_ISO);
906
-        if (! $CNT_ISO) {
906
+        if ( ! $CNT_ISO) {
907 907
             return '';
908 908
         }
909 909
         // for ajax
@@ -967,8 +967,8 @@  discard block
 block discarded – undo
967 967
                     GEN_SET_ADMIN_URL
968 968
                 );
969 969
 
970
-                $this->_template_args['states'][ $STA_ID ]['inputs']           = $inputs;
971
-                $this->_template_args['states'][ $STA_ID ]['delete_state_url'] = $delete_state_url;
970
+                $this->_template_args['states'][$STA_ID]['inputs']           = $inputs;
971
+                $this->_template_args['states'][$STA_ID]['delete_state_url'] = $delete_state_url;
972 972
             }
973 973
         }
974 974
 
@@ -976,7 +976,7 @@  discard block
 block discarded – undo
976 976
         $this->_template_args['delete_state_nonce'] = wp_create_nonce('espresso_delete_state');
977 977
 
978 978
         $state_details_settings = EEH_Template::display_template(
979
-            GEN_SET_TEMPLATE_PATH . 'state_details_settings.template.php',
979
+            GEN_SET_TEMPLATE_PATH.'state_details_settings.template.php',
980 980
             $this->_template_args,
981 981
             true
982 982
         );
@@ -1008,13 +1008,13 @@  discard block
 block discarded – undo
1008 1008
     {
1009 1009
         $this->_verify_nonce();
1010 1010
         // add_new_state_nonce
1011
-        if (! $this->capabilities->current_user_can('manage_options', __FUNCTION__)) {
1011
+        if ( ! $this->capabilities->current_user_can('manage_options', __FUNCTION__)) {
1012 1012
             wp_die(esc_html__('You do not have the required privileges to perform this action', 'event_espresso'));
1013 1013
         }
1014 1014
 
1015 1015
         $success = true;
1016 1016
         $CNT_ISO = $this->getCountryISO('');
1017
-        if (! $CNT_ISO) {
1017
+        if ( ! $CNT_ISO) {
1018 1018
             EE_Error::add_error(
1019 1019
                 esc_html__('No Country ISO code or an invalid Country ISO code was received.', 'event_espresso'),
1020 1020
                 __FILE__,
@@ -1024,7 +1024,7 @@  discard block
 block discarded – undo
1024 1024
             $success = false;
1025 1025
         }
1026 1026
         $STA_abbrev = $this->request->getRequestParam('STA_abbrev');
1027
-        if (! $STA_abbrev) {
1027
+        if ( ! $STA_abbrev) {
1028 1028
             EE_Error::add_error(
1029 1029
                 esc_html__('No State ISO code or an invalid State ISO code was received.', 'event_espresso'),
1030 1030
                 __FILE__,
@@ -1034,7 +1034,7 @@  discard block
 block discarded – undo
1034 1034
             $success = false;
1035 1035
         }
1036 1036
         $STA_name = $this->request->getRequestParam('STA_name');
1037
-        if (! $STA_name) {
1037
+        if ( ! $STA_name) {
1038 1038
             EE_Error::add_error(
1039 1039
                 esc_html__('No State name or an invalid State name was received.', 'event_espresso'),
1040 1040
                 __FILE__,
@@ -1051,7 +1051,7 @@  discard block
 block discarded – undo
1051 1051
                 'STA_name'   => $STA_name,
1052 1052
                 'STA_active' => true,
1053 1053
             ];
1054
-            $success       = EEM_State::instance()->insert($cols_n_values);
1054
+            $success = EEM_State::instance()->insert($cols_n_values);
1055 1055
             EE_Error::add_success(esc_html__('The State was added successfully.', 'event_espresso'));
1056 1056
         }
1057 1057
 
@@ -1080,7 +1080,7 @@  discard block
 block discarded – undo
1080 1080
     public function delete_state()
1081 1081
     {
1082 1082
         $this->_verify_nonce();
1083
-        if (! $this->capabilities->current_user_can('manage_options', __FUNCTION__)) {
1083
+        if ( ! $this->capabilities->current_user_can('manage_options', __FUNCTION__)) {
1084 1084
             wp_die(esc_html__('You do not have the required privileges to perform this action', 'event_espresso'));
1085 1085
         }
1086 1086
 
@@ -1088,7 +1088,7 @@  discard block
 block discarded – undo
1088 1088
         $STA_ID     = $this->request->getRequestParam('STA_ID');
1089 1089
         $STA_abbrev = $this->request->getRequestParam('STA_abbrev');
1090 1090
 
1091
-        if (! $STA_ID) {
1091
+        if ( ! $STA_ID) {
1092 1092
             EE_Error::add_error(
1093 1093
                 esc_html__('No State ID or an invalid State ID was received.', 'event_espresso'),
1094 1094
                 __FILE__,
@@ -1134,7 +1134,7 @@  discard block
 block discarded – undo
1134 1134
     protected function _update_country_settings()
1135 1135
     {
1136 1136
         $CNT_ISO = $this->getCountryISO();
1137
-        if (! $CNT_ISO) {
1137
+        if ( ! $CNT_ISO) {
1138 1138
             EE_Error::add_error(
1139 1139
                 esc_html__('No Country ISO code or an invalid Country ISO code was received.', 'event_espresso'),
1140 1140
                 __FILE__,
@@ -1153,25 +1153,25 @@  discard block
 block discarded – undo
1153 1153
                 $country->ISO3()
1154 1154
             )
1155 1155
         );
1156
-        $cols_n_values['CNT_name']        = $this->request->getRequestParam(
1156
+        $cols_n_values['CNT_name'] = $this->request->getRequestParam(
1157 1157
             "cntry[$CNT_ISO][CNT_name]",
1158 1158
             $country->name()
1159 1159
         );
1160
-        $cols_n_values['CNT_cur_code']    = strtoupper(
1160
+        $cols_n_values['CNT_cur_code'] = strtoupper(
1161 1161
             $this->request->getRequestParam(
1162 1162
                 "cntry[$CNT_ISO][CNT_cur_code]",
1163 1163
                 $country->currency_code()
1164 1164
             )
1165 1165
         );
1166
-        $cols_n_values['CNT_cur_single']  = $this->request->getRequestParam(
1166
+        $cols_n_values['CNT_cur_single'] = $this->request->getRequestParam(
1167 1167
             "cntry[$CNT_ISO][CNT_cur_single]",
1168 1168
             $country->currency_name_single()
1169 1169
         );
1170
-        $cols_n_values['CNT_cur_plural']  = $this->request->getRequestParam(
1170
+        $cols_n_values['CNT_cur_plural'] = $this->request->getRequestParam(
1171 1171
             "cntry[$CNT_ISO][CNT_cur_plural]",
1172 1172
             $country->currency_name_plural()
1173 1173
         );
1174
-        $cols_n_values['CNT_cur_sign']    = $this->request->getRequestParam(
1174
+        $cols_n_values['CNT_cur_sign'] = $this->request->getRequestParam(
1175 1175
             "cntry[$CNT_ISO][CNT_cur_sign]",
1176 1176
             $country->currency_sign()
1177 1177
         );
@@ -1188,20 +1188,20 @@  discard block
 block discarded – undo
1188 1188
             "cntry[$CNT_ISO][CNT_cur_dec_mrk]",
1189 1189
             $country->currency_decimal_mark()
1190 1190
         );
1191
-        $cols_n_values['CNT_cur_thsnds']  = $this->request->getRequestParam(
1191
+        $cols_n_values['CNT_cur_thsnds'] = $this->request->getRequestParam(
1192 1192
             "cntry[$CNT_ISO][CNT_cur_thsnds]",
1193 1193
             $country->currency_thousands_separator()
1194 1194
         );
1195
-        $cols_n_values['CNT_tel_code']    = $this->request->getRequestParam(
1195
+        $cols_n_values['CNT_tel_code'] = $this->request->getRequestParam(
1196 1196
             "cntry[$CNT_ISO][CNT_tel_code]",
1197 1197
             $country->telephoneCode()
1198 1198
         );
1199
-        $cols_n_values['CNT_active']      = $this->request->getRequestParam(
1199
+        $cols_n_values['CNT_active'] = $this->request->getRequestParam(
1200 1200
             "cntry[$CNT_ISO][CNT_active]",
1201 1201
             $country->isActive(),
1202 1202
             DataType::BOOL
1203 1203
         );
1204
-        $cols_n_values['CNT_is_EU']      = $this->request->getRequestParam(
1204
+        $cols_n_values['CNT_is_EU'] = $this->request->getRequestParam(
1205 1205
             "cntry[$CNT_ISO][CNT_is_EU]",
1206 1206
             $country->isEU(),
1207 1207
             DataType::BOOL
@@ -1224,7 +1224,7 @@  discard block
 block discarded – undo
1224 1224
             $this->request->getRequestParam('states', [], DataType::STRING, true)
1225 1225
         );
1226 1226
 
1227
-        if (! empty($states) && $success !== false) {
1227
+        if ( ! empty($states) && $success !== false) {
1228 1228
             // loop thru state data ( looks like : states[75][STA_name] )
1229 1229
             foreach ($states as $STA_ID => $state) {
1230 1230
                 $cols_n_values = [
@@ -1282,7 +1282,7 @@  discard block
 block discarded – undo
1282 1282
         return '
1283 1283
 			<tr>
1284 1284
 				<th>
1285
-					' . $label . '
1285
+					' . $label.'
1286 1286
 				</th>';
1287 1287
     }
1288 1288
 
@@ -1297,7 +1297,7 @@  discard block
 block discarded – undo
1297 1297
     {
1298 1298
         return '
1299 1299
 				<td class="general-settings-country-input-td">
1300
-					' . $input . '
1300
+					' . $input.'
1301 1301
 				</td>
1302 1302
 			</tr>';
1303 1303
     }
@@ -1326,7 +1326,7 @@  discard block
 block discarded – undo
1326 1326
     {
1327 1327
         return '
1328 1328
 				<td class="general-settings-country-state-input-td">
1329
-					' . $input . '
1329
+					' . $input.'
1330 1330
 				</td>';
1331 1331
     }
1332 1332
 
@@ -1346,9 +1346,9 @@  discard block
 block discarded – undo
1346 1346
             ['post' => $ee_page_id, 'action' => 'edit'],
1347 1347
             admin_url('post.php')
1348 1348
         );
1349
-        $links    = '<a href="' . esc_url_raw($edit_url) . '" >' . esc_html__('Edit', 'event_espresso') . '</a>';
1349
+        $links = '<a href="'.esc_url_raw($edit_url).'" >'.esc_html__('Edit', 'event_espresso').'</a>';
1350 1350
         $links    .= ' &nbsp;|&nbsp; ';
1351
-        $links    .= '<a href="' . get_permalink($ee_page_id) . '" >' . esc_html__('View', 'event_espresso') . '</a>';
1351
+        $links    .= '<a href="'.get_permalink($ee_page_id).'" >'.esc_html__('View', 'event_espresso').'</a>';
1352 1352
 
1353 1353
         return $links;
1354 1354
     }
@@ -1382,8 +1382,8 @@  discard block
 block discarded – undo
1382 1382
         }
1383 1383
 
1384 1384
         return '
1385
-        <span class="ee-page-status ' . $pg_class . '"><strong>' . $pg_status . '</strong></span>
1386
-        <span class="ee-page-status ' . $sc_class . '"><strong>' . $sc_status . '</strong></span>';
1385
+        <span class="ee-page-status ' . $pg_class.'"><strong>'.$pg_status.'</strong></span>
1386
+        <span class="ee-page-status ' . $sc_class.'"><strong>'.$sc_status.'</strong></span>';
1387 1387
     }
1388 1388
 
1389 1389
 
@@ -1403,7 +1403,7 @@  discard block
 block discarded – undo
1403 1403
         bool $echo = true
1404 1404
     ): string {
1405 1405
         global $wpdb;
1406
-        $items  = $wpdb->get_results(
1406
+        $items = $wpdb->get_results(
1407 1407
             $wpdb->prepare(
1408 1408
                 "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",
1409 1409
                 $parent
@@ -1418,8 +1418,8 @@  discard block
 block discarded – undo
1418 1418
                 $post_title = wp_strip_all_tags($item->post_title);
1419 1419
                 $pad        = str_repeat('&nbsp;', $level * 3);
1420 1420
                 $option     = "\n\t";
1421
-                $option     .= '<option class="level-' . $level . '" ';
1422
-                $option     .= 'value="' . $ID . '" ';
1421
+                $option     .= '<option class="level-'.$level.'" ';
1422
+                $option     .= 'value="'.$ID.'" ';
1423 1423
                 $option     .= $ID === absint($default) ? ' selected' : '';
1424 1424
                 $option     .= '>';
1425 1425
                 $option     .= "$pad {$post_title}";
Please login to merge, or discard this patch.
admin/extend/registrations/Extend_Registrations_Admin_Page.core.php 1 patch
Indentation   +1278 added lines, -1278 removed lines patch added patch discarded remove patch
@@ -16,1289 +16,1289 @@
 block discarded – undo
16 16
  */
17 17
 class Extend_Registrations_Admin_Page extends Registrations_Admin_Page
18 18
 {
19
-    /**
20
-     * This is used to hold the reports template data which is setup early in the request.
21
-     *
22
-     * @type array
23
-     */
24
-    protected array $_reports_template_data = [];
25
-
26
-
27
-    /**
28
-     * Extend_Registrations_Admin_Page constructor.
29
-     *
30
-     * @param bool $routing
31
-     * @throws ReflectionException
32
-     */
33
-    public function __construct($routing = true)
34
-    {
35
-        parent::__construct($routing);
36
-        if (! defined('REG_CAF_TEMPLATE_PATH')) {
37
-            define('REG_CAF_TEMPLATE_PATH', EE_CORE_CAF_ADMIN_EXTEND . 'registrations/templates/');
38
-            define('REG_CAF_ASSETS', EE_CORE_CAF_ADMIN_EXTEND . 'registrations/assets/');
39
-            define('REG_CAF_ASSETS_URL', EE_CORE_CAF_ADMIN_EXTEND_URL . 'registrations/assets/');
40
-        }
41
-    }
42
-
43
-
44
-    protected function _set_page_config()
45
-    {
46
-        parent::_set_page_config();
47
-
48
-        $this->_admin_base_path                           = EE_CORE_CAF_ADMIN_EXTEND . 'registrations';
49
-        $reg_id                                           =
50
-            ! empty($this->_req_data['_REG_ID']) && ! is_array($this->_req_data['_REG_ID'])
51
-                ? $this->_req_data['_REG_ID']
52
-                : 0;
53
-        $new_page_routes                                  = [
54
-            'reports'                      => [
55
-                'func'       => [$this, '_registration_reports'],
56
-                'capability' => 'ee_read_registrations',
57
-            ],
58
-            'registration_checkins'        => [
59
-                'func'       => [$this, '_registration_checkin_list_table'],
60
-                'capability' => 'ee_read_checkins',
61
-            ],
62
-            'newsletter_selected_send'     => [
63
-                'func'       => [$this, '_newsletter_selected_send'],
64
-                'noheader'   => true,
65
-                'capability' => 'ee_send_message',
66
-            ],
67
-            'delete_checkin_rows'          => [
68
-                'func'       => [$this, '_delete_checkin_rows'],
69
-                'noheader'   => true,
70
-                'capability' => 'ee_delete_checkins',
71
-            ],
72
-            'delete_checkin_row'           => [
73
-                'func'       => [$this, '_delete_checkin_row'],
74
-                'noheader'   => true,
75
-                'capability' => 'ee_delete_checkin',
76
-                'obj_id'     => $reg_id,
77
-            ],
78
-            'toggle_checkin_status'        => [
79
-                'func'       => [$this, '_toggle_checkin_status'],
80
-                'noheader'   => true,
81
-                'capability' => 'ee_edit_checkin',
82
-                'obj_id'     => $reg_id,
83
-            ],
84
-            'toggle_checkin_status_bulk'   => [
85
-                'func'       => [$this, '_toggle_checkin_status'],
86
-                'noheader'   => true,
87
-                'capability' => 'ee_edit_checkins',
88
-            ],
89
-            'event_registrations'          => [
90
-                'func'       => [$this, '_event_registrations_list_table'],
91
-                'capability' => 'ee_read_checkins',
92
-            ],
93
-            'registrations_checkin_report' => [
94
-                'func'       => [$this, '_registrations_checkin_report'],
95
-                'noheader'   => true,
96
-                'capability' => 'ee_read_registrations',
97
-            ],
98
-        ];
99
-        $this->_page_routes                               = array_merge($this->_page_routes, $new_page_routes);
100
-        $new_page_config                                  = [
101
-            'reports'               => [
102
-                'nav'           => [
103
-                    'label' => esc_html__('Reports', 'event_espresso'),
104
-                    'icon'  => 'dashicons-chart-bar',
105
-                    'order' => 30,
106
-                ],
107
-                'help_tabs'     => [
108
-                    'registrations_reports_help_tab' => [
109
-                        'title'    => esc_html__('Registration Reports', 'event_espresso'),
110
-                        'filename' => 'registrations_reports',
111
-                    ],
112
-                ],
113
-                'require_nonce' => false,
114
-            ],
115
-            'event_registrations'   => [
116
-                'nav'           => [
117
-                    'label'      => esc_html__('Event Check-In', 'event_espresso'),
118
-                    'icon'       => 'dashicons-yes-alt',
119
-                    'order'      => 10,
120
-                    'persistent' => true,
121
-                ],
122
-                'help_tabs'     => [
123
-                    'registrations_event_checkin_help_tab'                       => [
124
-                        'title'    => esc_html__('Registrations Event Check-In', 'event_espresso'),
125
-                        'filename' => 'registrations_event_checkin',
126
-                    ],
127
-                    'registrations_event_checkin_table_column_headings_help_tab' => [
128
-                        'title'    => esc_html__('Event Check-In Table Column Headings', 'event_espresso'),
129
-                        'filename' => 'registrations_event_checkin_table_column_headings',
130
-                    ],
131
-                    'registrations_event_checkin_filters_help_tab'               => [
132
-                        'title'    => esc_html__('Event Check-In Filters', 'event_espresso'),
133
-                        'filename' => 'registrations_event_checkin_filters',
134
-                    ],
135
-                    'registrations_event_checkin_views_help_tab'                 => [
136
-                        'title'    => esc_html__('Event Check-In Views', 'event_espresso'),
137
-                        'filename' => 'registrations_event_checkin_views',
138
-                    ],
139
-                    'registrations_event_checkin_other_help_tab'                 => [
140
-                        'title'    => esc_html__('Event Check-In Other', 'event_espresso'),
141
-                        'filename' => 'registrations_event_checkin_other',
142
-                    ],
143
-                ],
144
-                'list_table'    => 'EE_Event_Registrations_List_Table',
145
-                'metaboxes'     => [],
146
-                'require_nonce' => false,
147
-            ],
148
-            'registration_checkins' => [
149
-                'nav'           => [
150
-                    'label'      => esc_html__('Check-In Records', 'event_espresso'),
151
-                    'icon'       => 'dashicons-list-view',
152
-                    'order'      => 15,
153
-                    'persistent' => false,
154
-                    'url'        => '',
155
-                ],
156
-                'list_table'    => 'EE_Registration_CheckIn_List_Table',
157
-                'metaboxes'     => [],
158
-                'require_nonce' => false,
159
-            ],
160
-        ];
161
-        $this->_page_config                               = array_merge($this->_page_config, $new_page_config);
162
-        $this->_page_config['contact_list']['list_table'] = 'Extend_EE_Attendee_Contact_List_Table';
163
-        $this->_page_config['default']['list_table']      = 'Extend_EE_Registrations_List_Table';
164
-    }
165
-
166
-
167
-    /**
168
-     * Ajax hooks for all routes in this page.
169
-     */
170
-    protected function _ajax_hooks()
171
-    {
172
-        parent::_ajax_hooks();
173
-        add_action('wp_ajax_get_newsletter_form_content', [$this, 'get_newsletter_form_content']);
174
-        add_action('wp_ajax_toggle_checkin_status', [$this, 'toggle_checkin_status']);
175
-    }
176
-
177
-
178
-    /**
179
-     * Global scripts for all routes in this page.
180
-     *
181
-     * @throws EE_Error
182
-     * *@throws ReflectionException
183
-     */
184
-    public function load_scripts_styles()
185
-    {
186
-        parent::load_scripts_styles();
187
-        // if newsletter message type is active then let's add filter and load js for it.
188
-        if (EEH_MSG_Template::is_mt_active('newsletter')) {
189
-            wp_enqueue_style(
190
-                'ee_message_shortcodes',
191
-                EE_MSG_ASSETS_URL . 'ee_message_shortcodes.css',
192
-                [EspressoLegacyAdminAssetManager::CSS_HANDLE_EE_ADMIN],
193
-                EVENT_ESPRESSO_VERSION
194
-            );
195
-            // enqueue newsletter js
196
-            wp_enqueue_script(
197
-                'ee-newsletter-trigger',
198
-                REG_CAF_ASSETS_URL . 'ee-newsletter-trigger.js',
199
-                ['ee-dialog'],
200
-                EVENT_ESPRESSO_VERSION,
201
-                true
202
-            );
203
-            // hook in buttons for newsletter message type trigger.
204
-            add_action(
205
-                'AHEE__EE_Admin_List_Table__extra_tablenav__after_bottom_buttons',
206
-                [$this, 'add_newsletter_action_buttons']
207
-            );
208
-        }
209
-    }
210
-
211
-
212
-    /**
213
-     * Scripts and styles for just the reports route.
214
-     *
215
-     * @throws EE_Error
216
-     * @throws ReflectionException
217
-     */
218
-    public function load_scripts_styles_reports()
219
-    {
220
-        wp_register_script(
221
-            'ee-reg-reports-js',
222
-            REG_CAF_ASSETS_URL . 'ee-registration-admin-reports.js',
223
-            ['google-charts'],
224
-            EVENT_ESPRESSO_VERSION,
225
-            true
226
-        );
227
-        wp_enqueue_script('ee-reg-reports-js');
228
-        $this->_registration_reports_js_setup();
229
-    }
230
-
231
-
232
-    /**
233
-     * Register screen options for event_registrations route.
234
-     */
235
-    protected function _add_screen_options_event_registrations()
236
-    {
237
-        $this->_per_page_screen_option();
238
-    }
239
-
240
-
241
-    /**
242
-     * Register screen options for registration_checkins route
243
-     */
244
-    protected function _add_screen_options_registration_checkins()
245
-    {
246
-        $page_title              = $this->_admin_page_title;
247
-        $this->_admin_page_title = esc_html__('Check-In Records', 'event_espresso');
248
-        $this->_per_page_screen_option();
249
-        $this->_admin_page_title = $page_title;
250
-    }
251
-
252
-
253
-    /**
254
-     * Set views property for event_registrations route.
255
-     */
256
-    protected function _set_list_table_views_event_registrations()
257
-    {
258
-        $DTT_ID = $this->request->getRequestParam('DTT_ID', 0, DataType::INTEGER);
259
-        $this->_views = [
260
-            'all' => [
261
-                'slug'        => 'all',
262
-                'label'       => esc_html__('All', 'event_espresso'),
263
-                'count'       => 0,
264
-                'bulk_action' => $DTT_ID
265
-                    ? ['toggle_checkin_status_bulk' => esc_html__('Toggle Check-In', 'event_espresso')]
266
-                    : [],
267
-            ],
268
-        ];
269
-    }
270
-
271
-
272
-    /**
273
-     * Set views property for registration_checkins route.
274
-     */
275
-    protected function _set_list_table_views_registration_checkins()
276
-    {
277
-        $this->_views = [
278
-            'all' => [
279
-                'slug'        => 'all',
280
-                'label'       => esc_html__('All', 'event_espresso'),
281
-                'count'       => 0,
282
-                'bulk_action' => ['delete_checkin_rows' => esc_html__('Delete Check-In Rows', 'event_espresso')],
283
-            ],
284
-        ];
285
-    }
286
-
287
-
288
-    /**
289
-     * callback for ajax action.
290
-     *
291
-     * @return void (JSON)
292
-     * @throws EE_Error
293
-     * @throws ReflectionException
294
-     * @since 4.3.0
295
-     */
296
-    public function get_newsletter_form_content()
297
-    {
298
-        if (! $this->capabilities->current_user_can('ee_read_messages', __FUNCTION__)) {
299
-            wp_die(esc_html__('You do not have the required privileges to perform this action', 'event_espresso'));
300
-        }
301
-        // do a nonce check because we're not coming in from a normal route here.
302
-        $nonce     = isset($this->_req_data['get_newsletter_form_content_nonce'])
303
-            ? sanitize_text_field($this->_req_data['get_newsletter_form_content_nonce'])
304
-            : '';
305
-        $nonce_ref = 'get_newsletter_form_content_nonce';
306
-        $this->_verify_nonce($nonce, $nonce_ref);
307
-        // let's get the mtp for the incoming MTP_ ID
308
-        if (! isset($this->_req_data['GRP_ID'])) {
309
-            EE_Error::add_error(
310
-                esc_html__(
311
-                    'There must be something broken with the js or html structure because the required data for getting a message template group is not present (need an GRP_ID).',
312
-                    'event_espresso'
313
-                ),
314
-                __FILE__,
315
-                __FUNCTION__,
316
-                __LINE__
317
-            );
318
-            $this->_template_args['success'] = false;
319
-            $this->_template_args['error']   = true;
320
-            $this->_return_json();
321
-        }
322
-        $MTPG = EEM_Message_Template_Group::instance()->get_one_by_ID($this->_req_data['GRP_ID']);
323
-        if (! $MTPG instanceof EE_Message_Template_Group) {
324
-            EE_Error::add_error(
325
-                sprintf(
326
-                    esc_html__(
327
-                        'The GRP_ID given (%d) does not appear to have a corresponding row in the database.',
328
-                        'event_espresso'
329
-                    ),
330
-                    $this->_req_data['GRP_ID']
331
-                ),
332
-                __FILE__,
333
-                __FUNCTION__,
334
-                __LINE__
335
-            );
336
-            $this->_template_args['success'] = false;
337
-            $this->_template_args['error']   = true;
338
-            $this->_return_json();
339
-        }
340
-        $MTPs            = $MTPG->context_templates();
341
-        $MTPs            = $MTPs['attendee'];
342
-        $template_fields = [];
343
-        /** @var EE_Message_Template $MTP */
344
-        foreach ($MTPs as $MTP) {
345
-            $field = $MTP->get('MTP_template_field');
346
-            if ($field === 'content') {
347
-                $content = $MTP->get('MTP_content');
348
-                if (! empty($content['newsletter_content'])) {
349
-                    $template_fields['newsletter_content'] = $content['newsletter_content'];
350
-                }
351
-                continue;
352
-            }
353
-            $template_fields[ $MTP->get('MTP_template_field') ] = $MTP->get('MTP_content');
354
-        }
355
-        $this->_template_args['success'] = true;
356
-        $this->_template_args['error']   = false;
357
-        $this->_template_args['data']    = [
358
-            'batch_message_from'    => $template_fields['from'] ?? '',
359
-            'batch_message_subject' => $template_fields['subject'] ?? '',
360
-            'batch_message_content' => $template_fields['newsletter_content'] ?? '',
361
-        ];
362
-        $this->_return_json();
363
-    }
364
-
365
-
366
-    /**
367
-     * callback for AHEE__EE_Admin_List_Table__extra_tablenav__after_bottom_buttons action
368
-     *
369
-     * @param EE_Admin_List_Table $list_table
370
-     * @return void
371
-     * @since 4.3.0
372
-     */
373
-    public function add_newsletter_action_buttons(EE_Admin_List_Table $list_table)
374
-    {
375
-        if (
376
-            ! EE_Registry::instance()->CAP->current_user_can(
377
-                'ee_send_message',
378
-                'espresso_registrations_newsletter_selected_send'
379
-            )
380
-        ) {
381
-            return;
382
-        }
383
-        $routes_to_add_to = [
384
-            'contact_list',
385
-            'event_registrations',
386
-            'default',
387
-        ];
388
-        if ($this->_current_page === 'espresso_registrations' && in_array($this->_req_action, $routes_to_add_to)) {
389
-            if (
390
-                ($this->_req_action === 'event_registrations' && empty($this->_req_data['event_id']))
391
-                || (isset($this->_req_data['status']) && $this->_req_data['status'] === 'trash')
392
-            ) {
393
-                echo '';
394
-            } else {
395
-                $button_text = sprintf(
396
-                    esc_html__('Send Batch Message (%s selected)', 'event_espresso'),
397
-                    '<span class="send-selected-newsletter-count">0</span>'
398
-                );
399
-                echo '<button id="selected-batch-send-trigger" class="button button--secondary">'
400
-                    . '<span class="dashicons dashicons-email "></span>'
401
-                    . $button_text
402
-                    . '</button>';
403
-                add_action('admin_footer', [$this, 'newsletter_send_form_skeleton']);
404
-            }
405
-        }
406
-    }
407
-
408
-
409
-    /**
410
-     * @throws DomainException
411
-     * @throws EE_Error
412
-     * @throws ReflectionException
413
-     */
414
-    public function newsletter_send_form_skeleton()
415
-    {
416
-        $list_table = $this->_list_table_object;
417
-        $codes      = [];
418
-        // need to templates for the newsletter message type for the template selector.
419
-        $values[] = ['text' => esc_html__('Select Template to Use', 'event_espresso'), 'id' => 0];
420
-        $mtps     = EEM_Message_Template_Group::instance()->get_all(
421
-            [['MTP_message_type' => 'newsletter', 'MTP_messenger' => 'email']]
422
-        );
423
-        foreach ($mtps as $mtp) {
424
-            $name     = $mtp->name();
425
-            $values[] = [
426
-                'text' => empty($name) ? esc_html__('Global', 'event_espresso') : $name,
427
-                'id'   => $mtp->ID(),
428
-            ];
429
-        }
430
-        // need to get a list of shortcodes that are available for the newsletter message type.
431
-        $shortcodes = EEH_MSG_Template::get_shortcodes(
432
-            'newsletter',
433
-            'email',
434
-            [],
435
-            'attendee'
436
-        );
437
-
438
-        foreach ($shortcodes as $field => $shortcode_array) {
439
-            $available_shortcodes = [];
440
-            foreach ($shortcode_array as $shortcode => $shortcode_details) {
441
-                $field_id               = $field === '[NEWSLETTER_CONTENT]'
442
-                    ? 'content'
443
-                    : strtolower($field);
444
-                $field_id               = "batch-message-$field_id";
445
-                $available_shortcodes[] = '
19
+	/**
20
+	 * This is used to hold the reports template data which is setup early in the request.
21
+	 *
22
+	 * @type array
23
+	 */
24
+	protected array $_reports_template_data = [];
25
+
26
+
27
+	/**
28
+	 * Extend_Registrations_Admin_Page constructor.
29
+	 *
30
+	 * @param bool $routing
31
+	 * @throws ReflectionException
32
+	 */
33
+	public function __construct($routing = true)
34
+	{
35
+		parent::__construct($routing);
36
+		if (! defined('REG_CAF_TEMPLATE_PATH')) {
37
+			define('REG_CAF_TEMPLATE_PATH', EE_CORE_CAF_ADMIN_EXTEND . 'registrations/templates/');
38
+			define('REG_CAF_ASSETS', EE_CORE_CAF_ADMIN_EXTEND . 'registrations/assets/');
39
+			define('REG_CAF_ASSETS_URL', EE_CORE_CAF_ADMIN_EXTEND_URL . 'registrations/assets/');
40
+		}
41
+	}
42
+
43
+
44
+	protected function _set_page_config()
45
+	{
46
+		parent::_set_page_config();
47
+
48
+		$this->_admin_base_path                           = EE_CORE_CAF_ADMIN_EXTEND . 'registrations';
49
+		$reg_id                                           =
50
+			! empty($this->_req_data['_REG_ID']) && ! is_array($this->_req_data['_REG_ID'])
51
+				? $this->_req_data['_REG_ID']
52
+				: 0;
53
+		$new_page_routes                                  = [
54
+			'reports'                      => [
55
+				'func'       => [$this, '_registration_reports'],
56
+				'capability' => 'ee_read_registrations',
57
+			],
58
+			'registration_checkins'        => [
59
+				'func'       => [$this, '_registration_checkin_list_table'],
60
+				'capability' => 'ee_read_checkins',
61
+			],
62
+			'newsletter_selected_send'     => [
63
+				'func'       => [$this, '_newsletter_selected_send'],
64
+				'noheader'   => true,
65
+				'capability' => 'ee_send_message',
66
+			],
67
+			'delete_checkin_rows'          => [
68
+				'func'       => [$this, '_delete_checkin_rows'],
69
+				'noheader'   => true,
70
+				'capability' => 'ee_delete_checkins',
71
+			],
72
+			'delete_checkin_row'           => [
73
+				'func'       => [$this, '_delete_checkin_row'],
74
+				'noheader'   => true,
75
+				'capability' => 'ee_delete_checkin',
76
+				'obj_id'     => $reg_id,
77
+			],
78
+			'toggle_checkin_status'        => [
79
+				'func'       => [$this, '_toggle_checkin_status'],
80
+				'noheader'   => true,
81
+				'capability' => 'ee_edit_checkin',
82
+				'obj_id'     => $reg_id,
83
+			],
84
+			'toggle_checkin_status_bulk'   => [
85
+				'func'       => [$this, '_toggle_checkin_status'],
86
+				'noheader'   => true,
87
+				'capability' => 'ee_edit_checkins',
88
+			],
89
+			'event_registrations'          => [
90
+				'func'       => [$this, '_event_registrations_list_table'],
91
+				'capability' => 'ee_read_checkins',
92
+			],
93
+			'registrations_checkin_report' => [
94
+				'func'       => [$this, '_registrations_checkin_report'],
95
+				'noheader'   => true,
96
+				'capability' => 'ee_read_registrations',
97
+			],
98
+		];
99
+		$this->_page_routes                               = array_merge($this->_page_routes, $new_page_routes);
100
+		$new_page_config                                  = [
101
+			'reports'               => [
102
+				'nav'           => [
103
+					'label' => esc_html__('Reports', 'event_espresso'),
104
+					'icon'  => 'dashicons-chart-bar',
105
+					'order' => 30,
106
+				],
107
+				'help_tabs'     => [
108
+					'registrations_reports_help_tab' => [
109
+						'title'    => esc_html__('Registration Reports', 'event_espresso'),
110
+						'filename' => 'registrations_reports',
111
+					],
112
+				],
113
+				'require_nonce' => false,
114
+			],
115
+			'event_registrations'   => [
116
+				'nav'           => [
117
+					'label'      => esc_html__('Event Check-In', 'event_espresso'),
118
+					'icon'       => 'dashicons-yes-alt',
119
+					'order'      => 10,
120
+					'persistent' => true,
121
+				],
122
+				'help_tabs'     => [
123
+					'registrations_event_checkin_help_tab'                       => [
124
+						'title'    => esc_html__('Registrations Event Check-In', 'event_espresso'),
125
+						'filename' => 'registrations_event_checkin',
126
+					],
127
+					'registrations_event_checkin_table_column_headings_help_tab' => [
128
+						'title'    => esc_html__('Event Check-In Table Column Headings', 'event_espresso'),
129
+						'filename' => 'registrations_event_checkin_table_column_headings',
130
+					],
131
+					'registrations_event_checkin_filters_help_tab'               => [
132
+						'title'    => esc_html__('Event Check-In Filters', 'event_espresso'),
133
+						'filename' => 'registrations_event_checkin_filters',
134
+					],
135
+					'registrations_event_checkin_views_help_tab'                 => [
136
+						'title'    => esc_html__('Event Check-In Views', 'event_espresso'),
137
+						'filename' => 'registrations_event_checkin_views',
138
+					],
139
+					'registrations_event_checkin_other_help_tab'                 => [
140
+						'title'    => esc_html__('Event Check-In Other', 'event_espresso'),
141
+						'filename' => 'registrations_event_checkin_other',
142
+					],
143
+				],
144
+				'list_table'    => 'EE_Event_Registrations_List_Table',
145
+				'metaboxes'     => [],
146
+				'require_nonce' => false,
147
+			],
148
+			'registration_checkins' => [
149
+				'nav'           => [
150
+					'label'      => esc_html__('Check-In Records', 'event_espresso'),
151
+					'icon'       => 'dashicons-list-view',
152
+					'order'      => 15,
153
+					'persistent' => false,
154
+					'url'        => '',
155
+				],
156
+				'list_table'    => 'EE_Registration_CheckIn_List_Table',
157
+				'metaboxes'     => [],
158
+				'require_nonce' => false,
159
+			],
160
+		];
161
+		$this->_page_config                               = array_merge($this->_page_config, $new_page_config);
162
+		$this->_page_config['contact_list']['list_table'] = 'Extend_EE_Attendee_Contact_List_Table';
163
+		$this->_page_config['default']['list_table']      = 'Extend_EE_Registrations_List_Table';
164
+	}
165
+
166
+
167
+	/**
168
+	 * Ajax hooks for all routes in this page.
169
+	 */
170
+	protected function _ajax_hooks()
171
+	{
172
+		parent::_ajax_hooks();
173
+		add_action('wp_ajax_get_newsletter_form_content', [$this, 'get_newsletter_form_content']);
174
+		add_action('wp_ajax_toggle_checkin_status', [$this, 'toggle_checkin_status']);
175
+	}
176
+
177
+
178
+	/**
179
+	 * Global scripts for all routes in this page.
180
+	 *
181
+	 * @throws EE_Error
182
+	 * *@throws ReflectionException
183
+	 */
184
+	public function load_scripts_styles()
185
+	{
186
+		parent::load_scripts_styles();
187
+		// if newsletter message type is active then let's add filter and load js for it.
188
+		if (EEH_MSG_Template::is_mt_active('newsletter')) {
189
+			wp_enqueue_style(
190
+				'ee_message_shortcodes',
191
+				EE_MSG_ASSETS_URL . 'ee_message_shortcodes.css',
192
+				[EspressoLegacyAdminAssetManager::CSS_HANDLE_EE_ADMIN],
193
+				EVENT_ESPRESSO_VERSION
194
+			);
195
+			// enqueue newsletter js
196
+			wp_enqueue_script(
197
+				'ee-newsletter-trigger',
198
+				REG_CAF_ASSETS_URL . 'ee-newsletter-trigger.js',
199
+				['ee-dialog'],
200
+				EVENT_ESPRESSO_VERSION,
201
+				true
202
+			);
203
+			// hook in buttons for newsletter message type trigger.
204
+			add_action(
205
+				'AHEE__EE_Admin_List_Table__extra_tablenav__after_bottom_buttons',
206
+				[$this, 'add_newsletter_action_buttons']
207
+			);
208
+		}
209
+	}
210
+
211
+
212
+	/**
213
+	 * Scripts and styles for just the reports route.
214
+	 *
215
+	 * @throws EE_Error
216
+	 * @throws ReflectionException
217
+	 */
218
+	public function load_scripts_styles_reports()
219
+	{
220
+		wp_register_script(
221
+			'ee-reg-reports-js',
222
+			REG_CAF_ASSETS_URL . 'ee-registration-admin-reports.js',
223
+			['google-charts'],
224
+			EVENT_ESPRESSO_VERSION,
225
+			true
226
+		);
227
+		wp_enqueue_script('ee-reg-reports-js');
228
+		$this->_registration_reports_js_setup();
229
+	}
230
+
231
+
232
+	/**
233
+	 * Register screen options for event_registrations route.
234
+	 */
235
+	protected function _add_screen_options_event_registrations()
236
+	{
237
+		$this->_per_page_screen_option();
238
+	}
239
+
240
+
241
+	/**
242
+	 * Register screen options for registration_checkins route
243
+	 */
244
+	protected function _add_screen_options_registration_checkins()
245
+	{
246
+		$page_title              = $this->_admin_page_title;
247
+		$this->_admin_page_title = esc_html__('Check-In Records', 'event_espresso');
248
+		$this->_per_page_screen_option();
249
+		$this->_admin_page_title = $page_title;
250
+	}
251
+
252
+
253
+	/**
254
+	 * Set views property for event_registrations route.
255
+	 */
256
+	protected function _set_list_table_views_event_registrations()
257
+	{
258
+		$DTT_ID = $this->request->getRequestParam('DTT_ID', 0, DataType::INTEGER);
259
+		$this->_views = [
260
+			'all' => [
261
+				'slug'        => 'all',
262
+				'label'       => esc_html__('All', 'event_espresso'),
263
+				'count'       => 0,
264
+				'bulk_action' => $DTT_ID
265
+					? ['toggle_checkin_status_bulk' => esc_html__('Toggle Check-In', 'event_espresso')]
266
+					: [],
267
+			],
268
+		];
269
+	}
270
+
271
+
272
+	/**
273
+	 * Set views property for registration_checkins route.
274
+	 */
275
+	protected function _set_list_table_views_registration_checkins()
276
+	{
277
+		$this->_views = [
278
+			'all' => [
279
+				'slug'        => 'all',
280
+				'label'       => esc_html__('All', 'event_espresso'),
281
+				'count'       => 0,
282
+				'bulk_action' => ['delete_checkin_rows' => esc_html__('Delete Check-In Rows', 'event_espresso')],
283
+			],
284
+		];
285
+	}
286
+
287
+
288
+	/**
289
+	 * callback for ajax action.
290
+	 *
291
+	 * @return void (JSON)
292
+	 * @throws EE_Error
293
+	 * @throws ReflectionException
294
+	 * @since 4.3.0
295
+	 */
296
+	public function get_newsletter_form_content()
297
+	{
298
+		if (! $this->capabilities->current_user_can('ee_read_messages', __FUNCTION__)) {
299
+			wp_die(esc_html__('You do not have the required privileges to perform this action', 'event_espresso'));
300
+		}
301
+		// do a nonce check because we're not coming in from a normal route here.
302
+		$nonce     = isset($this->_req_data['get_newsletter_form_content_nonce'])
303
+			? sanitize_text_field($this->_req_data['get_newsletter_form_content_nonce'])
304
+			: '';
305
+		$nonce_ref = 'get_newsletter_form_content_nonce';
306
+		$this->_verify_nonce($nonce, $nonce_ref);
307
+		// let's get the mtp for the incoming MTP_ ID
308
+		if (! isset($this->_req_data['GRP_ID'])) {
309
+			EE_Error::add_error(
310
+				esc_html__(
311
+					'There must be something broken with the js or html structure because the required data for getting a message template group is not present (need an GRP_ID).',
312
+					'event_espresso'
313
+				),
314
+				__FILE__,
315
+				__FUNCTION__,
316
+				__LINE__
317
+			);
318
+			$this->_template_args['success'] = false;
319
+			$this->_template_args['error']   = true;
320
+			$this->_return_json();
321
+		}
322
+		$MTPG = EEM_Message_Template_Group::instance()->get_one_by_ID($this->_req_data['GRP_ID']);
323
+		if (! $MTPG instanceof EE_Message_Template_Group) {
324
+			EE_Error::add_error(
325
+				sprintf(
326
+					esc_html__(
327
+						'The GRP_ID given (%d) does not appear to have a corresponding row in the database.',
328
+						'event_espresso'
329
+					),
330
+					$this->_req_data['GRP_ID']
331
+				),
332
+				__FILE__,
333
+				__FUNCTION__,
334
+				__LINE__
335
+			);
336
+			$this->_template_args['success'] = false;
337
+			$this->_template_args['error']   = true;
338
+			$this->_return_json();
339
+		}
340
+		$MTPs            = $MTPG->context_templates();
341
+		$MTPs            = $MTPs['attendee'];
342
+		$template_fields = [];
343
+		/** @var EE_Message_Template $MTP */
344
+		foreach ($MTPs as $MTP) {
345
+			$field = $MTP->get('MTP_template_field');
346
+			if ($field === 'content') {
347
+				$content = $MTP->get('MTP_content');
348
+				if (! empty($content['newsletter_content'])) {
349
+					$template_fields['newsletter_content'] = $content['newsletter_content'];
350
+				}
351
+				continue;
352
+			}
353
+			$template_fields[ $MTP->get('MTP_template_field') ] = $MTP->get('MTP_content');
354
+		}
355
+		$this->_template_args['success'] = true;
356
+		$this->_template_args['error']   = false;
357
+		$this->_template_args['data']    = [
358
+			'batch_message_from'    => $template_fields['from'] ?? '',
359
+			'batch_message_subject' => $template_fields['subject'] ?? '',
360
+			'batch_message_content' => $template_fields['newsletter_content'] ?? '',
361
+		];
362
+		$this->_return_json();
363
+	}
364
+
365
+
366
+	/**
367
+	 * callback for AHEE__EE_Admin_List_Table__extra_tablenav__after_bottom_buttons action
368
+	 *
369
+	 * @param EE_Admin_List_Table $list_table
370
+	 * @return void
371
+	 * @since 4.3.0
372
+	 */
373
+	public function add_newsletter_action_buttons(EE_Admin_List_Table $list_table)
374
+	{
375
+		if (
376
+			! EE_Registry::instance()->CAP->current_user_can(
377
+				'ee_send_message',
378
+				'espresso_registrations_newsletter_selected_send'
379
+			)
380
+		) {
381
+			return;
382
+		}
383
+		$routes_to_add_to = [
384
+			'contact_list',
385
+			'event_registrations',
386
+			'default',
387
+		];
388
+		if ($this->_current_page === 'espresso_registrations' && in_array($this->_req_action, $routes_to_add_to)) {
389
+			if (
390
+				($this->_req_action === 'event_registrations' && empty($this->_req_data['event_id']))
391
+				|| (isset($this->_req_data['status']) && $this->_req_data['status'] === 'trash')
392
+			) {
393
+				echo '';
394
+			} else {
395
+				$button_text = sprintf(
396
+					esc_html__('Send Batch Message (%s selected)', 'event_espresso'),
397
+					'<span class="send-selected-newsletter-count">0</span>'
398
+				);
399
+				echo '<button id="selected-batch-send-trigger" class="button button--secondary">'
400
+					. '<span class="dashicons dashicons-email "></span>'
401
+					. $button_text
402
+					. '</button>';
403
+				add_action('admin_footer', [$this, 'newsletter_send_form_skeleton']);
404
+			}
405
+		}
406
+	}
407
+
408
+
409
+	/**
410
+	 * @throws DomainException
411
+	 * @throws EE_Error
412
+	 * @throws ReflectionException
413
+	 */
414
+	public function newsletter_send_form_skeleton()
415
+	{
416
+		$list_table = $this->_list_table_object;
417
+		$codes      = [];
418
+		// need to templates for the newsletter message type for the template selector.
419
+		$values[] = ['text' => esc_html__('Select Template to Use', 'event_espresso'), 'id' => 0];
420
+		$mtps     = EEM_Message_Template_Group::instance()->get_all(
421
+			[['MTP_message_type' => 'newsletter', 'MTP_messenger' => 'email']]
422
+		);
423
+		foreach ($mtps as $mtp) {
424
+			$name     = $mtp->name();
425
+			$values[] = [
426
+				'text' => empty($name) ? esc_html__('Global', 'event_espresso') : $name,
427
+				'id'   => $mtp->ID(),
428
+			];
429
+		}
430
+		// need to get a list of shortcodes that are available for the newsletter message type.
431
+		$shortcodes = EEH_MSG_Template::get_shortcodes(
432
+			'newsletter',
433
+			'email',
434
+			[],
435
+			'attendee'
436
+		);
437
+
438
+		foreach ($shortcodes as $field => $shortcode_array) {
439
+			$available_shortcodes = [];
440
+			foreach ($shortcode_array as $shortcode => $shortcode_details) {
441
+				$field_id               = $field === '[NEWSLETTER_CONTENT]'
442
+					? 'content'
443
+					: strtolower($field);
444
+				$field_id               = "batch-message-$field_id";
445
+				$available_shortcodes[] = '
446 446
                 <span class="js-shortcode-selection"
447 447
                       data-value="' . $shortcode . '"
448 448
                       data-linked-input-id="' . $field_id . '"
449 449
                 >' . $shortcode . '</span>';
450
-            }
451
-            $codes[ $field ] = '<ul><li>' . implode('</li><li>', $available_shortcodes) . '</li></ul>';
452
-        }
453
-
454
-        EEH_Template::display_template(
455
-            REG_CAF_TEMPLATE_PATH . 'newsletter-send-form.template.php',
456
-            [
457
-                'form_action'       => admin_url('admin.php?page=espresso_registrations'),
458
-                'form_route'        => 'newsletter_selected_send',
459
-                'form_nonce_name'   => 'newsletter_selected_send_nonce',
460
-                'form_nonce'        => wp_create_nonce('newsletter_selected_send_nonce'),
461
-                'redirect_back_to'  => $this->_req_action,
462
-                'ajax_nonce'        => wp_create_nonce('get_newsletter_form_content_nonce'),
463
-                'template_selector' => EEH_Form_Fields::select_input('newsletter_mtp_selected', $values),
464
-                'shortcodes'        => $codes,
465
-                'id_type'           => $list_table instanceof EE_Attendee_Contact_List_Table ? 'contact'
466
-                    : 'registration',
467
-            ]
468
-        );
469
-    }
470
-
471
-
472
-    /**
473
-     * Handles sending selected registrations/contacts a newsletter.
474
-     *
475
-     * @return void
476
-     * @throws EE_Error
477
-     * @throws ReflectionException
478
-     * @since  4.3.0
479
-     */
480
-    protected function _newsletter_selected_send()
481
-    {
482
-        $success = true;
483
-        // first we need to make sure we have a GRP_ID so we know what template we're sending and updating!
484
-        if (empty($this->_req_data['newsletter_mtp_selected'])) {
485
-            EE_Error::add_error(
486
-                esc_html__(
487
-                    'In order to send a message, a Message Template GRP_ID is needed. It was not provided so messages were not sent.',
488
-                    'event_espresso'
489
-                ),
490
-                __FILE__,
491
-                __FUNCTION__,
492
-                __LINE__
493
-            );
494
-            $success = false;
495
-        }
496
-        if ($success) {
497
-            // update Message template in case there are any changes
498
-            $Message_Template_Group = EEM_Message_Template_Group::instance()->get_one_by_ID(
499
-                $this->_req_data['newsletter_mtp_selected']
500
-            );
501
-            $Message_Templates      = $Message_Template_Group instanceof EE_Message_Template_Group
502
-                ? $Message_Template_Group->context_templates()
503
-                : [];
504
-            if (empty($Message_Templates)) {
505
-                EE_Error::add_error(
506
-                    esc_html__(
507
-                        'Unable to retrieve message template fields from the db. Messages not sent.',
508
-                        'event_espresso'
509
-                    ),
510
-                    __FILE__,
511
-                    __FUNCTION__,
512
-                    __LINE__
513
-                );
514
-            }
515
-            // let's just update the specific fields
516
-            foreach ($Message_Templates['attendee'] as $Message_Template) {
517
-                if ($Message_Template instanceof EE_Message_Template) {
518
-                    $field   = $Message_Template->get('MTP_template_field');
519
-                    $content = $Message_Template->get('MTP_content');
520
-                    switch ($field) {
521
-                        case 'from':
522
-                            $new_content = ! empty($this->_req_data['batch_message']['from'])
523
-                                ? $this->_req_data['batch_message']['from']
524
-                                : $content;
525
-                            break;
526
-                        case 'subject':
527
-                            $new_content = ! empty($this->_req_data['batch_message']['subject'])
528
-                                ? $this->_req_data['batch_message']['subject']
529
-                                : $content;
530
-                            break;
531
-                        case 'content':
532
-                            $new_content                       = $content;
533
-                            $new_content['newsletter_content'] = ! empty($this->_req_data['batch_message']['content'])
534
-                                ? $this->_req_data['batch_message']['content']
535
-                                : $content['newsletter_content'];
536
-                            break;
537
-                        default:
538
-                            // continue the foreach loop, we don't want to set $new_content nor save.
539
-                            continue 2;
540
-                    }
541
-                    $Message_Template->set('MTP_content', $new_content);
542
-                    $Message_Template->save();
543
-                }
544
-            }
545
-            // great fields are updated!  now let's make sure we just have contact objects (EE_Attendee).
546
-            $id_type = ! empty($this->_req_data['batch_message']['id_type'])
547
-                ? $this->_req_data['batch_message']['id_type']
548
-                : 'registration';
549
-            // id_type will affect how we assemble the ids.
550
-            $ids                                 = ! empty($this->_req_data['batch_message']['ids'])
551
-                ? json_decode(stripslashes($this->_req_data['batch_message']['ids']))
552
-                : [];
553
-            $registrations_used_for_contact_data = [];
554
-            // using switch because eventually we'll have other contexts that will be used for generating messages.
555
-            switch ($id_type) {
556
-                case 'registration':
557
-                    $registrations_used_for_contact_data = EEM_Registration::instance()->get_all(
558
-                        [
559
-                            [
560
-                                'REG_ID' => ['IN', $ids],
561
-                            ],
562
-                        ]
563
-                    );
564
-                    break;
565
-                case 'contact':
566
-                    $registrations_used_for_contact_data = EEM_Registration::instance()
567
-                                                                           ->get_latest_registration_for_each_of_given_contacts(
568
-                                                                               $ids
569
-                                                                           );
570
-                    break;
571
-            }
572
-            do_action_ref_array(
573
-                'AHEE__Extend_Registrations_Admin_Page___newsletter_selected_send__with_registrations',
574
-                [
575
-                    $registrations_used_for_contact_data,
576
-                    $Message_Template_Group->ID(),
577
-                ]
578
-            );
579
-            // kept for backward compat, internally we no longer use this action.
580
-            // @deprecated 4.8.36.rc.002
581
-            $contacts = $id_type === 'registration'
582
-                ? EEM_Attendee::instance()->get_array_of_contacts_from_reg_ids($ids)
583
-                : EEM_Attendee::instance()->get_all([['ATT_ID' => ['in', $ids]]]);
584
-            do_action_ref_array(
585
-                'AHEE__Extend_Registrations_Admin_Page___newsletter_selected_send',
586
-                [
587
-                    $contacts,
588
-                    $Message_Template_Group->ID(),
589
-                ]
590
-            );
591
-        }
592
-        $query_args = [
593
-            'action' => ! empty($this->_req_data['redirect_back_to'])
594
-                ? $this->_req_data['redirect_back_to']
595
-                : 'default',
596
-        ];
597
-        $this->_redirect_after_action(false, '', '', $query_args, true);
598
-    }
599
-
600
-
601
-    /**
602
-     * This is called when javascript is being enqueued to setup the various data needed for the reports js.
603
-     * Also $this->{$_reports_template_data} property is set for later usage by the _registration_reports method.
604
-     *
605
-     * @throws EE_Error
606
-     * @throws ReflectionException
607
-     */
608
-    protected function _registration_reports_js_setup()
609
-    {
610
-        $this->_reports_template_data['admin_reports'][] = $this->_registrations_per_day_report();
611
-        $this->_reports_template_data['admin_reports'][] = $this->_registrations_per_event_report();
612
-    }
613
-
614
-
615
-    /**
616
-     * generates Business Reports regarding Registrations
617
-     *
618
-     * @return void
619
-     * @throws DomainException
620
-     * @throws EE_Error
621
-     */
622
-    protected function _registration_reports()
623
-    {
624
-        $template_path                              = EE_ADMIN_TEMPLATE . 'admin_reports.template.php';
625
-        $this->_template_args['admin_page_content'] = EEH_Template::display_template(
626
-            $template_path,
627
-            $this->_reports_template_data,
628
-            true
629
-        );
630
-        // the final template wrapper
631
-        $this->display_admin_page_with_no_sidebar();
632
-    }
633
-
634
-
635
-    /**
636
-     * Generates Business Report showing total registrations per day.
637
-     *
638
-     * @param string $period The period (acceptable by PHP Datetime constructor) for which the report is generated.
639
-     * @return string
640
-     * @throws EE_Error
641
-     * @throws ReflectionException
642
-     * @throws Exception
643
-     * @throws Exception
644
-     * @throws Exception
645
-     */
646
-    private function _registrations_per_day_report(string $period = '-1 month'): string
647
-    {
648
-        $report_ID = 'reg-admin-registrations-per-day-report-dv';
649
-        $results   = EEM_Registration::instance()->get_registrations_per_day_and_per_status_report($period);
650
-        $regs      = [];
651
-        $subtitle  = '';
652
-        if ($results) {
653
-            $column_titles = [];
654
-            $tracker       = 0;
655
-            foreach ($results as $result) {
656
-                $report_column_values = [];
657
-                foreach ($result as $property_name => $property_value) {
658
-                    $property_value         = $property_name === 'Registration_REG_date' ? $property_value
659
-                        : (int) $property_value;
660
-                    $report_column_values[] = $property_value;
661
-                    if ($tracker === 0) {
662
-                        if ($property_name === 'Registration_REG_date') {
663
-                            $column_titles[] = esc_html__(
664
-                                'Date (only days with registrations are shown)',
665
-                                'event_espresso'
666
-                            );
667
-                        } else {
668
-                            $column_titles[] = EEH_Template::pretty_status($property_name, false, 'sentence');
669
-                        }
670
-                    }
671
-                }
672
-                $tracker++;
673
-                $regs[] = $report_column_values;
674
-            }
675
-            // make sure the column_titles is pushed to the beginning of the array
676
-            array_unshift($regs, $column_titles);
677
-            // setup the date range.
678
-            $DateTimeZone   = new DateTimeZone(EEH_DTT_Helper::get_timezone());
679
-            $beginning_date = new DateTime("now " . $period, $DateTimeZone);
680
-            $ending_date    = new DateTime("now", $DateTimeZone);
681
-            $subtitle       = sprintf(
682
-                wp_strip_all_tags(
683
-                    _x('For the period: %1$s to %2$s', 'Used to give date range', 'event_espresso')
684
-                ),
685
-                $beginning_date->format('Y-m-d'),
686
-                $ending_date->format('Y-m-d')
687
-            );
688
-        }
689
-        $report_title  = wp_strip_all_tags(__('Total Registrations per Day', 'event_espresso'));
690
-        $report_params = [
691
-            'title'     => $report_title,
692
-            'subtitle'  => $subtitle,
693
-            'id'        => $report_ID,
694
-            'regs'      => $regs,
695
-            'noResults' => empty($regs),
696
-            'noRegsMsg' => sprintf(
697
-                wp_strip_all_tags(
698
-                    __(
699
-                        '%sThere are currently no registration records in the last month for this report.%s',
700
-                        'event_espresso'
701
-                    )
702
-                ),
703
-                '<h2>' . $report_title . '</h2><p>',
704
-                '</p>'
705
-            ),
706
-        ];
707
-        wp_localize_script('ee-reg-reports-js', 'regPerDay', $report_params);
708
-        return $report_ID;
709
-    }
710
-
711
-
712
-    /**
713
-     * Generates Business Report showing total registrations per event.
714
-     *
715
-     * @param string $period The period (acceptable by PHP Datetime constructor) for which the report is generated.
716
-     * @return string
717
-     * @throws EE_Error
718
-     * @throws ReflectionException
719
-     * @throws Exception
720
-     * @throws Exception
721
-     * @throws Exception
722
-     */
723
-    private function _registrations_per_event_report(string $period = '-1 month'): string
724
-    {
725
-        $report_ID = 'reg-admin-registrations-per-event-report-dv';
726
-        $results   = EEM_Registration::instance()->get_registrations_per_event_and_per_status_report($period);
727
-        $regs      = [];
728
-        $subtitle  = '';
729
-        if ($results) {
730
-            $column_titles = [];
731
-            $tracker       = 0;
732
-            foreach ($results as $result) {
733
-                $report_column_values = [];
734
-                foreach ($result as $property_name => $property_value) {
735
-                    $property_value         = $property_name === 'Registration_Event' ? wp_trim_words(
736
-                        $property_value,
737
-                        4,
738
-                        '...'
739
-                    ) : (int) $property_value;
740
-                    $report_column_values[] = $property_value;
741
-                    if ($tracker === 0) {
742
-                        if ($property_name === 'Registration_Event') {
743
-                            $column_titles[] = esc_html__('Event', 'event_espresso');
744
-                        } else {
745
-                            $column_titles[] = EEH_Template::pretty_status($property_name, false, 'sentence');
746
-                        }
747
-                    }
748
-                }
749
-                $tracker++;
750
-                $regs[] = $report_column_values;
751
-            }
752
-            // make sure the column_titles is pushed to the beginning of the array
753
-            array_unshift($regs, $column_titles);
754
-            // setup the date range.
755
-            $DateTimeZone   = new DateTimeZone(EEH_DTT_Helper::get_timezone());
756
-            $beginning_date = new DateTime("now " . $period, $DateTimeZone);
757
-            $ending_date    = new DateTime("now", $DateTimeZone);
758
-            $subtitle       = sprintf(
759
-                wp_strip_all_tags(
760
-                    _x('For the period: %1$s to %2$s', 'Used to give date range', 'event_espresso')
761
-                ),
762
-                $beginning_date->format('Y-m-d'),
763
-                $ending_date->format('Y-m-d')
764
-            );
765
-        }
766
-        $report_title  = wp_strip_all_tags(__('Total Registrations per Event', 'event_espresso'));
767
-        $report_params = [
768
-            'title'     => $report_title,
769
-            'subtitle'  => $subtitle,
770
-            'id'        => $report_ID,
771
-            'regs'      => $regs,
772
-            'noResults' => empty($regs),
773
-            'noRegsMsg' => sprintf(
774
-                wp_strip_all_tags(
775
-                    __(
776
-                        '%sThere are currently no registration records in the last month for this report.%s',
777
-                        'event_espresso'
778
-                    )
779
-                ),
780
-                '<h2>' . $report_title . '</h2><p>',
781
-                '</p>'
782
-            ),
783
-        ];
784
-        wp_localize_script('ee-reg-reports-js', 'regPerEvent', $report_params);
785
-        return $report_ID;
786
-    }
787
-
788
-
789
-    /**
790
-     * generates HTML for the Registration Check-in list table (showing all Check-ins for a specific registration)
791
-     *
792
-     * @return void
793
-     * @throws EE_Error
794
-     * @throws EntityNotFoundException
795
-     * @throws ReflectionException
796
-     */
797
-    protected function _registration_checkin_list_table()
798
-    {
799
-        $REG_ID = $this->request->getRequestParam('_REG_ID', 0, DataType::INTEGER);
800
-        /** @var EE_Registration $registration */
801
-        $registration = EEM_Registration::instance()->get_one_by_ID($REG_ID);
802
-        if (! $registration instanceof EE_Registration) {
803
-            throw new EE_Error(
804
-                sprintf(
805
-                    esc_html__('An error occurred. There is no registration with ID (%d)', 'event_espresso'),
806
-                    $REG_ID
807
-                )
808
-            );
809
-        }
810
-        $attendee                                 = $registration->attendee();
811
-        $this->_admin_page_title                  .= $this->get_action_link_or_button(
812
-            'new_registration',
813
-            'add-registrant',
814
-            ['event_id' => $registration->event_ID()],
815
-            'add-new-h2'
816
-        );
817
-        $checked_in                               = new CheckinStatusDashicon(EE_Checkin::status_checked_in);
818
-        $checked_out                              = new CheckinStatusDashicon(EE_Checkin::status_checked_out);
819
-        $legend_items                             = [
820
-            'checkin'  => [
821
-                'class' => $checked_in->cssClasses(),
822
-                'desc'  => $checked_in->legendLabel(),
823
-            ],
824
-            'checkout' => [
825
-                'class' => $checked_out->cssClasses(),
826
-                'desc'  => $checked_out->legendLabel(),
827
-            ],
828
-        ];
829
-        $this->_template_args['after_list_table'] = $this->_display_legend($legend_items);
830
-
831
-        $DTT_ID         = $this->request->getRequestParam('DTT_ID', 0, DataType::INTEGER);
832
-        $datetime       = EEM_Datetime::instance()->get_one_by_ID($DTT_ID);
833
-        $datetime_label = '';
834
-        if ($datetime instanceof EE_Datetime) {
835
-            $datetime_label = $datetime->get_dtt_display_name(true);
836
-            $datetime_label .= ! empty($datetime_label)
837
-                ? ' (' . $datetime->get_dtt_display_name() . ')'
838
-                : $datetime->get_dtt_display_name();
839
-        }
840
-        $datetime_link                                    = ! $DTT_ID
841
-            ? EE_Admin_Page::add_query_args_and_nonce(
842
-                [
843
-                    'action'   => 'event_registrations',
844
-                    'event_id' => $registration->event_ID(),
845
-                    'DTT_ID'   => $DTT_ID,
846
-                ],
847
-                $this->_admin_base_url
848
-            )
849
-            : '';
850
-        $datetime_link                                    = ! empty($datetime_link)
851
-            ? '<a href="' . $datetime_link . '">'
852
-            . '<span id="checkin-dtt">'
853
-            . $datetime_label
854
-            . '</span></a>'
855
-            : $datetime_label;
856
-        $attendee_name                                    = $attendee instanceof EE_Attendee
857
-            ? $attendee->full_name()
858
-            : '';
859
-        $attendee_link                                    = $attendee instanceof EE_Attendee
860
-            ? $attendee->get_admin_details_link()
861
-            : '';
862
-        $attendee_link                                    = ! empty($attendee_link)
863
-            ? '<a href="' . $attendee->get_admin_details_link() . '"'
864
-            . ' aria-label="' . esc_html__('Click for attendee details', 'event_espresso') . '">'
865
-            . '<span id="checkin-attendee-name">'
866
-            . $attendee_name
867
-            . '</span></a>'
868
-            : '';
869
-        $event_link                                       = $registration->event() instanceof EE_Event
870
-            ? $registration->event()->get_admin_details_link()
871
-            : '';
872
-        $event_link                                       = ! empty($event_link)
873
-            ? '<a href="' . $event_link . '"'
874
-            . ' aria-label="' . esc_html__('Click here to edit event.', 'event_espresso') . '">'
875
-            . '<span id="checkin-event-name">'
876
-            . $registration->event_name()
877
-            . '</span>'
878
-            . '</a>'
879
-            : '';
880
-        $this->_template_args['before_list_table']        = $REG_ID && $DTT_ID
881
-            ? '<h2>' . sprintf(
882
-                esc_html__('Displaying check in records for %1$s for %2$s at the event, %3$s', 'event_espresso'),
883
-                $attendee_link,
884
-                $datetime_link,
885
-                $event_link
886
-            ) . '</h2>'
887
-            : '';
888
-        $this->_template_args['list_table_hidden_fields'] = $REG_ID
889
-            ? '<input type="hidden" name="_REG_ID" value="' . $REG_ID . '">'
890
-            : '';
891
-        $this->_template_args['list_table_hidden_fields'] .= $DTT_ID
892
-            ? '<input type="hidden" name="DTT_ID" value="' . $DTT_ID . '">'
893
-            : '';
894
-        $this->display_admin_list_table_page_with_no_sidebar();
895
-    }
896
-
897
-
898
-    /**
899
-     * toggle the Check-in status for the given registration (coming from ajax)
900
-     *
901
-     * @return void (JSON)
902
-     * @throws EE_Error
903
-     * @throws ReflectionException
904
-     */
905
-    public function toggle_checkin_status()
906
-    {
907
-        if (! $this->capabilities->current_user_can('ee_edit_checkins', __FUNCTION__)) {
908
-            wp_die(esc_html__('You do not have the required privileges to perform this action', 'event_espresso'));
909
-        }
910
-        // first make sure we have the necessary data
911
-        if (! isset($this->_req_data['_regid'])) {
912
-            EE_Error::add_error(
913
-                esc_html__(
914
-                    'There must be something broken with the html structure because the required data for toggling the Check-in status is not being sent via ajax',
915
-                    'event_espresso'
916
-                ),
917
-                __FILE__,
918
-                __FUNCTION__,
919
-                __LINE__
920
-            );
921
-            $this->_template_args['success'] = false;
922
-            $this->_template_args['error']   = true;
923
-            $this->_return_json();
924
-        }
925
-        // do a nonce check because we're not coming in from a normal route here.
926
-        $nonce     = isset($this->_req_data['checkinnonce']) ? sanitize_text_field($this->_req_data['checkinnonce'])
927
-            : '';
928
-        $nonce_ref = 'checkin_nonce';
929
-        $this->_verify_nonce($nonce, $nonce_ref);
930
-        // beautiful! Made it this far so let's get the status.
931
-        $new_status = new CheckinStatusDashicon($this->_toggle_checkin_status());
932
-        // setup new class to return via ajax
933
-        $this->_template_args['admin_page_content'] = 'clickable trigger-checkin ' . $new_status->cssClasses();
934
-        $this->_template_args['success']            = true;
935
-        $this->_return_json();
936
-    }
937
-
938
-
939
-    /**
940
-     * handles toggling the checkin status for the registration,
941
-     *
942
-     * @return int|void
943
-     * @throws EE_Error
944
-     * @throws ReflectionException
945
-     */
946
-    protected function _toggle_checkin_status()
947
-    {
948
-        $DTT_ID = $this->request->getRequestParam('DTT_ID', 0, DataType::INTEGER);
949
-        $DTT_ID = $this->request->getRequestParam('dttid', $DTT_ID, DataType::INTEGER);
950
-        $DTT_ID = $this->request->getRequestParam('datetime_id', $DTT_ID, DataType::INTEGER);
951
-        $_REG_ID = $this->request->getRequestParam('_regid', 0, DataType::INTEGER);
952
-        $checkboxes = $this->request->getRequestParam('checkbox', [], DataType::INTEGER, true);
953
-
954
-        $new_status = false;
955
-        // bulk action check in toggle
956
-        if (! empty($checkboxes)) {
957
-            foreach ($checkboxes as $REG_ID) {
958
-                $new_status = $this->_toggle_checkin($REG_ID, $DTT_ID);
959
-            }
960
-        } elseif ($_REG_ID) {
961
-            $new_status = $this->_toggle_checkin($_REG_ID, $DTT_ID);
962
-        } else {
963
-            EE_Error::add_error(
964
-                esc_html__('Missing some required data to toggle the Check-in', 'event_espresso'),
965
-                __FILE__,
966
-                __FUNCTION__,
967
-                __LINE__
968
-            );
969
-        }
970
-        if (defined('DOING_AJAX') && DOING_AJAX) {
971
-            return $new_status;
972
-        }
973
-        $EVT_ID = $this->request->getRequestParam('EVT_ID', 0, DataType::INTEGER);
974
-        $EVT_ID = $this->request->getRequestParam('event_id', $EVT_ID, DataType::INTEGER);
975
-        $redirect_args = [
976
-            'action' => 'event_registrations',
977
-            'EVT_ID' => $EVT_ID,
978
-            'DTT_ID' => $DTT_ID,
979
-        ];
980
-        $this->_redirect_after_action(false, '', '', $redirect_args, true);
981
-    }
982
-
983
-
984
-    /**
985
-     * This is toggles a single Check-in for the given registration and datetime.
986
-     *
987
-     * @param int $REG_ID The registration we're toggling
988
-     * @param int $DTT_ID The datetime we're toggling
989
-     * @return bool|int   the chk_in status toggled to OR false if nothing got changed.
990
-     * @throws EE_Error
991
-     * @throws ReflectionException
992
-     */
993
-    private function _toggle_checkin(int $REG_ID, int $DTT_ID)
994
-    {
995
-        /** @var EE_Registration $REG */
996
-        $REG        = EEM_Registration::instance()->get_one_by_ID($REG_ID);
997
-        if (! $REG instanceof EE_Registration) {
998
-            EE_Error::add_error(
999
-                sprintf(
1000
-                    esc_html__('There is no registration with ID (%d)', 'event_espresso'),
1001
-                    $REG_ID
1002
-                ),
1003
-                __FILE__,
1004
-                __FUNCTION__,
1005
-                __LINE__
1006
-            );
1007
-            return false;
1008
-        }
1009
-        $new_status = $REG->toggle_checkin_status($DTT_ID);
1010
-        if ($new_status !== false) {
1011
-            EE_Error::add_success($REG->get_checkin_msg($DTT_ID));
1012
-        } else {
1013
-            EE_Error::add_error($REG->get_checkin_msg($DTT_ID, true), __FILE__, __FUNCTION__, __LINE__);
1014
-            $new_status = false;
1015
-        }
1016
-        return $new_status;
1017
-    }
1018
-
1019
-
1020
-    /**
1021
-     * Takes care of deleting multiple EE_Checkin table rows
1022
-     *
1023
-     * @return void
1024
-     * @throws EE_Error
1025
-     * @throws ReflectionException
1026
-     */
1027
-    protected function _delete_checkin_rows()
1028
-    {
1029
-        $query_args = [
1030
-            'action'  => 'registration_checkins',
1031
-            'DTT_ID'  => $this->_req_data['DTT_ID'] ?? 0,
1032
-            '_REG_ID' => $this->_req_data['_REG_ID'] ?? 0,
1033
-        ];
1034
-        $errors     = 0;
1035
-        if (! empty($this->_req_data['checkbox']) && is_array($this->_req_data['checkbox'])) {
1036
-            $checkboxes = $this->_req_data['checkbox'];
1037
-            foreach (array_keys($checkboxes) as $CHK_ID) {
1038
-                if (! EEM_Checkin::instance()->delete_by_ID($CHK_ID)) {
1039
-                    $errors++;
1040
-                }
1041
-            }
1042
-        } else {
1043
-            EE_Error::add_error(
1044
-                esc_html__(
1045
-                    'So, something went wrong with the bulk delete because there was no data received for instructions on WHAT to delete!',
1046
-                    'event_espresso'
1047
-                ),
1048
-                __FILE__,
1049
-                __FUNCTION__,
1050
-                __LINE__
1051
-            );
1052
-            $this->_redirect_after_action(false, '', '', $query_args, true);
1053
-        }
1054
-        if ($errors > 0) {
1055
-            EE_Error::add_error(
1056
-                sprintf(
1057
-                    esc_html__('There were %d records that did not delete successfully', 'event_espresso'),
1058
-                    $errors
1059
-                ),
1060
-                __FILE__,
1061
-                __FUNCTION__,
1062
-                __LINE__
1063
-            );
1064
-        } else {
1065
-            EE_Error::add_success(esc_html__('Records were successfully deleted', 'event_espresso'));
1066
-        }
1067
-        $this->_redirect_after_action(false, '', '', $query_args, true);
1068
-    }
1069
-
1070
-
1071
-    /**
1072
-     * Deletes a single EE_Checkin row
1073
-     *
1074
-     * @return void
1075
-     * @throws EE_Error
1076
-     * @throws ReflectionException
1077
-     */
1078
-    protected function _delete_checkin_row()
1079
-    {
1080
-        $query_args = [
1081
-            'action'  => 'registration_checkins',
1082
-            'DTT_ID'  => $this->_req_data['DTT_ID'] ?? 0,
1083
-            '_REG_ID' => $this->_req_data['_REG_ID'] ?? 0,
1084
-        ];
1085
-        if (! empty($this->_req_data['CHK_ID'])) {
1086
-            if (! EEM_Checkin::instance()->delete_by_ID($this->_req_data['CHK_ID'])) {
1087
-                EE_Error::add_error(
1088
-                    esc_html__('Something went wrong and this check-in record was not deleted', 'event_espresso'),
1089
-                    __FILE__,
1090
-                    __FUNCTION__,
1091
-                    __LINE__
1092
-                );
1093
-            } else {
1094
-                EE_Error::add_success(esc_html__('Check-In record successfully deleted', 'event_espresso'));
1095
-            }
1096
-        } else {
1097
-            EE_Error::add_error(
1098
-                esc_html__(
1099
-                    'In order to delete a Check-in record, there must be a Check-In ID available. There is not. It is not your fault, there is just a gremlin living in the code',
1100
-                    'event_espresso'
1101
-                ),
1102
-                __FILE__,
1103
-                __FUNCTION__,
1104
-                __LINE__
1105
-            );
1106
-        }
1107
-        $this->_redirect_after_action(false, '', '', $query_args, true);
1108
-    }
1109
-
1110
-
1111
-    /**
1112
-     * @return void
1113
-     * @throws EE_Error
1114
-     */
1115
-    protected function _event_registrations_list_table()
1116
-    {
1117
-        $EVT_ID                  = $this->request->getRequestParam('EVT_ID', 0, DataType::INTEGER);
1118
-        $this->_admin_page_title .= $EVT_ID
1119
-            ? $this->get_action_link_or_button(
1120
-                'new_registration',
1121
-                'add-registrant',
1122
-                ['event_id' => $EVT_ID],
1123
-                'add-new-h2'
1124
-            )
1125
-            : '';
1126
-
1127
-        $this->_template_args['before_list_table'] = $this->generateListTableHeaderText();
1128
-        $this->_template_args['after_list_table']  = $this->generateListTableLegend();
1129
-
1130
-        $this->display_admin_list_table_page_with_no_sidebar();
1131
-    }
1132
-
1133
-
1134
-    /**
1135
-     * @return string
1136
-     * @since 5.0.24.p
1137
-     */
1138
-    private function generateListTableHeaderText(): string
1139
-    {
1140
-        $header_text                  = '';
1141
-        $admin_page_header_decorators = [
1142
-            'EventEspresso\core\domain\services\admin\registrations\list_table\page_header\AttendeeFilterHeader',
1143
-            'EventEspresso\core\domain\services\admin\registrations\list_table\page_header\EventFilterHeader',
1144
-            'EventEspresso\core\domain\services\admin\registrations\list_table\page_header\DateFilterHeader',
1145
-            'EventEspresso\core\domain\services\admin\registrations\list_table\page_header\TicketFilterHeader',
1146
-        ];
1147
-        foreach ($admin_page_header_decorators as $admin_page_header_decorator) {
1148
-            $filter_header_decorator = $this->loader->getNew($admin_page_header_decorator);
1149
-            $header_text             = $filter_header_decorator->getHeaderText($header_text);
1150
-        }
1151
-        $header_text .= '
450
+			}
451
+			$codes[ $field ] = '<ul><li>' . implode('</li><li>', $available_shortcodes) . '</li></ul>';
452
+		}
453
+
454
+		EEH_Template::display_template(
455
+			REG_CAF_TEMPLATE_PATH . 'newsletter-send-form.template.php',
456
+			[
457
+				'form_action'       => admin_url('admin.php?page=espresso_registrations'),
458
+				'form_route'        => 'newsletter_selected_send',
459
+				'form_nonce_name'   => 'newsletter_selected_send_nonce',
460
+				'form_nonce'        => wp_create_nonce('newsletter_selected_send_nonce'),
461
+				'redirect_back_to'  => $this->_req_action,
462
+				'ajax_nonce'        => wp_create_nonce('get_newsletter_form_content_nonce'),
463
+				'template_selector' => EEH_Form_Fields::select_input('newsletter_mtp_selected', $values),
464
+				'shortcodes'        => $codes,
465
+				'id_type'           => $list_table instanceof EE_Attendee_Contact_List_Table ? 'contact'
466
+					: 'registration',
467
+			]
468
+		);
469
+	}
470
+
471
+
472
+	/**
473
+	 * Handles sending selected registrations/contacts a newsletter.
474
+	 *
475
+	 * @return void
476
+	 * @throws EE_Error
477
+	 * @throws ReflectionException
478
+	 * @since  4.3.0
479
+	 */
480
+	protected function _newsletter_selected_send()
481
+	{
482
+		$success = true;
483
+		// first we need to make sure we have a GRP_ID so we know what template we're sending and updating!
484
+		if (empty($this->_req_data['newsletter_mtp_selected'])) {
485
+			EE_Error::add_error(
486
+				esc_html__(
487
+					'In order to send a message, a Message Template GRP_ID is needed. It was not provided so messages were not sent.',
488
+					'event_espresso'
489
+				),
490
+				__FILE__,
491
+				__FUNCTION__,
492
+				__LINE__
493
+			);
494
+			$success = false;
495
+		}
496
+		if ($success) {
497
+			// update Message template in case there are any changes
498
+			$Message_Template_Group = EEM_Message_Template_Group::instance()->get_one_by_ID(
499
+				$this->_req_data['newsletter_mtp_selected']
500
+			);
501
+			$Message_Templates      = $Message_Template_Group instanceof EE_Message_Template_Group
502
+				? $Message_Template_Group->context_templates()
503
+				: [];
504
+			if (empty($Message_Templates)) {
505
+				EE_Error::add_error(
506
+					esc_html__(
507
+						'Unable to retrieve message template fields from the db. Messages not sent.',
508
+						'event_espresso'
509
+					),
510
+					__FILE__,
511
+					__FUNCTION__,
512
+					__LINE__
513
+				);
514
+			}
515
+			// let's just update the specific fields
516
+			foreach ($Message_Templates['attendee'] as $Message_Template) {
517
+				if ($Message_Template instanceof EE_Message_Template) {
518
+					$field   = $Message_Template->get('MTP_template_field');
519
+					$content = $Message_Template->get('MTP_content');
520
+					switch ($field) {
521
+						case 'from':
522
+							$new_content = ! empty($this->_req_data['batch_message']['from'])
523
+								? $this->_req_data['batch_message']['from']
524
+								: $content;
525
+							break;
526
+						case 'subject':
527
+							$new_content = ! empty($this->_req_data['batch_message']['subject'])
528
+								? $this->_req_data['batch_message']['subject']
529
+								: $content;
530
+							break;
531
+						case 'content':
532
+							$new_content                       = $content;
533
+							$new_content['newsletter_content'] = ! empty($this->_req_data['batch_message']['content'])
534
+								? $this->_req_data['batch_message']['content']
535
+								: $content['newsletter_content'];
536
+							break;
537
+						default:
538
+							// continue the foreach loop, we don't want to set $new_content nor save.
539
+							continue 2;
540
+					}
541
+					$Message_Template->set('MTP_content', $new_content);
542
+					$Message_Template->save();
543
+				}
544
+			}
545
+			// great fields are updated!  now let's make sure we just have contact objects (EE_Attendee).
546
+			$id_type = ! empty($this->_req_data['batch_message']['id_type'])
547
+				? $this->_req_data['batch_message']['id_type']
548
+				: 'registration';
549
+			// id_type will affect how we assemble the ids.
550
+			$ids                                 = ! empty($this->_req_data['batch_message']['ids'])
551
+				? json_decode(stripslashes($this->_req_data['batch_message']['ids']))
552
+				: [];
553
+			$registrations_used_for_contact_data = [];
554
+			// using switch because eventually we'll have other contexts that will be used for generating messages.
555
+			switch ($id_type) {
556
+				case 'registration':
557
+					$registrations_used_for_contact_data = EEM_Registration::instance()->get_all(
558
+						[
559
+							[
560
+								'REG_ID' => ['IN', $ids],
561
+							],
562
+						]
563
+					);
564
+					break;
565
+				case 'contact':
566
+					$registrations_used_for_contact_data = EEM_Registration::instance()
567
+																		   ->get_latest_registration_for_each_of_given_contacts(
568
+																			   $ids
569
+																		   );
570
+					break;
571
+			}
572
+			do_action_ref_array(
573
+				'AHEE__Extend_Registrations_Admin_Page___newsletter_selected_send__with_registrations',
574
+				[
575
+					$registrations_used_for_contact_data,
576
+					$Message_Template_Group->ID(),
577
+				]
578
+			);
579
+			// kept for backward compat, internally we no longer use this action.
580
+			// @deprecated 4.8.36.rc.002
581
+			$contacts = $id_type === 'registration'
582
+				? EEM_Attendee::instance()->get_array_of_contacts_from_reg_ids($ids)
583
+				: EEM_Attendee::instance()->get_all([['ATT_ID' => ['in', $ids]]]);
584
+			do_action_ref_array(
585
+				'AHEE__Extend_Registrations_Admin_Page___newsletter_selected_send',
586
+				[
587
+					$contacts,
588
+					$Message_Template_Group->ID(),
589
+				]
590
+			);
591
+		}
592
+		$query_args = [
593
+			'action' => ! empty($this->_req_data['redirect_back_to'])
594
+				? $this->_req_data['redirect_back_to']
595
+				: 'default',
596
+		];
597
+		$this->_redirect_after_action(false, '', '', $query_args, true);
598
+	}
599
+
600
+
601
+	/**
602
+	 * This is called when javascript is being enqueued to setup the various data needed for the reports js.
603
+	 * Also $this->{$_reports_template_data} property is set for later usage by the _registration_reports method.
604
+	 *
605
+	 * @throws EE_Error
606
+	 * @throws ReflectionException
607
+	 */
608
+	protected function _registration_reports_js_setup()
609
+	{
610
+		$this->_reports_template_data['admin_reports'][] = $this->_registrations_per_day_report();
611
+		$this->_reports_template_data['admin_reports'][] = $this->_registrations_per_event_report();
612
+	}
613
+
614
+
615
+	/**
616
+	 * generates Business Reports regarding Registrations
617
+	 *
618
+	 * @return void
619
+	 * @throws DomainException
620
+	 * @throws EE_Error
621
+	 */
622
+	protected function _registration_reports()
623
+	{
624
+		$template_path                              = EE_ADMIN_TEMPLATE . 'admin_reports.template.php';
625
+		$this->_template_args['admin_page_content'] = EEH_Template::display_template(
626
+			$template_path,
627
+			$this->_reports_template_data,
628
+			true
629
+		);
630
+		// the final template wrapper
631
+		$this->display_admin_page_with_no_sidebar();
632
+	}
633
+
634
+
635
+	/**
636
+	 * Generates Business Report showing total registrations per day.
637
+	 *
638
+	 * @param string $period The period (acceptable by PHP Datetime constructor) for which the report is generated.
639
+	 * @return string
640
+	 * @throws EE_Error
641
+	 * @throws ReflectionException
642
+	 * @throws Exception
643
+	 * @throws Exception
644
+	 * @throws Exception
645
+	 */
646
+	private function _registrations_per_day_report(string $period = '-1 month'): string
647
+	{
648
+		$report_ID = 'reg-admin-registrations-per-day-report-dv';
649
+		$results   = EEM_Registration::instance()->get_registrations_per_day_and_per_status_report($period);
650
+		$regs      = [];
651
+		$subtitle  = '';
652
+		if ($results) {
653
+			$column_titles = [];
654
+			$tracker       = 0;
655
+			foreach ($results as $result) {
656
+				$report_column_values = [];
657
+				foreach ($result as $property_name => $property_value) {
658
+					$property_value         = $property_name === 'Registration_REG_date' ? $property_value
659
+						: (int) $property_value;
660
+					$report_column_values[] = $property_value;
661
+					if ($tracker === 0) {
662
+						if ($property_name === 'Registration_REG_date') {
663
+							$column_titles[] = esc_html__(
664
+								'Date (only days with registrations are shown)',
665
+								'event_espresso'
666
+							);
667
+						} else {
668
+							$column_titles[] = EEH_Template::pretty_status($property_name, false, 'sentence');
669
+						}
670
+					}
671
+				}
672
+				$tracker++;
673
+				$regs[] = $report_column_values;
674
+			}
675
+			// make sure the column_titles is pushed to the beginning of the array
676
+			array_unshift($regs, $column_titles);
677
+			// setup the date range.
678
+			$DateTimeZone   = new DateTimeZone(EEH_DTT_Helper::get_timezone());
679
+			$beginning_date = new DateTime("now " . $period, $DateTimeZone);
680
+			$ending_date    = new DateTime("now", $DateTimeZone);
681
+			$subtitle       = sprintf(
682
+				wp_strip_all_tags(
683
+					_x('For the period: %1$s to %2$s', 'Used to give date range', 'event_espresso')
684
+				),
685
+				$beginning_date->format('Y-m-d'),
686
+				$ending_date->format('Y-m-d')
687
+			);
688
+		}
689
+		$report_title  = wp_strip_all_tags(__('Total Registrations per Day', 'event_espresso'));
690
+		$report_params = [
691
+			'title'     => $report_title,
692
+			'subtitle'  => $subtitle,
693
+			'id'        => $report_ID,
694
+			'regs'      => $regs,
695
+			'noResults' => empty($regs),
696
+			'noRegsMsg' => sprintf(
697
+				wp_strip_all_tags(
698
+					__(
699
+						'%sThere are currently no registration records in the last month for this report.%s',
700
+						'event_espresso'
701
+					)
702
+				),
703
+				'<h2>' . $report_title . '</h2><p>',
704
+				'</p>'
705
+			),
706
+		];
707
+		wp_localize_script('ee-reg-reports-js', 'regPerDay', $report_params);
708
+		return $report_ID;
709
+	}
710
+
711
+
712
+	/**
713
+	 * Generates Business Report showing total registrations per event.
714
+	 *
715
+	 * @param string $period The period (acceptable by PHP Datetime constructor) for which the report is generated.
716
+	 * @return string
717
+	 * @throws EE_Error
718
+	 * @throws ReflectionException
719
+	 * @throws Exception
720
+	 * @throws Exception
721
+	 * @throws Exception
722
+	 */
723
+	private function _registrations_per_event_report(string $period = '-1 month'): string
724
+	{
725
+		$report_ID = 'reg-admin-registrations-per-event-report-dv';
726
+		$results   = EEM_Registration::instance()->get_registrations_per_event_and_per_status_report($period);
727
+		$regs      = [];
728
+		$subtitle  = '';
729
+		if ($results) {
730
+			$column_titles = [];
731
+			$tracker       = 0;
732
+			foreach ($results as $result) {
733
+				$report_column_values = [];
734
+				foreach ($result as $property_name => $property_value) {
735
+					$property_value         = $property_name === 'Registration_Event' ? wp_trim_words(
736
+						$property_value,
737
+						4,
738
+						'...'
739
+					) : (int) $property_value;
740
+					$report_column_values[] = $property_value;
741
+					if ($tracker === 0) {
742
+						if ($property_name === 'Registration_Event') {
743
+							$column_titles[] = esc_html__('Event', 'event_espresso');
744
+						} else {
745
+							$column_titles[] = EEH_Template::pretty_status($property_name, false, 'sentence');
746
+						}
747
+					}
748
+				}
749
+				$tracker++;
750
+				$regs[] = $report_column_values;
751
+			}
752
+			// make sure the column_titles is pushed to the beginning of the array
753
+			array_unshift($regs, $column_titles);
754
+			// setup the date range.
755
+			$DateTimeZone   = new DateTimeZone(EEH_DTT_Helper::get_timezone());
756
+			$beginning_date = new DateTime("now " . $period, $DateTimeZone);
757
+			$ending_date    = new DateTime("now", $DateTimeZone);
758
+			$subtitle       = sprintf(
759
+				wp_strip_all_tags(
760
+					_x('For the period: %1$s to %2$s', 'Used to give date range', 'event_espresso')
761
+				),
762
+				$beginning_date->format('Y-m-d'),
763
+				$ending_date->format('Y-m-d')
764
+			);
765
+		}
766
+		$report_title  = wp_strip_all_tags(__('Total Registrations per Event', 'event_espresso'));
767
+		$report_params = [
768
+			'title'     => $report_title,
769
+			'subtitle'  => $subtitle,
770
+			'id'        => $report_ID,
771
+			'regs'      => $regs,
772
+			'noResults' => empty($regs),
773
+			'noRegsMsg' => sprintf(
774
+				wp_strip_all_tags(
775
+					__(
776
+						'%sThere are currently no registration records in the last month for this report.%s',
777
+						'event_espresso'
778
+					)
779
+				),
780
+				'<h2>' . $report_title . '</h2><p>',
781
+				'</p>'
782
+			),
783
+		];
784
+		wp_localize_script('ee-reg-reports-js', 'regPerEvent', $report_params);
785
+		return $report_ID;
786
+	}
787
+
788
+
789
+	/**
790
+	 * generates HTML for the Registration Check-in list table (showing all Check-ins for a specific registration)
791
+	 *
792
+	 * @return void
793
+	 * @throws EE_Error
794
+	 * @throws EntityNotFoundException
795
+	 * @throws ReflectionException
796
+	 */
797
+	protected function _registration_checkin_list_table()
798
+	{
799
+		$REG_ID = $this->request->getRequestParam('_REG_ID', 0, DataType::INTEGER);
800
+		/** @var EE_Registration $registration */
801
+		$registration = EEM_Registration::instance()->get_one_by_ID($REG_ID);
802
+		if (! $registration instanceof EE_Registration) {
803
+			throw new EE_Error(
804
+				sprintf(
805
+					esc_html__('An error occurred. There is no registration with ID (%d)', 'event_espresso'),
806
+					$REG_ID
807
+				)
808
+			);
809
+		}
810
+		$attendee                                 = $registration->attendee();
811
+		$this->_admin_page_title                  .= $this->get_action_link_or_button(
812
+			'new_registration',
813
+			'add-registrant',
814
+			['event_id' => $registration->event_ID()],
815
+			'add-new-h2'
816
+		);
817
+		$checked_in                               = new CheckinStatusDashicon(EE_Checkin::status_checked_in);
818
+		$checked_out                              = new CheckinStatusDashicon(EE_Checkin::status_checked_out);
819
+		$legend_items                             = [
820
+			'checkin'  => [
821
+				'class' => $checked_in->cssClasses(),
822
+				'desc'  => $checked_in->legendLabel(),
823
+			],
824
+			'checkout' => [
825
+				'class' => $checked_out->cssClasses(),
826
+				'desc'  => $checked_out->legendLabel(),
827
+			],
828
+		];
829
+		$this->_template_args['after_list_table'] = $this->_display_legend($legend_items);
830
+
831
+		$DTT_ID         = $this->request->getRequestParam('DTT_ID', 0, DataType::INTEGER);
832
+		$datetime       = EEM_Datetime::instance()->get_one_by_ID($DTT_ID);
833
+		$datetime_label = '';
834
+		if ($datetime instanceof EE_Datetime) {
835
+			$datetime_label = $datetime->get_dtt_display_name(true);
836
+			$datetime_label .= ! empty($datetime_label)
837
+				? ' (' . $datetime->get_dtt_display_name() . ')'
838
+				: $datetime->get_dtt_display_name();
839
+		}
840
+		$datetime_link                                    = ! $DTT_ID
841
+			? EE_Admin_Page::add_query_args_and_nonce(
842
+				[
843
+					'action'   => 'event_registrations',
844
+					'event_id' => $registration->event_ID(),
845
+					'DTT_ID'   => $DTT_ID,
846
+				],
847
+				$this->_admin_base_url
848
+			)
849
+			: '';
850
+		$datetime_link                                    = ! empty($datetime_link)
851
+			? '<a href="' . $datetime_link . '">'
852
+			. '<span id="checkin-dtt">'
853
+			. $datetime_label
854
+			. '</span></a>'
855
+			: $datetime_label;
856
+		$attendee_name                                    = $attendee instanceof EE_Attendee
857
+			? $attendee->full_name()
858
+			: '';
859
+		$attendee_link                                    = $attendee instanceof EE_Attendee
860
+			? $attendee->get_admin_details_link()
861
+			: '';
862
+		$attendee_link                                    = ! empty($attendee_link)
863
+			? '<a href="' . $attendee->get_admin_details_link() . '"'
864
+			. ' aria-label="' . esc_html__('Click for attendee details', 'event_espresso') . '">'
865
+			. '<span id="checkin-attendee-name">'
866
+			. $attendee_name
867
+			. '</span></a>'
868
+			: '';
869
+		$event_link                                       = $registration->event() instanceof EE_Event
870
+			? $registration->event()->get_admin_details_link()
871
+			: '';
872
+		$event_link                                       = ! empty($event_link)
873
+			? '<a href="' . $event_link . '"'
874
+			. ' aria-label="' . esc_html__('Click here to edit event.', 'event_espresso') . '">'
875
+			. '<span id="checkin-event-name">'
876
+			. $registration->event_name()
877
+			. '</span>'
878
+			. '</a>'
879
+			: '';
880
+		$this->_template_args['before_list_table']        = $REG_ID && $DTT_ID
881
+			? '<h2>' . sprintf(
882
+				esc_html__('Displaying check in records for %1$s for %2$s at the event, %3$s', 'event_espresso'),
883
+				$attendee_link,
884
+				$datetime_link,
885
+				$event_link
886
+			) . '</h2>'
887
+			: '';
888
+		$this->_template_args['list_table_hidden_fields'] = $REG_ID
889
+			? '<input type="hidden" name="_REG_ID" value="' . $REG_ID . '">'
890
+			: '';
891
+		$this->_template_args['list_table_hidden_fields'] .= $DTT_ID
892
+			? '<input type="hidden" name="DTT_ID" value="' . $DTT_ID . '">'
893
+			: '';
894
+		$this->display_admin_list_table_page_with_no_sidebar();
895
+	}
896
+
897
+
898
+	/**
899
+	 * toggle the Check-in status for the given registration (coming from ajax)
900
+	 *
901
+	 * @return void (JSON)
902
+	 * @throws EE_Error
903
+	 * @throws ReflectionException
904
+	 */
905
+	public function toggle_checkin_status()
906
+	{
907
+		if (! $this->capabilities->current_user_can('ee_edit_checkins', __FUNCTION__)) {
908
+			wp_die(esc_html__('You do not have the required privileges to perform this action', 'event_espresso'));
909
+		}
910
+		// first make sure we have the necessary data
911
+		if (! isset($this->_req_data['_regid'])) {
912
+			EE_Error::add_error(
913
+				esc_html__(
914
+					'There must be something broken with the html structure because the required data for toggling the Check-in status is not being sent via ajax',
915
+					'event_espresso'
916
+				),
917
+				__FILE__,
918
+				__FUNCTION__,
919
+				__LINE__
920
+			);
921
+			$this->_template_args['success'] = false;
922
+			$this->_template_args['error']   = true;
923
+			$this->_return_json();
924
+		}
925
+		// do a nonce check because we're not coming in from a normal route here.
926
+		$nonce     = isset($this->_req_data['checkinnonce']) ? sanitize_text_field($this->_req_data['checkinnonce'])
927
+			: '';
928
+		$nonce_ref = 'checkin_nonce';
929
+		$this->_verify_nonce($nonce, $nonce_ref);
930
+		// beautiful! Made it this far so let's get the status.
931
+		$new_status = new CheckinStatusDashicon($this->_toggle_checkin_status());
932
+		// setup new class to return via ajax
933
+		$this->_template_args['admin_page_content'] = 'clickable trigger-checkin ' . $new_status->cssClasses();
934
+		$this->_template_args['success']            = true;
935
+		$this->_return_json();
936
+	}
937
+
938
+
939
+	/**
940
+	 * handles toggling the checkin status for the registration,
941
+	 *
942
+	 * @return int|void
943
+	 * @throws EE_Error
944
+	 * @throws ReflectionException
945
+	 */
946
+	protected function _toggle_checkin_status()
947
+	{
948
+		$DTT_ID = $this->request->getRequestParam('DTT_ID', 0, DataType::INTEGER);
949
+		$DTT_ID = $this->request->getRequestParam('dttid', $DTT_ID, DataType::INTEGER);
950
+		$DTT_ID = $this->request->getRequestParam('datetime_id', $DTT_ID, DataType::INTEGER);
951
+		$_REG_ID = $this->request->getRequestParam('_regid', 0, DataType::INTEGER);
952
+		$checkboxes = $this->request->getRequestParam('checkbox', [], DataType::INTEGER, true);
953
+
954
+		$new_status = false;
955
+		// bulk action check in toggle
956
+		if (! empty($checkboxes)) {
957
+			foreach ($checkboxes as $REG_ID) {
958
+				$new_status = $this->_toggle_checkin($REG_ID, $DTT_ID);
959
+			}
960
+		} elseif ($_REG_ID) {
961
+			$new_status = $this->_toggle_checkin($_REG_ID, $DTT_ID);
962
+		} else {
963
+			EE_Error::add_error(
964
+				esc_html__('Missing some required data to toggle the Check-in', 'event_espresso'),
965
+				__FILE__,
966
+				__FUNCTION__,
967
+				__LINE__
968
+			);
969
+		}
970
+		if (defined('DOING_AJAX') && DOING_AJAX) {
971
+			return $new_status;
972
+		}
973
+		$EVT_ID = $this->request->getRequestParam('EVT_ID', 0, DataType::INTEGER);
974
+		$EVT_ID = $this->request->getRequestParam('event_id', $EVT_ID, DataType::INTEGER);
975
+		$redirect_args = [
976
+			'action' => 'event_registrations',
977
+			'EVT_ID' => $EVT_ID,
978
+			'DTT_ID' => $DTT_ID,
979
+		];
980
+		$this->_redirect_after_action(false, '', '', $redirect_args, true);
981
+	}
982
+
983
+
984
+	/**
985
+	 * This is toggles a single Check-in for the given registration and datetime.
986
+	 *
987
+	 * @param int $REG_ID The registration we're toggling
988
+	 * @param int $DTT_ID The datetime we're toggling
989
+	 * @return bool|int   the chk_in status toggled to OR false if nothing got changed.
990
+	 * @throws EE_Error
991
+	 * @throws ReflectionException
992
+	 */
993
+	private function _toggle_checkin(int $REG_ID, int $DTT_ID)
994
+	{
995
+		/** @var EE_Registration $REG */
996
+		$REG        = EEM_Registration::instance()->get_one_by_ID($REG_ID);
997
+		if (! $REG instanceof EE_Registration) {
998
+			EE_Error::add_error(
999
+				sprintf(
1000
+					esc_html__('There is no registration with ID (%d)', 'event_espresso'),
1001
+					$REG_ID
1002
+				),
1003
+				__FILE__,
1004
+				__FUNCTION__,
1005
+				__LINE__
1006
+			);
1007
+			return false;
1008
+		}
1009
+		$new_status = $REG->toggle_checkin_status($DTT_ID);
1010
+		if ($new_status !== false) {
1011
+			EE_Error::add_success($REG->get_checkin_msg($DTT_ID));
1012
+		} else {
1013
+			EE_Error::add_error($REG->get_checkin_msg($DTT_ID, true), __FILE__, __FUNCTION__, __LINE__);
1014
+			$new_status = false;
1015
+		}
1016
+		return $new_status;
1017
+	}
1018
+
1019
+
1020
+	/**
1021
+	 * Takes care of deleting multiple EE_Checkin table rows
1022
+	 *
1023
+	 * @return void
1024
+	 * @throws EE_Error
1025
+	 * @throws ReflectionException
1026
+	 */
1027
+	protected function _delete_checkin_rows()
1028
+	{
1029
+		$query_args = [
1030
+			'action'  => 'registration_checkins',
1031
+			'DTT_ID'  => $this->_req_data['DTT_ID'] ?? 0,
1032
+			'_REG_ID' => $this->_req_data['_REG_ID'] ?? 0,
1033
+		];
1034
+		$errors     = 0;
1035
+		if (! empty($this->_req_data['checkbox']) && is_array($this->_req_data['checkbox'])) {
1036
+			$checkboxes = $this->_req_data['checkbox'];
1037
+			foreach (array_keys($checkboxes) as $CHK_ID) {
1038
+				if (! EEM_Checkin::instance()->delete_by_ID($CHK_ID)) {
1039
+					$errors++;
1040
+				}
1041
+			}
1042
+		} else {
1043
+			EE_Error::add_error(
1044
+				esc_html__(
1045
+					'So, something went wrong with the bulk delete because there was no data received for instructions on WHAT to delete!',
1046
+					'event_espresso'
1047
+				),
1048
+				__FILE__,
1049
+				__FUNCTION__,
1050
+				__LINE__
1051
+			);
1052
+			$this->_redirect_after_action(false, '', '', $query_args, true);
1053
+		}
1054
+		if ($errors > 0) {
1055
+			EE_Error::add_error(
1056
+				sprintf(
1057
+					esc_html__('There were %d records that did not delete successfully', 'event_espresso'),
1058
+					$errors
1059
+				),
1060
+				__FILE__,
1061
+				__FUNCTION__,
1062
+				__LINE__
1063
+			);
1064
+		} else {
1065
+			EE_Error::add_success(esc_html__('Records were successfully deleted', 'event_espresso'));
1066
+		}
1067
+		$this->_redirect_after_action(false, '', '', $query_args, true);
1068
+	}
1069
+
1070
+
1071
+	/**
1072
+	 * Deletes a single EE_Checkin row
1073
+	 *
1074
+	 * @return void
1075
+	 * @throws EE_Error
1076
+	 * @throws ReflectionException
1077
+	 */
1078
+	protected function _delete_checkin_row()
1079
+	{
1080
+		$query_args = [
1081
+			'action'  => 'registration_checkins',
1082
+			'DTT_ID'  => $this->_req_data['DTT_ID'] ?? 0,
1083
+			'_REG_ID' => $this->_req_data['_REG_ID'] ?? 0,
1084
+		];
1085
+		if (! empty($this->_req_data['CHK_ID'])) {
1086
+			if (! EEM_Checkin::instance()->delete_by_ID($this->_req_data['CHK_ID'])) {
1087
+				EE_Error::add_error(
1088
+					esc_html__('Something went wrong and this check-in record was not deleted', 'event_espresso'),
1089
+					__FILE__,
1090
+					__FUNCTION__,
1091
+					__LINE__
1092
+				);
1093
+			} else {
1094
+				EE_Error::add_success(esc_html__('Check-In record successfully deleted', 'event_espresso'));
1095
+			}
1096
+		} else {
1097
+			EE_Error::add_error(
1098
+				esc_html__(
1099
+					'In order to delete a Check-in record, there must be a Check-In ID available. There is not. It is not your fault, there is just a gremlin living in the code',
1100
+					'event_espresso'
1101
+				),
1102
+				__FILE__,
1103
+				__FUNCTION__,
1104
+				__LINE__
1105
+			);
1106
+		}
1107
+		$this->_redirect_after_action(false, '', '', $query_args, true);
1108
+	}
1109
+
1110
+
1111
+	/**
1112
+	 * @return void
1113
+	 * @throws EE_Error
1114
+	 */
1115
+	protected function _event_registrations_list_table()
1116
+	{
1117
+		$EVT_ID                  = $this->request->getRequestParam('EVT_ID', 0, DataType::INTEGER);
1118
+		$this->_admin_page_title .= $EVT_ID
1119
+			? $this->get_action_link_or_button(
1120
+				'new_registration',
1121
+				'add-registrant',
1122
+				['event_id' => $EVT_ID],
1123
+				'add-new-h2'
1124
+			)
1125
+			: '';
1126
+
1127
+		$this->_template_args['before_list_table'] = $this->generateListTableHeaderText();
1128
+		$this->_template_args['after_list_table']  = $this->generateListTableLegend();
1129
+
1130
+		$this->display_admin_list_table_page_with_no_sidebar();
1131
+	}
1132
+
1133
+
1134
+	/**
1135
+	 * @return string
1136
+	 * @since 5.0.24.p
1137
+	 */
1138
+	private function generateListTableHeaderText(): string
1139
+	{
1140
+		$header_text                  = '';
1141
+		$admin_page_header_decorators = [
1142
+			'EventEspresso\core\domain\services\admin\registrations\list_table\page_header\AttendeeFilterHeader',
1143
+			'EventEspresso\core\domain\services\admin\registrations\list_table\page_header\EventFilterHeader',
1144
+			'EventEspresso\core\domain\services\admin\registrations\list_table\page_header\DateFilterHeader',
1145
+			'EventEspresso\core\domain\services\admin\registrations\list_table\page_header\TicketFilterHeader',
1146
+		];
1147
+		foreach ($admin_page_header_decorators as $admin_page_header_decorator) {
1148
+			$filter_header_decorator = $this->loader->getNew($admin_page_header_decorator);
1149
+			$header_text             = $filter_header_decorator->getHeaderText($header_text);
1150
+		}
1151
+		$header_text .= '
1152 1152
             <div class="description ee-status-outline ee-status-bg--info ee-status-outline--fit-content">
1153 1153
                 <strong>' . esc_html__(
1154
-            'In this view, the check-in status represents the latest check-in record for the registration in that row.',
1155
-            'event_espresso'
1156
-        ) . '</strong>
1154
+			'In this view, the check-in status represents the latest check-in record for the registration in that row.',
1155
+			'event_espresso'
1156
+		) . '</strong>
1157 1157
             </div>';
1158
-        return $header_text;
1159
-    }
1160
-
1161
-
1162
-    /**
1163
-     * @return string
1164
-     * @throws EE_Error
1165
-     * @since 5.0.24.p
1166
-     */
1167
-    private function generateListTableLegend(): string
1168
-    {
1169
-        $checked_in      = new CheckinStatusDashicon(EE_Checkin::status_checked_in);
1170
-        $checked_out     = new CheckinStatusDashicon(EE_Checkin::status_checked_out);
1171
-        $checked_never   = new CheckinStatusDashicon(EE_Checkin::status_checked_never);
1172
-        $checkin_invalid = new CheckinStatusDashicon(EE_Checkin::status_invalid);
1173
-
1174
-        $legend_items = [
1175
-            'star-icon'        => [
1176
-                'class' => 'dashicons dashicons-star-filled gold-icon',
1177
-                'desc'  => esc_html__('This Registrant is the Primary Registrant', 'event_espresso'),
1178
-            ],
1179
-            'checkin'          => [
1180
-                'class' => $checked_in->cssClasses(),
1181
-                'desc'  => $checked_in->legendLabel(),
1182
-            ],
1183
-            'checkout'         => [
1184
-                'class' => $checked_out->cssClasses(),
1185
-                'desc'  => $checked_out->legendLabel(),
1186
-            ],
1187
-            'nocheckinrecord'  => [
1188
-                'class' => $checked_never->cssClasses(),
1189
-                'desc'  => $checked_never->legendLabel(),
1190
-            ],
1191
-            'canNotCheckin'    => [
1192
-                'class' => $checkin_invalid->cssClasses(),
1193
-                'desc'  => $checkin_invalid->legendLabel(),
1194
-            ],
1195
-            'approved_status'  => [
1196
-                'class' => 'ee-status-legend ee-status-bg--' . RegStatus::APPROVED,
1197
-                'desc'  => EEH_Template::pretty_status(RegStatus::APPROVED, false, 'sentence'),
1198
-            ],
1199
-            'cancelled_status' => [
1200
-                'class' => 'ee-status-legend ee-status-bg--' . RegStatus::CANCELLED,
1201
-                'desc'  => EEH_Template::pretty_status(RegStatus::CANCELLED, false, 'sentence'),
1202
-            ],
1203
-            'declined_status'  => [
1204
-                'class' => 'ee-status-legend ee-status-bg--' . RegStatus::DECLINED,
1205
-                'desc'  => EEH_Template::pretty_status(RegStatus::DECLINED, false, 'sentence'),
1206
-            ],
1207
-            'not_approved'     => [
1208
-                'class' => 'ee-status-legend ee-status-bg--' . RegStatus::AWAITING_REVIEW,
1209
-                'desc'  => EEH_Template::pretty_status(RegStatus::AWAITING_REVIEW, false, 'sentence'),
1210
-            ],
1211
-            'pending_status'   => [
1212
-                'class' => 'ee-status-legend ee-status-bg--' . RegStatus::PENDING_PAYMENT,
1213
-                'desc'  => EEH_Template::pretty_status(RegStatus::PENDING_PAYMENT, false, 'sentence'),
1214
-            ],
1215
-            'wait_list'        => [
1216
-                'class' => 'ee-status-legend ee-status-bg--' . RegStatus::WAIT_LIST,
1217
-                'desc'  => EEH_Template::pretty_status(RegStatus::WAIT_LIST, false, 'sentence'),
1218
-            ],
1219
-        ];
1220
-        return $this->_display_legend($legend_items);
1221
-    }
1222
-
1223
-
1224
-    /**
1225
-     * Download the registrations check-in report (same as the normal registration report, but with different where
1226
-     * conditions)
1227
-     *
1228
-     * @return void ends the request by a redirect or download
1229
-     */
1230
-    public function _registrations_checkin_report()
1231
-    {
1232
-        $this->_registrations_report_base('_get_checkin_query_params_from_request');
1233
-    }
1234
-
1235
-
1236
-    /**
1237
-     * Gets the query params from the request, plus adds a where condition for the registration status,
1238
-     * because on the checkin page we only ever want to see approved and pending-approval registrations
1239
-     *
1240
-     * @param array $query_params
1241
-     * @param int   $per_page
1242
-     * @param bool  $count
1243
-     * @return array
1244
-     * @throws EE_Error
1245
-     */
1246
-    protected function _get_checkin_query_params_from_request(
1247
-        array $query_params,
1248
-        int $per_page = 10,
1249
-        bool $count = false
1250
-    ): array {
1251
-        $query_params = $this->_get_registration_query_parameters($query_params, $per_page, $count);
1252
-        // unlike the regular registrations list table,
1253
-        $status_ids_array          = apply_filters(
1254
-            'FHEE__Extend_Registrations_Admin_Page__get_event_attendees__status_ids_array',
1255
-            [RegStatus::PENDING_PAYMENT, RegStatus::APPROVED]
1256
-        );
1257
-        $query_params[0]['STS_ID'] = ['IN', $status_ids_array];
1258
-        return $query_params;
1259
-    }
1260
-
1261
-
1262
-    /**
1263
-     * Gets registrations for an event
1264
-     *
1265
-     * @param int    $per_page
1266
-     * @param bool   $count whether to return count or data.
1267
-     * @param bool   $trash
1268
-     * @param string $orderby
1269
-     * @return EE_Registration[]|int
1270
-     * @throws EE_Error
1271
-     * @throws ReflectionException
1272
-     */
1273
-    public function get_event_attendees(
1274
-        int $per_page = 10,
1275
-        bool $count = false,
1276
-        bool $trash = false,
1277
-        string $orderby = 'ATT_fname'
1278
-    ) {
1279
-        // set some defaults, these will get overridden if included in the actual request parameters
1280
-        $defaults = [
1281
-            'orderby' => $orderby,
1282
-            'order'   => 'ASC',
1283
-        ];
1284
-        if ($trash) {
1285
-            $defaults['status'] = 'trash';
1286
-        }
1287
-        $query_params = $this->_get_checkin_query_params_from_request($defaults, $per_page, $count);
1288
-
1289
-        /**
1290
-         * Override the default groupby added by EEM_Base so that sorts with multiple order bys work as expected
1291
-         *
1292
-         * @link https://events.codebasehq.com/projects/event-espresso/tickets/10093
1293
-         * @see  https://github.com/eventespresso/event-espresso-core/tree/master/docs/G--Model-System/model-query-params.md
1294
-         *                             or if you have the development copy of EE you can view this at the path:
1295
-         *                             /docs/G--Model-System/model-query-params.md
1296
-         */
1297
-        $query_params['group_by'] = '';
1298
-
1299
-        return $count
1300
-            ? EEM_Registration::instance()->count($query_params)
1301
-            /** @type EE_Registration[] */
1302
-            : EEM_Registration::instance()->get_all($query_params);
1303
-    }
1158
+		return $header_text;
1159
+	}
1160
+
1161
+
1162
+	/**
1163
+	 * @return string
1164
+	 * @throws EE_Error
1165
+	 * @since 5.0.24.p
1166
+	 */
1167
+	private function generateListTableLegend(): string
1168
+	{
1169
+		$checked_in      = new CheckinStatusDashicon(EE_Checkin::status_checked_in);
1170
+		$checked_out     = new CheckinStatusDashicon(EE_Checkin::status_checked_out);
1171
+		$checked_never   = new CheckinStatusDashicon(EE_Checkin::status_checked_never);
1172
+		$checkin_invalid = new CheckinStatusDashicon(EE_Checkin::status_invalid);
1173
+
1174
+		$legend_items = [
1175
+			'star-icon'        => [
1176
+				'class' => 'dashicons dashicons-star-filled gold-icon',
1177
+				'desc'  => esc_html__('This Registrant is the Primary Registrant', 'event_espresso'),
1178
+			],
1179
+			'checkin'          => [
1180
+				'class' => $checked_in->cssClasses(),
1181
+				'desc'  => $checked_in->legendLabel(),
1182
+			],
1183
+			'checkout'         => [
1184
+				'class' => $checked_out->cssClasses(),
1185
+				'desc'  => $checked_out->legendLabel(),
1186
+			],
1187
+			'nocheckinrecord'  => [
1188
+				'class' => $checked_never->cssClasses(),
1189
+				'desc'  => $checked_never->legendLabel(),
1190
+			],
1191
+			'canNotCheckin'    => [
1192
+				'class' => $checkin_invalid->cssClasses(),
1193
+				'desc'  => $checkin_invalid->legendLabel(),
1194
+			],
1195
+			'approved_status'  => [
1196
+				'class' => 'ee-status-legend ee-status-bg--' . RegStatus::APPROVED,
1197
+				'desc'  => EEH_Template::pretty_status(RegStatus::APPROVED, false, 'sentence'),
1198
+			],
1199
+			'cancelled_status' => [
1200
+				'class' => 'ee-status-legend ee-status-bg--' . RegStatus::CANCELLED,
1201
+				'desc'  => EEH_Template::pretty_status(RegStatus::CANCELLED, false, 'sentence'),
1202
+			],
1203
+			'declined_status'  => [
1204
+				'class' => 'ee-status-legend ee-status-bg--' . RegStatus::DECLINED,
1205
+				'desc'  => EEH_Template::pretty_status(RegStatus::DECLINED, false, 'sentence'),
1206
+			],
1207
+			'not_approved'     => [
1208
+				'class' => 'ee-status-legend ee-status-bg--' . RegStatus::AWAITING_REVIEW,
1209
+				'desc'  => EEH_Template::pretty_status(RegStatus::AWAITING_REVIEW, false, 'sentence'),
1210
+			],
1211
+			'pending_status'   => [
1212
+				'class' => 'ee-status-legend ee-status-bg--' . RegStatus::PENDING_PAYMENT,
1213
+				'desc'  => EEH_Template::pretty_status(RegStatus::PENDING_PAYMENT, false, 'sentence'),
1214
+			],
1215
+			'wait_list'        => [
1216
+				'class' => 'ee-status-legend ee-status-bg--' . RegStatus::WAIT_LIST,
1217
+				'desc'  => EEH_Template::pretty_status(RegStatus::WAIT_LIST, false, 'sentence'),
1218
+			],
1219
+		];
1220
+		return $this->_display_legend($legend_items);
1221
+	}
1222
+
1223
+
1224
+	/**
1225
+	 * Download the registrations check-in report (same as the normal registration report, but with different where
1226
+	 * conditions)
1227
+	 *
1228
+	 * @return void ends the request by a redirect or download
1229
+	 */
1230
+	public function _registrations_checkin_report()
1231
+	{
1232
+		$this->_registrations_report_base('_get_checkin_query_params_from_request');
1233
+	}
1234
+
1235
+
1236
+	/**
1237
+	 * Gets the query params from the request, plus adds a where condition for the registration status,
1238
+	 * because on the checkin page we only ever want to see approved and pending-approval registrations
1239
+	 *
1240
+	 * @param array $query_params
1241
+	 * @param int   $per_page
1242
+	 * @param bool  $count
1243
+	 * @return array
1244
+	 * @throws EE_Error
1245
+	 */
1246
+	protected function _get_checkin_query_params_from_request(
1247
+		array $query_params,
1248
+		int $per_page = 10,
1249
+		bool $count = false
1250
+	): array {
1251
+		$query_params = $this->_get_registration_query_parameters($query_params, $per_page, $count);
1252
+		// unlike the regular registrations list table,
1253
+		$status_ids_array          = apply_filters(
1254
+			'FHEE__Extend_Registrations_Admin_Page__get_event_attendees__status_ids_array',
1255
+			[RegStatus::PENDING_PAYMENT, RegStatus::APPROVED]
1256
+		);
1257
+		$query_params[0]['STS_ID'] = ['IN', $status_ids_array];
1258
+		return $query_params;
1259
+	}
1260
+
1261
+
1262
+	/**
1263
+	 * Gets registrations for an event
1264
+	 *
1265
+	 * @param int    $per_page
1266
+	 * @param bool   $count whether to return count or data.
1267
+	 * @param bool   $trash
1268
+	 * @param string $orderby
1269
+	 * @return EE_Registration[]|int
1270
+	 * @throws EE_Error
1271
+	 * @throws ReflectionException
1272
+	 */
1273
+	public function get_event_attendees(
1274
+		int $per_page = 10,
1275
+		bool $count = false,
1276
+		bool $trash = false,
1277
+		string $orderby = 'ATT_fname'
1278
+	) {
1279
+		// set some defaults, these will get overridden if included in the actual request parameters
1280
+		$defaults = [
1281
+			'orderby' => $orderby,
1282
+			'order'   => 'ASC',
1283
+		];
1284
+		if ($trash) {
1285
+			$defaults['status'] = 'trash';
1286
+		}
1287
+		$query_params = $this->_get_checkin_query_params_from_request($defaults, $per_page, $count);
1288
+
1289
+		/**
1290
+		 * Override the default groupby added by EEM_Base so that sorts with multiple order bys work as expected
1291
+		 *
1292
+		 * @link https://events.codebasehq.com/projects/event-espresso/tickets/10093
1293
+		 * @see  https://github.com/eventespresso/event-espresso-core/tree/master/docs/G--Model-System/model-query-params.md
1294
+		 *                             or if you have the development copy of EE you can view this at the path:
1295
+		 *                             /docs/G--Model-System/model-query-params.md
1296
+		 */
1297
+		$query_params['group_by'] = '';
1298
+
1299
+		return $count
1300
+			? EEM_Registration::instance()->count($query_params)
1301
+			/** @type EE_Registration[] */
1302
+			: EEM_Registration::instance()->get_all($query_params);
1303
+	}
1304 1304
 }
Please login to merge, or discard this patch.
core/admin/EE_Admin_Page.core.php 2 patches
Indentation   +4237 added lines, -4237 removed lines patch added patch discarded remove patch
@@ -24,4333 +24,4333 @@
 block discarded – undo
24 24
  */
25 25
 abstract class EE_Admin_Page extends EE_Base implements InterminableInterface
26 26
 {
27
-    protected ?EE_Admin_Config $admin_config       = null;
27
+	protected ?EE_Admin_Config $admin_config       = null;
28 28
 
29
-    protected ?EE_Admin_Hooks $_hook_obj          = null;
29
+	protected ?EE_Admin_Hooks $_hook_obj          = null;
30 30
 
31
-    protected ?EE_Admin_List_Table $_list_table_object = null;
31
+	protected ?EE_Admin_List_Table $_list_table_object = null;
32 32
 
33
-    protected ?EE_Capabilities $capabilities       = null;
33
+	protected ?EE_Capabilities $capabilities       = null;
34 34
 
35
-    protected ?EE_Registry $EE                 = null;
35
+	protected ?EE_Registry $EE                 = null;
36 36
 
37
-    protected ?FeatureFlags $feature            = null;
37
+	protected ?FeatureFlags $feature            = null;
38 38
 
39
-    protected ?LoaderInterface $loader             = null;
39
+	protected ?LoaderInterface $loader             = null;
40 40
 
41
-    protected ?RequestInterface $request            = null;
41
+	protected ?RequestInterface $request            = null;
42 42
 
43
-    protected ?WP_Screen $_current_screen    = null;
44
-
45
-    /**
46
-     * @var array
47
-     * @since 5.0.0.p
48
-     */
49
-    private array $publish_post_meta_box_hidden_fields = [];
50
-
51
-    /**
52
-     * some default things shared by all child classes
53
-     *
54
-     * @var string[]
55
-     */
56
-    protected array $_default_espresso_metaboxes = [
57
-        '_espresso_news_post_box',
58
-        '_espresso_links_post_box',
59
-        '_espresso_ratings_request',
60
-        '_espresso_sponsors_post_box',
61
-    ];
62
-
63
-    /**
64
-     * Used to hold default query args for list table routes to help preserve stickiness of filters for carried out
65
-     * actions.
66
-     *
67
-     * @since 4.6.x
68
-     */
69
-    protected array $_default_route_query_args = [];
70
-
71
-    protected array $_labels                   = [];
72
-
73
-    protected array $_nav_tabs                 = [];
74
-
75
-    protected array $_page_config              = [];
76
-
77
-    /**
78
-     * action => method pairs used for routing incoming requests
79
-     *
80
-     * @var array
81
-     */
82
-    protected array $_page_routes   = [];
83
-
84
-    protected array $_req_data      = [];
85
-
86
-    protected array $_route_config  = [];
87
-
88
-    protected array $_template_args = [];
89
-
90
-    protected array $_views         = [];
91
-
92
-    /**
93
-     * yes / no array for admin form fields
94
-     *
95
-     * @var array|array[]
96
-     */
97
-    protected array $_yes_no_values = [];
98
-
99
-    /**
100
-     * this starts at null so we can have no header routes progress through two states.
101
-     */
102
-    protected ?bool $_is_UI_request = null;
103
-
104
-    /**
105
-     * flags whether the given route is a caffeinated route or not.
106
-     */
107
-    protected bool $_is_caf        = false;
108
-
109
-    protected bool $_routing       = false;
110
-
111
-    /**
112
-     * whether initializePage() has run
113
-     *
114
-     * @var bool
115
-     */
116
-    protected bool $initialized = false;
117
-
118
-
119
-    protected string $_admin_base_path      = '';
120
-
121
-    protected string $_admin_base_url       = '';
122
-
123
-    protected string $_admin_page_title     = '';
124
-
125
-    protected string $_column_template_path = '';
126
-
127
-    protected bool $_cpt_route            = false;
128
-
129
-    /**
130
-     * set via request page and action args.
131
-     */
132
-    protected string $_current_page          = '';
133
-
134
-    protected string $_current_page_view_url = '';
135
-
136
-    protected string $_current_view          = '';
137
-
138
-    protected string $_default_nav_tab_name  = 'overview';
139
-
140
-    /**
141
-     * sanitized request action
142
-     */
143
-    protected string $_req_action = '';
144
-
145
-    /**
146
-     * sanitized request action nonce
147
-     */
148
-    protected string $_req_nonce        = '';
149
-
150
-    protected string $_search_btn_label = '';
151
-
152
-    protected string $_template_path    = '';
153
-
154
-    protected string $_view             = '';
155
-
156
-    /**
157
-     * set early within EE_Admin_Init
158
-     *
159
-     * @var string
160
-     */
161
-    protected string $_wp_page_slug = '';
162
-
163
-    /**
164
-     * if the current class is an admin page extension, like: Extend_Events_Admin_Page,
165
-     * then this would be the parent classname: Events_Admin_Page
166
-     *
167
-     * @var string
168
-     */
169
-    public string $base_class_name = '';
170
-
171
-    public string $class_name      = '';
172
-
173
-    /**
174
-     * unprocessed value for the 'action' request param (default '')
175
-     *
176
-     * @var string
177
-     */
178
-    protected string $raw_req_action = '';
179
-
180
-    /**
181
-     * unprocessed value for the 'page' request param (default '')
182
-     *
183
-     * @var string
184
-     */
185
-    protected string $raw_req_page = '';
186
-
187
-    public string $page_folder  = '';
188
-
189
-    public string $page_label   = '';
190
-
191
-    public string $page_slug    = '';
192
-
193
-
194
-    /**
195
-     * the current page route and route config
196
-     *
197
-     * @var array|callable|string|null
198
-     */
199
-    protected $_route = null;
200
-
201
-
202
-    /**
203
-     * @Constructor
204
-     * @param bool $routing indicate whether we want to just load the object and handle routing or just load the object.
205
-     * @throws InvalidArgumentException
206
-     * @throws InvalidDataTypeException
207
-     * @throws InvalidInterfaceException
208
-     * @throws ReflectionException
209
-     */
210
-    public function __construct($routing = true)
211
-    {
212
-        $this->_routing = $routing;
213
-
214
-        $this->loader       = LoaderFactory::getLoader();
215
-        $this->admin_config = $this->loader->getShared(EE_Admin_Config::class);
216
-        $this->feature      = $this->loader->getShared(FeatureFlags::class);
217
-        $this->request      = $this->loader->getShared(RequestInterface::class);
218
-        $this->capabilities = $this->loader->getShared(EE_Capabilities::class);
219
-
220
-        $this->class_name      = get_class($this);
221
-        $this->base_class_name = strpos($this->class_name, 'Extend_') === 0
222
-            ? str_replace('Extend_', '', $this->class_name)
223
-            : '';
224
-
225
-        if (strpos($this->_get_dir(), 'caffeinated') !== false) {
226
-            $this->_is_caf = true;
227
-        }
228
-        $this->_yes_no_values = [
229
-            ['id' => true, 'text' => esc_html__('Yes', 'event_espresso')],
230
-            ['id' => false, 'text' => esc_html__('No', 'event_espresso')],
231
-        ];
232
-        // set the _req_data property.
233
-        $this->_req_data = $this->request->requestParams();
234
-    }
235
-
236
-
237
-    /**
238
-     * @return EE_Admin_Config
239
-     */
240
-    public function adminConfig(): EE_Admin_Config
241
-    {
242
-        return $this->admin_config;
243
-    }
244
-
245
-
246
-    public function capabilities(): EE_Capabilities
247
-    {
248
-        if (! $this->capabilities instanceof EE_Capabilities) {
249
-            $this->capabilities = $this->loader->getShared(EE_Capabilities::class);
250
-        }
251
-        return $this->capabilities;
252
-    }
253
-
254
-
255
-    /**
256
-     * @return FeatureFlags
257
-     */
258
-    public function feature(): FeatureFlags
259
-    {
260
-        return $this->feature;
261
-    }
262
-
263
-
264
-    /**
265
-     * This logic used to be in the constructor, but that caused a chicken <--> egg scenario
266
-     * for child classes that needed to set properties prior to these methods getting called,
267
-     * but also needed the parent class to have its construction completed as well.
268
-     * Bottom line is that constructors should ONLY be used for setting initial properties
269
-     * and any complex initialization logic should only run after instantiation is complete.
270
-     * This method gets called immediately after construction from within
271
-     *      EE_Admin_Page_Init::_initialize_admin_page()
272
-     *
273
-     * @throws EE_Error
274
-     * @throws InvalidArgumentException
275
-     * @throws InvalidDataTypeException
276
-     * @throws InvalidInterfaceException
277
-     * @throws ReflectionException
278
-     * @throws Throwable
279
-     * @since 5.0.0.p
280
-     */
281
-    public function initializePage()
282
-    {
283
-        if ($this->initialized) {
284
-            return;
285
-        }
286
-        // set initial page props (child method)
287
-        $this->_init_page_props();
288
-        // set global defaults
289
-        $this->_set_defaults();
290
-        // set early because incoming requests could be ajax related and we need to register those hooks.
291
-        if ($this->request->isAjax()) {
292
-            $this->_global_ajax_hooks();
293
-            $this->_ajax_hooks();
294
-        }
295
-        // other_page_hooks have to be early too.
296
-        $this->_do_other_page_hooks();
297
-        // set up page dependencies
298
-        $this->_before_page_setup();
299
-        $this->_page_setup();
300
-        $this->initialized = true;
301
-    }
302
-
303
-
304
-    /**
305
-     * _init_page_props
306
-     * Child classes use to set at least the following properties:
307
-     * $page_slug.
308
-     * $page_label.
309
-     *
310
-     * @abstract
311
-     * @return void
312
-     */
313
-    abstract protected function _init_page_props();
314
-
315
-
316
-    /**
317
-     * _ajax_hooks
318
-     * child classes put all their add_action('wp_ajax_{name_of_hook}') hooks in here.
319
-     * Note: within the ajax callback methods.
320
-     *
321
-     * @abstract
322
-     * @return void
323
-     */
324
-    abstract protected function _ajax_hooks();
325
-
326
-
327
-    /**
328
-     * _define_page_props
329
-     * child classes define page properties in here.  Must include at least:
330
-     * $_admin_base_url = base_url for all admin pages
331
-     * $_admin_page_title = default admin_page_title for admin pages
332
-     * $_labels = array of default labels for various automatically generated elements:
333
-     *    array(
334
-     *        'buttons' => array(
335
-     *            'add' => esc_html__('label for add new button'),
336
-     *            'edit' => esc_html__('label for edit button'),
337
-     *            'delete' => esc_html__('label for delete button')
338
-     *            )
339
-     *        )
340
-     *
341
-     * @abstract
342
-     * @return void
343
-     */
344
-    abstract protected function _define_page_props();
345
-
346
-
347
-    /**
348
-     * _set_page_routes
349
-     * child classes use this to define the page routes for all subpages handled by the class.  Page routes are
350
-     * assigned to an action => method pairs in an array and to the $_page_routes property.  Each page route must also
351
-     * have a 'default' route. Here's the format
352
-     * $this->_page_routes = array(
353
-     *        'default' => array(
354
-     *            'func' => '_default_method_handling_route',
355
-     *            'args' => array('array','of','args'),
356
-     *            'noheader' => true, //add this in if this page route is processed before any headers are loaded (i.e.
357
-     *            ajax request, backend processing)
358
-     *            'headers_sent_route'=>'headers_route_reference', //add this if noheader=>true, and you want to load a
359
-     *            headers route after.  The string you enter here should match the defined route reference for a
360
-     *            headers sent route.
361
-     *            'capability' => 'route_capability', //indicate a string for minimum capability required to access
362
-     *            this route.
363
-     *            'obj_id' => 10 // if this route has an object id, then this can include it (used for capability
364
-     *            checks).
365
-     *        ),
366
-     *        'insert_item' => '_method_for_handling_insert_item' //this can be used if all we need to have is a
367
-     *        handling method.
368
-     *        )
369
-     * )
370
-     *
371
-     * @abstract
372
-     * @return void
373
-     */
374
-    abstract protected function _set_page_routes();
375
-
376
-
377
-    /**
378
-     * _set_page_config
379
-     * child classes use this to define the _page_config array for all subpages handled by the class. Each key in the
380
-     * array corresponds to the page_route for the loaded page. Format:
381
-     * $this->_page_config = array(
382
-     *        'default' => array(
383
-     *            'labels' => array(
384
-     *                'buttons' => array(
385
-     *                    'add' => esc_html__('label for adding item'),
386
-     *                    'edit' => esc_html__('label for editing item'),
387
-     *                    'delete' => esc_html__('label for deleting item')
388
-     *                ),
389
-     *                'publishbox' => esc_html__('Localized Title for Publish metabox', 'event_espresso')
390
-     *            ), //optional an array of custom labels for various automatically generated elements to use on the
391
-     *            page. If this isn't present then the defaults will be used as set for the $this->_labels in
392
-     *            _define_page_props() method
393
-     *            'nav' => array(
394
-     *                'label' => esc_html__('Label for Tab', 'event_espresso').
395
-     *                'url' => 'http://someurl', //automatically generated UNLESS you define
396
-     *                'css_class' => 'css-class', //automatically generated UNLESS you define
397
-     *                'order' => 10, //required to indicate tab position.
398
-     *                'persistent' => false //if you want the nav tab to ONLY display when the specific route is
399
-     *                displayed then add this parameter.
400
-     *            'list_table' => 'name_of_list_table' //string for list table class to be loaded for this admin_page.
401
-     *            'metaboxes' => array('metabox1', 'metabox2'), //if present this key indicates we want to load
402
-     *            metaboxes set for eventespresso admin pages.
403
-     *            'has_metaboxes' => true, //this boolean flag can simply be used to indicate if the route will have
404
-     *            metaboxes.  Typically this is used if the 'metaboxes' index is not used because metaboxes are added
405
-     *            later.  We just use this flag to make sure the necessary js gets enqueued on page load.
406
-     *            'has_help_popups' => false //defaults(true) //this boolean flag can simply be used to indicate if the
407
-     *            given route has help popups setup and if it does then we need to make sure thickbox is enqueued.
408
-     *            'columns' => array(4, 2), //this key triggers the setup of a page that uses columns (metaboxes).  The
409
-     *            array indicates the max number of columns (4) and the default number of columns on page load (2).
410
-     *            There is an option in the "screen_options" dropdown that is set up so users can pick what columns they
411
-     *            want to display.
412
-     *            'help_tabs' => array( //this is used for adding help tabs to a page
413
-     *                'tab_id' => array(
414
-     *                    'title' => 'tab_title',
415
-     *                    'filename' => 'name_of_file_containing_content', //this is the primary method for setting
416
-     *                    help tab content.  The fallback if it isn't present is to try the callback.  Filename
417
-     *                    should match a file in the admin folder's "help_tabs" dir (ie..
418
-     *                    events/help_tabs/name_of_file_containing_content.help_tab.php)
419
-     *                    'callback' => 'callback_method_for_content', //if 'filename' isn't present then system will
420
-     *                    attempt to use the callback which should match the name of a method in the class
421
-     *                    ),
422
-     *                'tab2_id' => array(
423
-     *                    'title' => 'tab2 title',
424
-     *                    'filename' => 'file_name_2'
425
-     *                    'callback' => 'callback_method_for_content',
426
-     *                 ),
427
-     *            'help_sidebar' => 'callback_for_sidebar_content', //this is used for setting up the sidebar in the
428
-     *            help tab area on an admin page. @return void
429
-     *
430
-     * @abstract
431
-     */
432
-    abstract protected function _set_page_config();
433
-
434
-
435
-    /**
436
-     * _add_screen_options
437
-     * Child classes can add any extra wp_screen_options within this method using built-in WP functions/methods for
438
-     * doing so. Note child classes can also define _add_screen_options_($this->_current_view) to limit screen options
439
-     * to a particular view.
440
-     *
441
-     * @link   http://chrismarslender.com/wp-tutorials/wordpress-screen-options-tutorial/
442
-     *         see also WP_Screen object documents...
443
-     * @link   http://codex.wordpress.org/Class_Reference/WP_Screen
444
-     * @abstract
445
-     * @return void
446
-     */
447
-    abstract protected function _add_screen_options();
448
-
449
-
450
-    /**
451
-     * _add_feature_pointers
452
-     * Child classes should use this method for implementing any "feature pointers" (using built-in WP styling js).
453
-     * Note child classes can also define _add_feature_pointers_($this->_current_view) to limit screen options to a
454
-     * particular view. Note: this is just a placeholder for now.  Implementation will come down the road See:
455
-     * WP_Internal_Pointers class in wp-admin/includes/template.php for example (it's a final class so can't be
456
-     * extended) also see:
457
-     *
458
-     * @link   http://eamann.com/tech/wordpress-portland/
459
-     * @abstract
460
-     * @return void
461
-     */
462
-    abstract protected function _add_feature_pointers();
463
-
464
-
465
-    /**
466
-     * load_scripts_styles
467
-     * child classes put their wp_enqueue_script and wp_enqueue_style hooks in here for anything they need loaded for
468
-     * their pages/subpages.  Note this is for all pages/subpages of the system.  You can also load only specific
469
-     * scripts/styles per view by putting them in a dynamic function in this format
470
-     * (load_scripts_styles_{$this->_current_view}) which matches your page route (action request arg)
471
-     *
472
-     * @abstract
473
-     * @return void
474
-     */
475
-    abstract public function load_scripts_styles();
476
-
477
-
478
-    /**
479
-     * admin_init
480
-     * Anything that should be set/executed at 'admin_init' WP hook runtime should be put in here.  This will apply to
481
-     * all pages/views loaded by child class.
482
-     *
483
-     * @abstract
484
-     * @return void
485
-     */
486
-    abstract public function admin_init();
487
-
488
-
489
-    /**
490
-     * admin_notices
491
-     * Anything triggered by the 'admin_notices' WP hook should be put in here.  This particular method will apply to
492
-     * all pages/views loaded by child class.
493
-     *
494
-     * @abstract
495
-     * @return void
496
-     */
497
-    abstract public function admin_notices();
498
-
499
-
500
-    /**
501
-     * admin_footer_scripts
502
-     * Anything triggered by the 'admin_print_footer_scripts' WP hook should be put in here. This particular method
503
-     * will apply to all pages/views loaded by child class.
504
-     *
505
-     * @return void
506
-     */
507
-    abstract public function admin_footer_scripts();
508
-
509
-
510
-    /**
511
-     * admin_footer
512
-     * anything triggered by the 'admin_footer' WP action hook should be added to here. This particular method will
513
-     * apply to all pages/views loaded by child class.
514
-     *
515
-     * @return void
516
-     */
517
-    public function admin_footer()
518
-    {
519
-    }
43
+	protected ?WP_Screen $_current_screen    = null;
520 44
 
45
+	/**
46
+	 * @var array
47
+	 * @since 5.0.0.p
48
+	 */
49
+	private array $publish_post_meta_box_hidden_fields = [];
521 50
 
522
-    /**
523
-     * _global_ajax_hooks
524
-     * all global add_action('wp_ajax_{name_of_hook}') hooks in here.
525
-     * Note: within the ajax callback methods.
526
-     *
527
-     * @abstract
528
-     * @return void
529
-     */
530
-    protected function _global_ajax_hooks()
531
-    {
532
-        // for lazy loading of metabox content
533
-        add_action('wp_ajax_espresso-ajax-content', [$this, 'ajax_metabox_content']);
534
-
535
-        add_action(
536
-            'wp_ajax_espresso_hide_status_change_notice',
537
-            [$this, 'hideStatusChangeNotice']
538
-        );
539
-        add_action(
540
-            'wp_ajax_nopriv_espresso_hide_status_change_notice',
541
-            [$this, 'hideStatusChangeNotice']
542
-        );
543
-    }
544
-
545
-
546
-    public function ajax_metabox_content()
547
-    {
548
-        $content_id  = $this->request->getRequestParam('contentid', '');
549
-        $content_url = $this->request->getRequestParam('contenturl', '', DataType::URL);
550
-        EE_Admin_Page::cached_rss_display($content_id, $content_url);
551
-        wp_die();
552
-    }
553
-
554
-
555
-    public function hideStatusChangeNotice()
556
-    {
557
-        $response = [];
558
-        try {
559
-            /** @var StatusChangeNotice $status_change_notice */
560
-            $status_change_notice = $this->loader->getShared(
561
-                'EventEspresso\core\domain\services\admin\notices\status_change\StatusChangeNotice'
562
-            );
563
-            $response['success']  = $status_change_notice->dismiss() > -1;
564
-        } catch (Exception $exception) {
565
-            $response['errors'] = $exception->getMessage();
566
-        }
567
-        wp_send_json($response);
568
-    }
51
+	/**
52
+	 * some default things shared by all child classes
53
+	 *
54
+	 * @var string[]
55
+	 */
56
+	protected array $_default_espresso_metaboxes = [
57
+		'_espresso_news_post_box',
58
+		'_espresso_links_post_box',
59
+		'_espresso_ratings_request',
60
+		'_espresso_sponsors_post_box',
61
+	];
569 62
 
63
+	/**
64
+	 * Used to hold default query args for list table routes to help preserve stickiness of filters for carried out
65
+	 * actions.
66
+	 *
67
+	 * @since 4.6.x
68
+	 */
69
+	protected array $_default_route_query_args = [];
570 70
 
571
-    /**
572
-     * allows extending classes do something specific before the parent constructor runs _page_setup().
573
-     *
574
-     * @return void
575
-     */
576
-    protected function _before_page_setup()
577
-    {
578
-        // default is to do nothing
579
-    }
71
+	protected array $_labels                   = [];
580 72
 
73
+	protected array $_nav_tabs                 = [];
581 74
 
582
-    /**
583
-     * Makes sure any things that need to be loaded early get handled.
584
-     * We also escape early here if the page requested doesn't match the object.
585
-     *
586
-     * @final
587
-     * @return void
588
-     * @throws EE_Error
589
-     * @throws InvalidArgumentException
590
-     * @throws ReflectionException
591
-     * @throws InvalidDataTypeException
592
-     * @throws InvalidInterfaceException
593
-     * @throws Throwable
594
-     */
595
-    final protected function _page_setup()
596
-    {
597
-        // requires?
598
-        // admin_init stuff - global - we're setting this REALLY early
599
-        // so if EE_Admin pages have to hook into other WP pages they can.
600
-        // But keep in mind, not everything is available from the EE_Admin Page object at this point.
601
-        add_action('admin_init', [$this, 'admin_init_global'], 5);
602
-        // next verify if we need to load anything...
603
-        $this->_current_page = $this->request->getRequestParam('page', '', DataType::KEY);
604
-        $this->_current_page = $this->request->getRequestParam('current_page', $this->_current_page, DataType::KEY);
605
-        $this->page_folder   = strtolower(
606
-            str_replace(['_Admin_Page', 'Extend_'], '', $this->class_name)
607
-        );
608
-        global $ee_menu_slugs;
609
-        $ee_menu_slugs = (array) $ee_menu_slugs;
610
-        if (
611
-            ! $this->request->isAjax()
612
-            && (! $this->_current_page || ! isset($ee_menu_slugs[ $this->_current_page ]))
613
-        ) {
614
-            return;
615
-        }
616
-        // because WP List tables have two duplicate select inputs for choosing bulk actions,
617
-        // we need to copy the action from the second to the first
618
-        $action     = $this->request->getRequestParam('action', '-1', DataType::KEY);
619
-        $action2    = $this->request->getRequestParam('action2', '-1', DataType::KEY);
620
-        $action     = $action !== '-1' ? $action : $action2;
621
-        $req_action = $action !== '-1' ? $action : 'default';
622
-
623
-        // if a specific 'route' has been set, and the action is 'default' OR we are doing_ajax
624
-        // then let's use the route as the action.
625
-        // This covers cases where we're coming in from a list table that isn't on the default route.
626
-        $route = $this->request->getRequestParam('route');
627
-        $route = $route !== '-1' ? $route : 'default';
628
-        $this->_req_action = $route && ($req_action === 'default' || $this->request->isAjax())
629
-            ? $route
630
-            : $req_action;
631
-        $this->_current_view = $this->_req_action;
632
-        $this->_req_nonce    = $this->_req_action . '_nonce';
633
-        $this->_define_page_props();
634
-        $this->_current_page_view_url = add_query_arg(
635
-            ['page' => $this->_current_page, 'action' => $this->_current_view],
636
-            $this->_admin_base_url
637
-        );
638
-        // set page configs
639
-        $this->_set_page_routes();
640
-        $this->_set_page_config();
641
-        // let's include any referrer data in our default_query_args for this route for "stickiness".
642
-        if ($this->request->requestParamIsSet('wp_referer')) {
643
-            $wp_referer = $this->request->getRequestParam('wp_referer');
644
-            if ($wp_referer) {
645
-                $this->_default_route_query_args['wp_referer'] = $wp_referer;
646
-            }
647
-        }
648
-        // for CPT and other extended functionality.
649
-        // If there is an _extend_page_config_for_cpt
650
-        // then let's run that to modify all the various page configuration arrays.
651
-        if (method_exists($this, '_extend_page_config_for_cpt')) {
652
-            $this->_extend_page_config_for_cpt();
653
-        }
654
-        // filter routes and page_config so addons can add their stuff. Filtering done per class
655
-        $this->_page_routes = apply_filters(
656
-            'FHEE__' . $this->class_name . '__page_setup__page_routes',
657
-            $this->_page_routes,
658
-            $this
659
-        );
660
-        $this->_page_config = apply_filters(
661
-            'FHEE__' . $this->class_name . '__page_setup__page_config',
662
-            $this->_page_config,
663
-            $this
664
-        );
665
-        if ($this->base_class_name !== '') {
666
-            $this->_page_routes = apply_filters(
667
-                'FHEE__' . $this->base_class_name . '__page_setup__page_routes',
668
-                $this->_page_routes,
669
-                $this
670
-            );
671
-            $this->_page_config = apply_filters(
672
-                'FHEE__' . $this->base_class_name . '__page_setup__page_config',
673
-                $this->_page_config,
674
-                $this
675
-            );
676
-        }
677
-        // if AHEE__EE_Admin_Page__route_admin_request_$this->_current_view method is present
678
-        // then we call it hooked into the AHEE__EE_Admin_Page__route_admin_request action
679
-        if (method_exists($this, 'AHEE__EE_Admin_Page__route_admin_request_' . $this->_current_view)) {
680
-            add_action(
681
-                'AHEE__EE_Admin_Page__route_admin_request',
682
-                [$this, 'AHEE__EE_Admin_Page__route_admin_request_' . $this->_current_view],
683
-                10,
684
-                2
685
-            );
686
-        }
687
-        // next route only if routing enabled
688
-        if ($this->_routing && ! $this->request->isAjax()) {
689
-            $this->_verify_routes();
690
-            // next let's just check user_access and kill if no access
691
-            $this->check_user_access();
692
-            if ($this->_is_UI_request) {
693
-                // admin_init stuff - global, all views for this page class, specific view
694
-                add_action('admin_init', [$this, 'admin_init']);
695
-                if (method_exists($this, 'admin_init_' . $this->_current_view)) {
696
-                    add_action('admin_init', [$this, 'admin_init_' . $this->_current_view], 15);
697
-                }
698
-            } else {
699
-                // hijack regular WP loading and route admin request immediately
700
-                @ini_set('memory_limit', apply_filters('admin_memory_limit', WP_MAX_MEMORY_LIMIT));
701
-                $this->route_admin_request();
702
-            }
703
-        }
704
-    }
75
+	protected array $_page_config              = [];
705 76
 
77
+	/**
78
+	 * action => method pairs used for routing incoming requests
79
+	 *
80
+	 * @var array
81
+	 */
82
+	protected array $_page_routes   = [];
706 83
 
707
-    /**
708
-     * Provides a way for related child admin pages to load stuff on the loaded admin page.
709
-     *
710
-     * @return void
711
-     * @throws EE_Error
712
-     */
713
-    private function _do_other_page_hooks()
714
-    {
715
-        $registered_pages = apply_filters('FHEE_do_other_page_hooks_' . $this->page_slug, []);
716
-        foreach ($registered_pages as $page) {
717
-            // now let's set up the file name and class that should be present
718
-            $classname = str_replace('.class.php', '', $page);
719
-            // autoloaders should take care of loading file
720
-            if (! class_exists($classname)) {
721
-                $error_msg[] = sprintf(
722
-                    esc_html__(
723
-                        'Something went wrong with loading the %s admin hooks page.',
724
-                        'event_espresso'
725
-                    ),
726
-                    $page
727
-                );
728
-                $error_msg[] = $error_msg[0]
729
-                               . "\r\n"
730
-                               . sprintf(
731
-                                   esc_html__(
732
-                                       'There is no class in place for the %1$s admin hooks page.%2$sMake sure you have %3$s defined. If this is a non-EE-core admin page then you also must have an autoloader in place for your class',
733
-                                       'event_espresso'
734
-                                   ),
735
-                                   $page,
736
-                                   '<br />',
737
-                                   '<strong>' . $classname . '</strong>'
738
-                               );
739
-                throw new EE_Error(implode('||', $error_msg));
740
-            }
741
-            // don't load the same class twice
742
-            static $loaded = [];
743
-            if (in_array($classname, $loaded, true)) {
744
-                continue;
745
-            }
746
-            $loaded[] = $classname;
747
-            // notice we are passing the instance of this class to the hook object.
748
-            $this->loader->getShared($classname, [$this]);
749
-        }
750
-    }
84
+	protected array $_req_data      = [];
751 85
 
86
+	protected array $_route_config  = [];
752 87
 
753
-    /**
754
-     * @throws ReflectionException
755
-     * @throws EE_Error
756
-     */
757
-    public function load_page_dependencies()
758
-    {
759
-        try {
760
-            $this->_load_page_dependencies();
761
-        } catch (EE_Error $e) {
762
-            $e->get_error();
763
-        }
764
-    }
88
+	protected array $_template_args = [];
765 89
 
90
+	protected array $_views         = [];
766 91
 
767
-    /**
768
-     * load_page_dependencies
769
-     * loads things specific to this page class when it's loaded.  Really helps with efficiency.
770
-     *
771
-     * @return void
772
-     * @throws DomainException
773
-     * @throws EE_Error
774
-     * @throws InvalidArgumentException
775
-     * @throws InvalidDataTypeException
776
-     * @throws InvalidInterfaceException
777
-     * @throws ReflectionException
778
-     */
779
-    protected function _load_page_dependencies()
780
-    {
781
-        // let's set the current_screen and screen options to override what WP set
782
-        $this->_current_screen = get_current_screen();
783
-        // load admin_notices - global, page class, and view specific
784
-        add_action('admin_notices', [$this, 'admin_notices_global'], 5);
785
-        add_action('admin_notices', [$this, 'admin_notices']);
786
-        if (method_exists($this, 'admin_notices_' . $this->_current_view)) {
787
-            add_action('admin_notices', [$this, 'admin_notices_' . $this->_current_view], 15);
788
-        }
789
-        // load network admin_notices - global, page class, and view specific
790
-        add_action('network_admin_notices', [$this, 'network_admin_notices_global'], 5);
791
-        if (method_exists($this, 'network_admin_notices_' . $this->_current_view)) {
792
-            add_action('network_admin_notices', [$this, 'network_admin_notices_' . $this->_current_view]);
793
-        }
794
-        // this will save any per_page screen options if they are present
795
-        $this->_set_per_page_screen_options();
796
-        // setup list table properties
797
-        $this->_set_list_table();
798
-        // child classes can "register" a metabox to be automatically handled via the _page_config array property.
799
-        // However in some cases the metaboxes will need to be added within a route handling callback.
800
-        add_action('add_meta_boxes', [$this, 'addRegisteredMetaBoxes'], 99);
801
-        // hack because promos admin was loading the edited promotion object in the metaboxes callback
802
-        // which should NOT be generated on non-UI requests like POST updates/inserts
803
-        if (
804
-            $this->class_name === 'Promotions_Admin_Page'
805
-            && ($this->_req_action === 'edit' || $this->_req_action === 'create_new')
806
-        ) {
807
-            $this->addRegisteredMetaBoxes();
808
-        }
809
-        $this->_add_screen_columns();
810
-        // add screen options - global, page child class, and view specific
811
-        $this->_add_global_screen_options();
812
-        $this->_add_screen_options();
813
-        $add_screen_options = "_add_screen_options_$this->_current_view";
814
-        if (method_exists($this, $add_screen_options)) {
815
-            $this->{$add_screen_options}();
816
-        }
817
-        // add help tab(s) - set via page_config and qtips.
818
-        $this->_add_help_tabs();
819
-        $this->_add_qtips();
820
-        // add feature_pointers - global, page child class, and view specific
821
-        $this->_add_feature_pointers();
822
-        $this->_add_global_feature_pointers();
823
-        $add_feature_pointer = "_add_feature_pointer_$this->_current_view";
824
-        if (method_exists($this, $add_feature_pointer)) {
825
-            $this->{$add_feature_pointer}();
826
-        }
827
-        // enqueue scripts/styles - global, page class, and view specific
828
-        add_action('admin_enqueue_scripts', [$this, 'admin_footer_scripts_eei18n_js_strings'], 1);
829
-        add_action('admin_enqueue_scripts', [$this, 'load_global_scripts_styles'], 5);
830
-        add_action('admin_enqueue_scripts', [$this, 'load_scripts_styles']);
831
-        if (method_exists($this, "load_scripts_styles_$this->_current_view")) {
832
-            add_action('admin_enqueue_scripts', [$this, "load_scripts_styles_$this->_current_view"], 15);
833
-        }
834
-        // admin_print_footer_scripts - global, page child class, and view specific.
835
-        // NOTE, despite the name, whenever possible, scripts should NOT be loaded using this.
836
-        // In most cases that's doing_it_wrong().  But adding hidden container elements etc.
837
-        // is a good use case. Notice the late priority we're giving these
838
-        add_action('admin_print_footer_scripts', [$this, 'admin_footer_scripts_global'], 99);
839
-        add_action('admin_print_footer_scripts', [$this, 'admin_footer_scripts'], 100);
840
-        if (method_exists($this, "admin_footer_scripts_$this->_current_view")) {
841
-            add_action('admin_print_footer_scripts', [$this, "admin_footer_scripts_$this->_current_view"], 101);
842
-        }
843
-        // admin footer scripts
844
-        add_action('admin_footer', [$this, 'admin_footer_global'], 99);
845
-        add_action('admin_footer', [$this, 'admin_footer'], 100);
846
-        if (method_exists($this, "admin_footer_$this->_current_view")) {
847
-            add_action('admin_footer', [$this, "admin_footer_$this->_current_view"], 101);
848
-        }
849
-        do_action('FHEE__EE_Admin_Page___load_page_dependencies__after_load', $this->page_slug);
850
-        // targeted hook
851
-        do_action(
852
-            "FHEE__EE_Admin_Page___load_page_dependencies__after_load__{$this->page_slug}__$this->_req_action"
853
-        );
854
-    }
92
+	/**
93
+	 * yes / no array for admin form fields
94
+	 *
95
+	 * @var array|array[]
96
+	 */
97
+	protected array $_yes_no_values = [];
855 98
 
99
+	/**
100
+	 * this starts at null so we can have no header routes progress through two states.
101
+	 */
102
+	protected ?bool $_is_UI_request = null;
856 103
 
857
-    /**
858
-     * _set_defaults
859
-     * This sets some global defaults for class properties.
860
-     */
861
-    private function _set_defaults()
862
-    {
863
-        // init template args
864
-        $this->set_template_args(
865
-            [
866
-                'admin_page_header'  => '',
867
-                'admin_page_content' => '',
868
-                'post_body_content'  => '',
869
-                'before_list_table'  => '',
870
-                'after_list_table'   => '',
871
-            ]
872
-        );
873
-    }
104
+	/**
105
+	 * flags whether the given route is a caffeinated route or not.
106
+	 */
107
+	protected bool $_is_caf        = false;
874 108
 
109
+	protected bool $_routing       = false;
875 110
 
876
-    /**
877
-     * route_admin_request
878
-     *
879
-     * @return void
880
-     * @throws InvalidArgumentException
881
-     * @throws InvalidInterfaceException
882
-     * @throws InvalidDataTypeException
883
-     * @throws EE_Error
884
-     * @throws ReflectionException
885
-     * @throws Throwable
886
-     * @see    _route_admin_request()
887
-     */
888
-    public function route_admin_request()
889
-    {
890
-        try {
891
-            $this->_route_admin_request();
892
-        } catch (EE_Error $e) {
893
-            $e->get_error();
894
-        }
895
-    }
896
-
897
-
898
-    public function set_wp_page_slug($wp_page_slug)
899
-    {
900
-        $this->_wp_page_slug = $wp_page_slug;
901
-        // if in network admin then we need to append "-network" to the page slug. Why? Because that's how WP rolls...
902
-        if (is_network_admin()) {
903
-            $this->_wp_page_slug .= '-network';
904
-        }
905
-    }
111
+	/**
112
+	 * whether initializePage() has run
113
+	 *
114
+	 * @var bool
115
+	 */
116
+	protected bool $initialized = false;
906 117
 
907 118
 
908
-    /**
909
-     * _verify_routes
910
-     * All this method does is verify the incoming request and make sure that routes exist for it.  We do this early so
911
-     * we know if we need to drop out.
912
-     *
913
-     * @return bool
914
-     * @throws EE_Error
915
-     */
916
-    protected function _verify_routes(): bool
917
-    {
918
-        if (! $this->_current_page && ! $this->request->isAjax()) {
919
-            return false;
920
-        }
921
-        // check that the page_routes array is not empty
922
-        if (empty($this->_page_routes)) {
923
-            // user error msg
924
-            $error_msg = sprintf(
925
-                esc_html__('No page routes have been set for the %s admin page.', 'event_espresso'),
926
-                $this->_admin_page_title
927
-            );
928
-            // developer error msg
929
-            $error_msg .= '||' . $error_msg
930
-                          . esc_html__(
931
-                              ' Make sure the "set_page_routes()" method exists, and is setting the "_page_routes" array properly.',
932
-                              'event_espresso'
933
-                          );
934
-            throw new EE_Error($error_msg);
935
-        }
936
-        // route 'editpost' routes to CPT 'edit' routes
937
-        $alt_edit_route = $this instanceof EE_Admin_Page_CPT ? $this->cpt_editpost_route : 'edit';
938
-        if (
939
-            $this->_req_action === 'editpost'
940
-            && ! isset($this->_page_routes['editpost'])
941
-            && isset($this->_page_routes[ $alt_edit_route ])
942
-        ) {
943
-            $this->_req_action = $alt_edit_route;
944
-        }
945
-        // and that the requested page route exists
946
-        if (array_key_exists($this->_req_action, $this->_page_routes)) {
947
-            $this->_route        = $this->_page_routes[ $this->_req_action ];
948
-            $this->_route_config = $this->_page_config[ $this->_req_action ] ?? [];
949
-        } else {
950
-            // user error msg
951
-            $error_msg = sprintf(
952
-                esc_html__(
953
-                    'The requested page route does not exist for the %s admin page.',
954
-                    'event_espresso'
955
-                ),
956
-                $this->_admin_page_title
957
-            );
958
-            // developer error msg
959
-            $error_msg .= '||' . $error_msg
960
-                          . sprintf(
961
-                              esc_html__(
962
-                                  ' Create a key in the "_page_routes" array named "%s" and set its value to the appropriate method.',
963
-                                  'event_espresso'
964
-                              ),
965
-                              $this->_req_action
966
-                          );
967
-            throw new EE_Error($error_msg);
968
-        }
969
-        // and that a default route exists
970
-        if (! array_key_exists('default', $this->_page_routes)) {
971
-            // user error msg
972
-            $error_msg = sprintf(
973
-                esc_html__(
974
-                    'A default page route has not been set for the % admin page.',
975
-                    'event_espresso'
976
-                ),
977
-                $this->_admin_page_title
978
-            );
979
-            // developer error msg
980
-            $error_msg .= '||' . $error_msg
981
-                          . esc_html__(
982
-                              ' Create a key in the "_page_routes" array named "default" and set its value to your default page method.',
983
-                              'event_espresso'
984
-                          );
985
-            throw new EE_Error($error_msg);
986
-        }
987
-
988
-        // first lets' catch if the UI request has EVER been set.
989
-        if ($this->_is_UI_request === null) {
990
-            // let's set if this is a UI request or not.
991
-            $this->_is_UI_request = ! $this->request->getRequestParam('noheader', false, DataType::BOOL);
992
-            // wait a minute... we might have a noheader in the route array
993
-            $this->_is_UI_request = ! (isset($this->_route['noheader']) && $this->_route['noheader'])
994
-                ? $this->_is_UI_request
995
-                : false;
996
-        }
997
-        $this->_set_current_labels();
998
-        return true;
999
-    }
119
+	protected string $_admin_base_path      = '';
1000 120
 
121
+	protected string $_admin_base_url       = '';
1001 122
 
1002
-    /**
1003
-     * this method simply verifies a given route and makes sure it's an actual route available for the loaded page
1004
-     *
1005
-     * @param string $route the route name we're verifying
1006
-     * @return bool we'll throw an exception if this isn't a valid route.
1007
-     * @throws EE_Error
1008
-     */
1009
-    protected function _verify_route(string $route): bool
1010
-    {
1011
-        if (array_key_exists($this->_req_action, $this->_page_routes)) {
1012
-            return true;
1013
-        }
1014
-        // user error msg
1015
-        $error_msg = sprintf(
1016
-            esc_html__('The given page route does not exist for the %s admin page.', 'event_espresso'),
1017
-            $this->_admin_page_title
1018
-        );
1019
-        // developer error msg
1020
-        $error_msg .= '||' . $error_msg
1021
-                      . sprintf(
1022
-                          esc_html__(
1023
-                              ' Check the route you are using in your method (%s) and make sure it matches a route set in your "_page_routes" array property',
1024
-                              'event_espresso'
1025
-                          ),
1026
-                          $route
1027
-                      );
1028
-        throw new EE_Error($error_msg);
1029
-    }
123
+	protected string $_admin_page_title     = '';
1030 124
 
125
+	protected string $_column_template_path = '';
1031 126
 
1032
-    /**
1033
-     * perform nonce verification
1034
-     * This method has be encapsulated here so that any ajax requests that bypass normal routes can verify their nonces
1035
-     * using this method (and save retyping!)
1036
-     *
1037
-     * @param string $nonce     The nonce sent
1038
-     * @param string $nonce_ref The nonce reference string (name0)
1039
-     * @return void
1040
-     * @throws EE_Error
1041
-     * @throws InvalidArgumentException
1042
-     * @throws InvalidDataTypeException
1043
-     * @throws InvalidInterfaceException
1044
-     */
1045
-    protected function _verify_nonce(string $nonce = '', string $nonce_ref = '')
1046
-    {
1047
-        $nonce = $nonce ?: $this->request->getRequestParam($this->_req_nonce, '');
1048
-        $nonce_ref = $nonce_ref ?: $this->_req_action;
1049
-        // verify nonce against expected value
1050
-        if (! wp_verify_nonce($nonce, $nonce_ref)) {
1051
-            // these are not the droids you are looking for !!!
1052
-            $msg = sprintf(
1053
-                esc_html__('%sNonce Fail.%s', 'event_espresso'),
1054
-                '<a href="https://www.youtube.com/watch?v=56_S0WeTkzs">',
1055
-                '</a>'
1056
-            );
1057
-            if (WP_DEBUG) {
1058
-                $msg .= "\n  ";
1059
-                $msg .= sprintf(
1060
-                    esc_html__(
1061
-                        'In order to dynamically generate nonces for your actions, use the %s::add_query_args_and_nonce() method. May the Nonce be with you!',
1062
-                        'event_espresso'
1063
-                    ),
1064
-                    __CLASS__
1065
-                );
1066
-            }
1067
-            if (! $this->request->isAjax()) {
1068
-                wp_die($msg);
1069
-            }
1070
-            EE_Error::add_error($msg, __FILE__, __FUNCTION__, __LINE__);
1071
-            $this->_return_json();
1072
-        }
1073
-    }
127
+	protected bool $_cpt_route            = false;
1074 128
 
129
+	/**
130
+	 * set via request page and action args.
131
+	 */
132
+	protected string $_current_page          = '';
1075 133
 
1076
-    /**
1077
-     * _route_admin_request()
1078
-     * Meat and potatoes of the class.  Basically, this dude checks out what's being requested and sees if there are
1079
-     * some doodads to work the magic and handle the flingjangy. Translation:  Checks if the requested action is listed
1080
-     * in the page routes and then will try to load the corresponding method.
1081
-     *
1082
-     * @return void
1083
-     * @throws EE_Error
1084
-     * @throws InvalidArgumentException
1085
-     * @throws InvalidDataTypeException
1086
-     * @throws InvalidInterfaceException
1087
-     * @throws ReflectionException
1088
-     * @throws Throwable
1089
-     */
1090
-    protected function _route_admin_request()
1091
-    {
1092
-        if (! $this->_is_UI_request) {
1093
-            $this->_verify_routes();
1094
-        }
1095
-        $nonce_check = ! isset($this->_route_config['require_nonce']) || $this->_route_config['require_nonce'];
1096
-        if ($this->_req_action !== 'default' && $nonce_check) {
1097
-            // set nonce from post data
1098
-            $nonce = $this->request->getRequestParam($this->_req_nonce, '');
1099
-            $this->_verify_nonce($nonce, $this->_req_nonce);
1100
-        }
1101
-        // set the nav_tabs array but ONLY if this is  UI_request
1102
-        if ($this->_is_UI_request) {
1103
-            $this->_set_nav_tabs();
1104
-        }
1105
-        // grab callback function
1106
-        $func = $this->_route['func'] ?? $this->_route;
1107
-        // check if callback has args
1108
-        $args = $this->_route['args'] ?? [];
1109
-
1110
-        // action right before calling route
1111
-        // (hook is something like 'AHEE__Registrations_Admin_Page__route_admin_request')
1112
-        if (! did_action('AHEE__EE_Admin_Page__route_admin_request')) {
1113
-            do_action('AHEE__EE_Admin_Page__route_admin_request', $this->_current_view, $this);
1114
-        }
1115
-        // strip _wp_http_referer from the server REQUEST_URI
1116
-        // else it grows in length on every submission due to recursion,
1117
-        // ultimately causing a "Request-URI Too Large" error
1118
-        $this->request->unSetRequestParam('_wp_http_referer');
1119
-        $this->request->unSetServerParam('_wp_http_referer');
1120
-        $cleaner_request_uri = remove_query_arg(
1121
-            '_wp_http_referer',
1122
-            wp_unslash($this->request->getServerParam('REQUEST_URI'))
1123
-        );
1124
-        $this->request->setRequestParam('_wp_http_referer', $cleaner_request_uri, true);
1125
-        $this->request->setServerParam('REQUEST_URI', $cleaner_request_uri, true);
1126
-        $route_callback = [];
1127
-        if (! empty($func)) {
1128
-            if (is_array($func) && is_callable($func)) {
1129
-                $route_callback = $func;
1130
-            } elseif (is_string($func)) {
1131
-                if (strpos($func, '::') !== false) {
1132
-                    $route_callback = explode('::', $func);
1133
-                } elseif (method_exists($this, $func)) {
1134
-                    $route_callback = [$this, $func];
1135
-                } else {
1136
-                    $route_callback = $func;
1137
-                }
1138
-            }
1139
-            [$class, $method] = $route_callback;
1140
-            // is it neither a class method NOR a standalone function?
1141
-            if (! is_callable($route_callback)) {
1142
-                // user error msg
1143
-                $error_msg = esc_html__(
1144
-                    'An error occurred. The  requested page route could not be found.',
1145
-                    'event_espresso'
1146
-                );
1147
-                // developer error msg
1148
-                $error_msg .= '||';
1149
-                $error_msg .= sprintf(
1150
-                    esc_html__(
1151
-                        'Page route "%s" could not be called. Check that the spelling for method names and actions in the "_page_routes" array are all correct.',
1152
-                        'event_espresso'
1153
-                    ),
1154
-                    $method
1155
-                );
1156
-                throw new DomainException($error_msg);
1157
-            }
1158
-            if ($class !== $this && ! in_array($this, $args)) {
1159
-                // send along this admin page object for access by addons.
1160
-                $args['admin_page'] = $this;
1161
-            }
1162
-
1163
-            call_user_func_array($route_callback, $args);
1164
-        }
1165
-        // if we've routed and this route has a no headers route AND a sent_headers_route,
1166
-        // then we need to reset the routing properties to the new route.
1167
-        // now if UI request is FALSE and noheader is true AND we have a headers_sent_route in the route array then let's set UI_request to true because the no header route has a second func after headers have been sent.
1168
-        if (
1169
-            $this->_is_UI_request === false
1170
-            && is_array($this->_route)
1171
-            && ! empty($this->_route['headers_sent_route'])
1172
-        ) {
1173
-            $this->_reset_routing_properties($this->_route['headers_sent_route']);
1174
-        }
1175
-    }
134
+	protected string $_current_page_view_url = '';
1176 135
 
136
+	protected string $_current_view          = '';
1177 137
 
1178
-    /**
1179
-     * This method just allows the resetting of page properties in the case where a no headers
1180
-     * route redirects to a headers route in its route config.
1181
-     *
1182
-     * @param string $new_route New (non header) route to redirect to.
1183
-     * @return void
1184
-     * @throws ReflectionException
1185
-     * @throws InvalidArgumentException
1186
-     * @throws InvalidInterfaceException
1187
-     * @throws InvalidDataTypeException
1188
-     * @throws EE_Error
1189
-     * @throws Throwable
1190
-     * @since   4.3.0
1191
-     */
1192
-    protected function _reset_routing_properties(string $new_route)
1193
-    {
1194
-        $this->_is_UI_request = true;
1195
-        // now we set the current route to whatever the headers_sent_route is set at
1196
-        $this->request->setRequestParam('action', $new_route);
1197
-        // rerun page setup
1198
-        $this->_page_setup();
1199
-    }
138
+	protected string $_default_nav_tab_name  = 'overview';
1200 139
 
140
+	/**
141
+	 * sanitized request action
142
+	 */
143
+	protected string $_req_action = '';
144
+
145
+	/**
146
+	 * sanitized request action nonce
147
+	 */
148
+	protected string $_req_nonce        = '';
149
+
150
+	protected string $_search_btn_label = '';
151
+
152
+	protected string $_template_path    = '';
153
+
154
+	protected string $_view             = '';
1201 155
 
1202
-    /**
1203
-     * _add_query_arg
1204
-     * adds nonce to array of arguments then calls WP add_query_arg function
1205
-     *(internally just uses EEH_URL's function with the same name)
1206
-     *
1207
-     * @param array  $args
1208
-     * @param string $url
1209
-     * @param bool   $sticky                  if true, then the existing Request params will be appended to the
1210
-     *                                        generated url in an associative array indexed by the key 'wp_referer';
1211
-     *                                        Example usage: If the current page is:
1212
-     *                                        http://mydomain.com/wp-admin/admin.php?page=espresso_registrations
1213
-     *                                        &action=default&event_id=20&month_range=March%202015
1214
-     *                                        &_wpnonce=5467821
1215
-     *                                        and you call:
1216
-     *                                        EE_Admin_Page::add_query_args_and_nonce(
1217
-     *                                        array(
1218
-     *                                        'action' => 'resend_something',
1219
-     *                                        'page=>espresso_registrations'
1220
-     *                                        ),
1221
-     *                                        $some_url,
1222
-     *                                        true
1223
-     *                                        );
1224
-     *                                        It will produce a URL in this structure:
1225
-     *                                        http://{$some_url}/?page=espresso_registrations&action=resend_something
1226
-     *                                        &wp_referer[action]=default&wp_referer[event_id]=20&wpreferer[
1227
-     *                                        month_range]=March%202015
1228
-     * @param bool   $exclude_nonce           If true, the nonce will be excluded from the generated nonce.
1229
-     * @param int    $context
1230
-     * @return string
1231
-     */
1232
-    public static function add_query_args_and_nonce(
1233
-        array $args = [],
1234
-        string $url = '',
1235
-        bool $sticky = false,
1236
-        bool $exclude_nonce = false,
1237
-        int $context = EEH_URL::CONTEXT_NONE
1238
-    ): string {
1239
-        // if there is a _wp_http_referer include the values from the request but only if sticky = true
1240
-        if ($sticky) {
1241
-            /** @var RequestInterface $request */
1242
-            $request = LoaderFactory::getLoader()->getShared(RequestInterface::class);
1243
-            $request->unSetRequestParams(['_wp_http_referer', 'wp_referer'], true);
1244
-            $request->unSetServerParam('_wp_http_referer', true);
1245
-            foreach ($request->requestParams() as $key => $value) {
1246
-                // do not add nonces
1247
-                if (strpos($key, 'nonce') !== false) {
1248
-                    continue;
1249
-                }
1250
-                $args[ 'wp_referer[' . $key . ']' ] = is_string($value) ? htmlspecialchars($value) : $value;
1251
-            }
1252
-        }
1253
-        return EEH_URL::add_query_args_and_nonce($args, $url, $exclude_nonce, $context);
1254
-    }
156
+	/**
157
+	 * set early within EE_Admin_Init
158
+	 *
159
+	 * @var string
160
+	 */
161
+	protected string $_wp_page_slug = '';
1255 162
 
163
+	/**
164
+	 * if the current class is an admin page extension, like: Extend_Events_Admin_Page,
165
+	 * then this would be the parent classname: Events_Admin_Page
166
+	 *
167
+	 * @var string
168
+	 */
169
+	public string $base_class_name = '';
1256 170
 
1257
-    /**
1258
-     * This returns a generated link that will load the related help tab.
1259
-     *
1260
-     * @param string $help_tab_id the id for the connected help tab
1261
-     * @param string $icon_style  (optional) include css class for the style you want to use for the help icon.
1262
-     * @param string $help_text   (optional) send help text you want to use for the link if default not to be used
1263
-     * @return string              generated link
1264
-     * @uses EEH_Template::get_help_tab_link()
1265
-     */
1266
-    protected function _get_help_tab_link(string $help_tab_id, string $icon_style = '', string $help_text = ''): string
1267
-    {
1268
-        return EEH_Template::get_help_tab_link(
1269
-            $help_tab_id,
1270
-            $this->page_slug,
1271
-            $this->_req_action,
1272
-            $icon_style,
1273
-            $help_text
1274
-        );
1275
-    }
1276
-
1277
-
1278
-    /**
1279
-     * _add_help_tabs
1280
-     * Note child classes define their help tabs within the page_config array.
1281
-     *
1282
-     * @link   http://codex.wordpress.org/Function_Reference/add_help_tab
1283
-     * @return void
1284
-     * @throws DomainException
1285
-     * @throws EE_Error
1286
-     * @throws ReflectionException
1287
-     */
1288
-    protected function _add_help_tabs()
1289
-    {
1290
-        if (isset($this->_page_config[ $this->_req_action ])) {
1291
-            $config = $this->_page_config[ $this->_req_action ];
1292
-            // let's see if there is a help_sidebar set for the current route and we'll set that up for usage as well.
1293
-            if (is_array($config) && isset($config['help_sidebar'])) {
1294
-                // check that the callback given is valid
1295
-                if (! method_exists($this, $config['help_sidebar'])) {
1296
-                    throw new EE_Error(
1297
-                        sprintf(
1298
-                            esc_html__(
1299
-                                'The _page_config array has a callback set for the "help_sidebar" option.  However the callback given (%s) is not a valid callback.  Double check the spelling and make sure this method exists for the class %s',
1300
-                                'event_espresso'
1301
-                            ),
1302
-                            $config['help_sidebar'],
1303
-                            $this->class_name
1304
-                        )
1305
-                    );
1306
-                }
1307
-                $content = apply_filters(
1308
-                    'FHEE__' . $this->class_name . '__add_help_tabs__help_sidebar',
1309
-                    $this->{$config['help_sidebar']}()
1310
-                );
1311
-                $this->_current_screen->set_help_sidebar($content);
1312
-            }
1313
-            if (! isset($config['help_tabs'])) {
1314
-                return;
1315
-            } //no help tabs for this route
1316
-            foreach ((array) $config['help_tabs'] as $tab_id => $cfg) {
1317
-                // we're here so there ARE help tabs!
1318
-                // make sure we've got what we need
1319
-                if (! isset($cfg['title'])) {
1320
-                    throw new EE_Error(
1321
-                        esc_html__(
1322
-                            'The _page_config array is not set up properly for help tabs.  It is missing a title',
1323
-                            'event_espresso'
1324
-                        )
1325
-                    );
1326
-                }
1327
-                if (! isset($cfg['filename']) && ! isset($cfg['callback']) && ! isset($cfg['content'])) {
1328
-                    throw new EE_Error(
1329
-                        esc_html__(
1330
-                            'The _page_config array is not setup properly for help tabs. It is missing a either a filename reference, or a callback reference or a content reference so there is no way to know the content for the help tab',
1331
-                            'event_espresso'
1332
-                        )
1333
-                    );
1334
-                }
1335
-                // first priority goes to content.
1336
-                if (! empty($cfg['content'])) {
1337
-                    $content = $cfg['content'];
1338
-                    // second priority goes to filename
1339
-                } elseif (! empty($cfg['filename'])) {
1340
-                    $file_path = $this->_get_dir() . '/help_tabs/' . $cfg['filename'] . '.help_tab.php';
1341
-                    // it's possible that the file is located on decaf route (and above sets up for caf route, if this is the case then lets check decaf route too)
1342
-                    $file_path = ! is_readable($file_path) ? EE_ADMIN_PAGES
1343
-                                                             . basename($this->_get_dir())
1344
-                                                             . '/help_tabs/'
1345
-                                                             . $cfg['filename']
1346
-                                                             . '.help_tab.php' : $file_path;
1347
-                    // if file is STILL not readable then let's do an EE_Error so its more graceful than a fatal error.
1348
-                    if (! isset($cfg['callback']) && ! is_readable($file_path)) {
1349
-                        EE_Error::add_error(
1350
-                            sprintf(
1351
-                                esc_html__(
1352
-                                    'The filename given for the help tab %s is not a valid file and there is no other configuration for the tab content.  Please check that the string you set for the help tab on this route (%s) is the correct spelling.  The file should be in %s',
1353
-                                    'event_espresso'
1354
-                                ),
1355
-                                $tab_id,
1356
-                                key($config),
1357
-                                $file_path
1358
-                            ),
1359
-                            __FILE__,
1360
-                            __FUNCTION__,
1361
-                            __LINE__
1362
-                        );
1363
-                        return;
1364
-                    }
1365
-                    $template_args['admin_page_obj'] = $this;
1366
-                    $content                         = EEH_Template::display_template(
1367
-                        $file_path,
1368
-                        $template_args,
1369
-                        true
1370
-                    );
1371
-                } else {
1372
-                    $content = '';
1373
-                }
1374
-                // check if callback is valid
1375
-                if (
1376
-                    empty($content)
1377
-                    && (
1378
-                        ! isset($cfg['callback']) || ! method_exists($this, $cfg['callback'])
1379
-                    )
1380
-                ) {
1381
-                    EE_Error::add_error(
1382
-                        sprintf(
1383
-                            esc_html__(
1384
-                                'The callback given for a %s help tab on this page does not content OR a corresponding method for generating the content.  Check the spelling or make sure the method is present.',
1385
-                                'event_espresso'
1386
-                            ),
1387
-                            $cfg['title']
1388
-                        ),
1389
-                        __FILE__,
1390
-                        __FUNCTION__,
1391
-                        __LINE__
1392
-                    );
1393
-                    return;
1394
-                }
1395
-                // setup config array for help tab method
1396
-                $id  = $this->page_slug . '-' . $this->_req_action . '-' . $tab_id;
1397
-                $_ht = [
1398
-                    'id'       => $id,
1399
-                    'title'    => $cfg['title'],
1400
-                    'callback' => isset($cfg['callback']) && empty($content) ? [$this, $cfg['callback']] : null,
1401
-                    'content'  => $content,
1402
-                ];
1403
-                $this->_current_screen->add_help_tab($_ht);
1404
-            }
1405
-        }
1406
-    }
1407
-
1408
-
1409
-    /**
1410
-     * This simply sets up any qtips that have been defined in the page config
1411
-     *
1412
-     * @return void
1413
-     * @throws ReflectionException
1414
-     * @throws EE_Error
1415
-     */
1416
-    protected function _add_qtips()
1417
-    {
1418
-        if (isset($this->_route_config['qtips'])) {
1419
-            $qtips = (array) $this->_route_config['qtips'];
1420
-            // load qtip loader
1421
-            $path = [
1422
-                $this->_get_dir() . '/qtips/',
1423
-                EE_ADMIN_PAGES . basename($this->_get_dir()) . '/qtips/',
1424
-            ];
1425
-            EEH_Qtip_Loader::instance()->register($qtips, $path);
1426
-        }
1427
-    }
171
+	public string $class_name      = '';
1428 172
 
1429
-
1430
-    /**
1431
-     * _set_nav_tabs
1432
-     * This sets up the nav tabs from the page_routes array.  This method can be overwritten by child classes if you
1433
-     * wish to add additional tabs or modify accordingly.
1434
-     *
1435
-     * @return void
1436
-     * @throws InvalidArgumentException
1437
-     * @throws InvalidInterfaceException
1438
-     * @throws InvalidDataTypeException
1439
-     */
1440
-    protected function _set_nav_tabs()
1441
-    {
1442
-        $i        = 0;
1443
-        $only_tab = count($this->_page_config) < 2;
1444
-        foreach ($this->_page_config as $slug => $config) {
1445
-            if (! is_array($config) || empty($config['nav'])) {
1446
-                continue;
1447
-            }
1448
-            // no nav tab for this config
1449
-            // check for persistent flag
1450
-            if ($slug !== $this->_req_action && isset($config['nav']['persistent']) && ! $config['nav']['persistent']) {
1451
-                // nav tab is only to appear when route requested.
1452
-                continue;
1453
-            }
1454
-            if (! $this->check_user_access($slug, true)) {
1455
-                // no nav tab because current user does not have access.
1456
-                continue;
1457
-            }
1458
-            $css_class = $config['css_class'] ?? '';
1459
-            $css_class .= $only_tab ? ' ee-only-tab' : '';
1460
-            $css_class .= " ee-nav-tab__$slug";
1461
-
1462
-            $this->_nav_tabs[ $slug ] = [
1463
-                'url'       => $config['nav']['url'] ?? EE_Admin_Page::add_query_args_and_nonce(
1464
-                    ['action' => $slug],
1465
-                    $this->_admin_base_url
1466
-                ),
1467
-                'link_text' => $this->navTabLabel($config['nav'], $slug),
1468
-                'css_class' => $this->_req_action === $slug ? $css_class . ' nav-tab-active' : $css_class,
1469
-                'order'     => $config['nav']['order'] ?? $i,
1470
-            ];
1471
-            $i++;
1472
-        }
1473
-        // if $this->_nav_tabs is empty then lets set the default
1474
-        if (empty($this->_nav_tabs)) {
1475
-            $this->_nav_tabs[ $this->_default_nav_tab_name ] = [
1476
-                'url'       => $this->_admin_base_url,
1477
-                'link_text' => ucwords(str_replace('_', ' ', $this->_default_nav_tab_name)),
1478
-                'css_class' => 'nav-tab-active',
1479
-                'order'     => 10,
1480
-            ];
1481
-        }
1482
-        // now let's sort the tabs according to order
1483
-        usort($this->_nav_tabs, [$this, '_sort_nav_tabs']);
1484
-    }
1485
-
1486
-
1487
-    private function navTabLabel(array $nav_tab, string $slug): string
1488
-    {
1489
-        $label = $nav_tab['label'] ?? ucwords(str_replace('_', ' ', $slug));
1490
-        $icon  = $nav_tab['icon'] ?? null;
1491
-        $icon  = $icon ? '<span class="dashicons ' . $icon . '"></span>' : '';
1492
-        return '
173
+	/**
174
+	 * unprocessed value for the 'action' request param (default '')
175
+	 *
176
+	 * @var string
177
+	 */
178
+	protected string $raw_req_action = '';
179
+
180
+	/**
181
+	 * unprocessed value for the 'page' request param (default '')
182
+	 *
183
+	 * @var string
184
+	 */
185
+	protected string $raw_req_page = '';
186
+
187
+	public string $page_folder  = '';
188
+
189
+	public string $page_label   = '';
190
+
191
+	public string $page_slug    = '';
192
+
193
+
194
+	/**
195
+	 * the current page route and route config
196
+	 *
197
+	 * @var array|callable|string|null
198
+	 */
199
+	protected $_route = null;
200
+
201
+
202
+	/**
203
+	 * @Constructor
204
+	 * @param bool $routing indicate whether we want to just load the object and handle routing or just load the object.
205
+	 * @throws InvalidArgumentException
206
+	 * @throws InvalidDataTypeException
207
+	 * @throws InvalidInterfaceException
208
+	 * @throws ReflectionException
209
+	 */
210
+	public function __construct($routing = true)
211
+	{
212
+		$this->_routing = $routing;
213
+
214
+		$this->loader       = LoaderFactory::getLoader();
215
+		$this->admin_config = $this->loader->getShared(EE_Admin_Config::class);
216
+		$this->feature      = $this->loader->getShared(FeatureFlags::class);
217
+		$this->request      = $this->loader->getShared(RequestInterface::class);
218
+		$this->capabilities = $this->loader->getShared(EE_Capabilities::class);
219
+
220
+		$this->class_name      = get_class($this);
221
+		$this->base_class_name = strpos($this->class_name, 'Extend_') === 0
222
+			? str_replace('Extend_', '', $this->class_name)
223
+			: '';
224
+
225
+		if (strpos($this->_get_dir(), 'caffeinated') !== false) {
226
+			$this->_is_caf = true;
227
+		}
228
+		$this->_yes_no_values = [
229
+			['id' => true, 'text' => esc_html__('Yes', 'event_espresso')],
230
+			['id' => false, 'text' => esc_html__('No', 'event_espresso')],
231
+		];
232
+		// set the _req_data property.
233
+		$this->_req_data = $this->request->requestParams();
234
+	}
235
+
236
+
237
+	/**
238
+	 * @return EE_Admin_Config
239
+	 */
240
+	public function adminConfig(): EE_Admin_Config
241
+	{
242
+		return $this->admin_config;
243
+	}
244
+
245
+
246
+	public function capabilities(): EE_Capabilities
247
+	{
248
+		if (! $this->capabilities instanceof EE_Capabilities) {
249
+			$this->capabilities = $this->loader->getShared(EE_Capabilities::class);
250
+		}
251
+		return $this->capabilities;
252
+	}
253
+
254
+
255
+	/**
256
+	 * @return FeatureFlags
257
+	 */
258
+	public function feature(): FeatureFlags
259
+	{
260
+		return $this->feature;
261
+	}
262
+
263
+
264
+	/**
265
+	 * This logic used to be in the constructor, but that caused a chicken <--> egg scenario
266
+	 * for child classes that needed to set properties prior to these methods getting called,
267
+	 * but also needed the parent class to have its construction completed as well.
268
+	 * Bottom line is that constructors should ONLY be used for setting initial properties
269
+	 * and any complex initialization logic should only run after instantiation is complete.
270
+	 * This method gets called immediately after construction from within
271
+	 *      EE_Admin_Page_Init::_initialize_admin_page()
272
+	 *
273
+	 * @throws EE_Error
274
+	 * @throws InvalidArgumentException
275
+	 * @throws InvalidDataTypeException
276
+	 * @throws InvalidInterfaceException
277
+	 * @throws ReflectionException
278
+	 * @throws Throwable
279
+	 * @since 5.0.0.p
280
+	 */
281
+	public function initializePage()
282
+	{
283
+		if ($this->initialized) {
284
+			return;
285
+		}
286
+		// set initial page props (child method)
287
+		$this->_init_page_props();
288
+		// set global defaults
289
+		$this->_set_defaults();
290
+		// set early because incoming requests could be ajax related and we need to register those hooks.
291
+		if ($this->request->isAjax()) {
292
+			$this->_global_ajax_hooks();
293
+			$this->_ajax_hooks();
294
+		}
295
+		// other_page_hooks have to be early too.
296
+		$this->_do_other_page_hooks();
297
+		// set up page dependencies
298
+		$this->_before_page_setup();
299
+		$this->_page_setup();
300
+		$this->initialized = true;
301
+	}
302
+
303
+
304
+	/**
305
+	 * _init_page_props
306
+	 * Child classes use to set at least the following properties:
307
+	 * $page_slug.
308
+	 * $page_label.
309
+	 *
310
+	 * @abstract
311
+	 * @return void
312
+	 */
313
+	abstract protected function _init_page_props();
314
+
315
+
316
+	/**
317
+	 * _ajax_hooks
318
+	 * child classes put all their add_action('wp_ajax_{name_of_hook}') hooks in here.
319
+	 * Note: within the ajax callback methods.
320
+	 *
321
+	 * @abstract
322
+	 * @return void
323
+	 */
324
+	abstract protected function _ajax_hooks();
325
+
326
+
327
+	/**
328
+	 * _define_page_props
329
+	 * child classes define page properties in here.  Must include at least:
330
+	 * $_admin_base_url = base_url for all admin pages
331
+	 * $_admin_page_title = default admin_page_title for admin pages
332
+	 * $_labels = array of default labels for various automatically generated elements:
333
+	 *    array(
334
+	 *        'buttons' => array(
335
+	 *            'add' => esc_html__('label for add new button'),
336
+	 *            'edit' => esc_html__('label for edit button'),
337
+	 *            'delete' => esc_html__('label for delete button')
338
+	 *            )
339
+	 *        )
340
+	 *
341
+	 * @abstract
342
+	 * @return void
343
+	 */
344
+	abstract protected function _define_page_props();
345
+
346
+
347
+	/**
348
+	 * _set_page_routes
349
+	 * child classes use this to define the page routes for all subpages handled by the class.  Page routes are
350
+	 * assigned to an action => method pairs in an array and to the $_page_routes property.  Each page route must also
351
+	 * have a 'default' route. Here's the format
352
+	 * $this->_page_routes = array(
353
+	 *        'default' => array(
354
+	 *            'func' => '_default_method_handling_route',
355
+	 *            'args' => array('array','of','args'),
356
+	 *            'noheader' => true, //add this in if this page route is processed before any headers are loaded (i.e.
357
+	 *            ajax request, backend processing)
358
+	 *            'headers_sent_route'=>'headers_route_reference', //add this if noheader=>true, and you want to load a
359
+	 *            headers route after.  The string you enter here should match the defined route reference for a
360
+	 *            headers sent route.
361
+	 *            'capability' => 'route_capability', //indicate a string for minimum capability required to access
362
+	 *            this route.
363
+	 *            'obj_id' => 10 // if this route has an object id, then this can include it (used for capability
364
+	 *            checks).
365
+	 *        ),
366
+	 *        'insert_item' => '_method_for_handling_insert_item' //this can be used if all we need to have is a
367
+	 *        handling method.
368
+	 *        )
369
+	 * )
370
+	 *
371
+	 * @abstract
372
+	 * @return void
373
+	 */
374
+	abstract protected function _set_page_routes();
375
+
376
+
377
+	/**
378
+	 * _set_page_config
379
+	 * child classes use this to define the _page_config array for all subpages handled by the class. Each key in the
380
+	 * array corresponds to the page_route for the loaded page. Format:
381
+	 * $this->_page_config = array(
382
+	 *        'default' => array(
383
+	 *            'labels' => array(
384
+	 *                'buttons' => array(
385
+	 *                    'add' => esc_html__('label for adding item'),
386
+	 *                    'edit' => esc_html__('label for editing item'),
387
+	 *                    'delete' => esc_html__('label for deleting item')
388
+	 *                ),
389
+	 *                'publishbox' => esc_html__('Localized Title for Publish metabox', 'event_espresso')
390
+	 *            ), //optional an array of custom labels for various automatically generated elements to use on the
391
+	 *            page. If this isn't present then the defaults will be used as set for the $this->_labels in
392
+	 *            _define_page_props() method
393
+	 *            'nav' => array(
394
+	 *                'label' => esc_html__('Label for Tab', 'event_espresso').
395
+	 *                'url' => 'http://someurl', //automatically generated UNLESS you define
396
+	 *                'css_class' => 'css-class', //automatically generated UNLESS you define
397
+	 *                'order' => 10, //required to indicate tab position.
398
+	 *                'persistent' => false //if you want the nav tab to ONLY display when the specific route is
399
+	 *                displayed then add this parameter.
400
+	 *            'list_table' => 'name_of_list_table' //string for list table class to be loaded for this admin_page.
401
+	 *            'metaboxes' => array('metabox1', 'metabox2'), //if present this key indicates we want to load
402
+	 *            metaboxes set for eventespresso admin pages.
403
+	 *            'has_metaboxes' => true, //this boolean flag can simply be used to indicate if the route will have
404
+	 *            metaboxes.  Typically this is used if the 'metaboxes' index is not used because metaboxes are added
405
+	 *            later.  We just use this flag to make sure the necessary js gets enqueued on page load.
406
+	 *            'has_help_popups' => false //defaults(true) //this boolean flag can simply be used to indicate if the
407
+	 *            given route has help popups setup and if it does then we need to make sure thickbox is enqueued.
408
+	 *            'columns' => array(4, 2), //this key triggers the setup of a page that uses columns (metaboxes).  The
409
+	 *            array indicates the max number of columns (4) and the default number of columns on page load (2).
410
+	 *            There is an option in the "screen_options" dropdown that is set up so users can pick what columns they
411
+	 *            want to display.
412
+	 *            'help_tabs' => array( //this is used for adding help tabs to a page
413
+	 *                'tab_id' => array(
414
+	 *                    'title' => 'tab_title',
415
+	 *                    'filename' => 'name_of_file_containing_content', //this is the primary method for setting
416
+	 *                    help tab content.  The fallback if it isn't present is to try the callback.  Filename
417
+	 *                    should match a file in the admin folder's "help_tabs" dir (ie..
418
+	 *                    events/help_tabs/name_of_file_containing_content.help_tab.php)
419
+	 *                    'callback' => 'callback_method_for_content', //if 'filename' isn't present then system will
420
+	 *                    attempt to use the callback which should match the name of a method in the class
421
+	 *                    ),
422
+	 *                'tab2_id' => array(
423
+	 *                    'title' => 'tab2 title',
424
+	 *                    'filename' => 'file_name_2'
425
+	 *                    'callback' => 'callback_method_for_content',
426
+	 *                 ),
427
+	 *            'help_sidebar' => 'callback_for_sidebar_content', //this is used for setting up the sidebar in the
428
+	 *            help tab area on an admin page. @return void
429
+	 *
430
+	 * @abstract
431
+	 */
432
+	abstract protected function _set_page_config();
433
+
434
+
435
+	/**
436
+	 * _add_screen_options
437
+	 * Child classes can add any extra wp_screen_options within this method using built-in WP functions/methods for
438
+	 * doing so. Note child classes can also define _add_screen_options_($this->_current_view) to limit screen options
439
+	 * to a particular view.
440
+	 *
441
+	 * @link   http://chrismarslender.com/wp-tutorials/wordpress-screen-options-tutorial/
442
+	 *         see also WP_Screen object documents...
443
+	 * @link   http://codex.wordpress.org/Class_Reference/WP_Screen
444
+	 * @abstract
445
+	 * @return void
446
+	 */
447
+	abstract protected function _add_screen_options();
448
+
449
+
450
+	/**
451
+	 * _add_feature_pointers
452
+	 * Child classes should use this method for implementing any "feature pointers" (using built-in WP styling js).
453
+	 * Note child classes can also define _add_feature_pointers_($this->_current_view) to limit screen options to a
454
+	 * particular view. Note: this is just a placeholder for now.  Implementation will come down the road See:
455
+	 * WP_Internal_Pointers class in wp-admin/includes/template.php for example (it's a final class so can't be
456
+	 * extended) also see:
457
+	 *
458
+	 * @link   http://eamann.com/tech/wordpress-portland/
459
+	 * @abstract
460
+	 * @return void
461
+	 */
462
+	abstract protected function _add_feature_pointers();
463
+
464
+
465
+	/**
466
+	 * load_scripts_styles
467
+	 * child classes put their wp_enqueue_script and wp_enqueue_style hooks in here for anything they need loaded for
468
+	 * their pages/subpages.  Note this is for all pages/subpages of the system.  You can also load only specific
469
+	 * scripts/styles per view by putting them in a dynamic function in this format
470
+	 * (load_scripts_styles_{$this->_current_view}) which matches your page route (action request arg)
471
+	 *
472
+	 * @abstract
473
+	 * @return void
474
+	 */
475
+	abstract public function load_scripts_styles();
476
+
477
+
478
+	/**
479
+	 * admin_init
480
+	 * Anything that should be set/executed at 'admin_init' WP hook runtime should be put in here.  This will apply to
481
+	 * all pages/views loaded by child class.
482
+	 *
483
+	 * @abstract
484
+	 * @return void
485
+	 */
486
+	abstract public function admin_init();
487
+
488
+
489
+	/**
490
+	 * admin_notices
491
+	 * Anything triggered by the 'admin_notices' WP hook should be put in here.  This particular method will apply to
492
+	 * all pages/views loaded by child class.
493
+	 *
494
+	 * @abstract
495
+	 * @return void
496
+	 */
497
+	abstract public function admin_notices();
498
+
499
+
500
+	/**
501
+	 * admin_footer_scripts
502
+	 * Anything triggered by the 'admin_print_footer_scripts' WP hook should be put in here. This particular method
503
+	 * will apply to all pages/views loaded by child class.
504
+	 *
505
+	 * @return void
506
+	 */
507
+	abstract public function admin_footer_scripts();
508
+
509
+
510
+	/**
511
+	 * admin_footer
512
+	 * anything triggered by the 'admin_footer' WP action hook should be added to here. This particular method will
513
+	 * apply to all pages/views loaded by child class.
514
+	 *
515
+	 * @return void
516
+	 */
517
+	public function admin_footer()
518
+	{
519
+	}
520
+
521
+
522
+	/**
523
+	 * _global_ajax_hooks
524
+	 * all global add_action('wp_ajax_{name_of_hook}') hooks in here.
525
+	 * Note: within the ajax callback methods.
526
+	 *
527
+	 * @abstract
528
+	 * @return void
529
+	 */
530
+	protected function _global_ajax_hooks()
531
+	{
532
+		// for lazy loading of metabox content
533
+		add_action('wp_ajax_espresso-ajax-content', [$this, 'ajax_metabox_content']);
534
+
535
+		add_action(
536
+			'wp_ajax_espresso_hide_status_change_notice',
537
+			[$this, 'hideStatusChangeNotice']
538
+		);
539
+		add_action(
540
+			'wp_ajax_nopriv_espresso_hide_status_change_notice',
541
+			[$this, 'hideStatusChangeNotice']
542
+		);
543
+	}
544
+
545
+
546
+	public function ajax_metabox_content()
547
+	{
548
+		$content_id  = $this->request->getRequestParam('contentid', '');
549
+		$content_url = $this->request->getRequestParam('contenturl', '', DataType::URL);
550
+		EE_Admin_Page::cached_rss_display($content_id, $content_url);
551
+		wp_die();
552
+	}
553
+
554
+
555
+	public function hideStatusChangeNotice()
556
+	{
557
+		$response = [];
558
+		try {
559
+			/** @var StatusChangeNotice $status_change_notice */
560
+			$status_change_notice = $this->loader->getShared(
561
+				'EventEspresso\core\domain\services\admin\notices\status_change\StatusChangeNotice'
562
+			);
563
+			$response['success']  = $status_change_notice->dismiss() > -1;
564
+		} catch (Exception $exception) {
565
+			$response['errors'] = $exception->getMessage();
566
+		}
567
+		wp_send_json($response);
568
+	}
569
+
570
+
571
+	/**
572
+	 * allows extending classes do something specific before the parent constructor runs _page_setup().
573
+	 *
574
+	 * @return void
575
+	 */
576
+	protected function _before_page_setup()
577
+	{
578
+		// default is to do nothing
579
+	}
580
+
581
+
582
+	/**
583
+	 * Makes sure any things that need to be loaded early get handled.
584
+	 * We also escape early here if the page requested doesn't match the object.
585
+	 *
586
+	 * @final
587
+	 * @return void
588
+	 * @throws EE_Error
589
+	 * @throws InvalidArgumentException
590
+	 * @throws ReflectionException
591
+	 * @throws InvalidDataTypeException
592
+	 * @throws InvalidInterfaceException
593
+	 * @throws Throwable
594
+	 */
595
+	final protected function _page_setup()
596
+	{
597
+		// requires?
598
+		// admin_init stuff - global - we're setting this REALLY early
599
+		// so if EE_Admin pages have to hook into other WP pages they can.
600
+		// But keep in mind, not everything is available from the EE_Admin Page object at this point.
601
+		add_action('admin_init', [$this, 'admin_init_global'], 5);
602
+		// next verify if we need to load anything...
603
+		$this->_current_page = $this->request->getRequestParam('page', '', DataType::KEY);
604
+		$this->_current_page = $this->request->getRequestParam('current_page', $this->_current_page, DataType::KEY);
605
+		$this->page_folder   = strtolower(
606
+			str_replace(['_Admin_Page', 'Extend_'], '', $this->class_name)
607
+		);
608
+		global $ee_menu_slugs;
609
+		$ee_menu_slugs = (array) $ee_menu_slugs;
610
+		if (
611
+			! $this->request->isAjax()
612
+			&& (! $this->_current_page || ! isset($ee_menu_slugs[ $this->_current_page ]))
613
+		) {
614
+			return;
615
+		}
616
+		// because WP List tables have two duplicate select inputs for choosing bulk actions,
617
+		// we need to copy the action from the second to the first
618
+		$action     = $this->request->getRequestParam('action', '-1', DataType::KEY);
619
+		$action2    = $this->request->getRequestParam('action2', '-1', DataType::KEY);
620
+		$action     = $action !== '-1' ? $action : $action2;
621
+		$req_action = $action !== '-1' ? $action : 'default';
622
+
623
+		// if a specific 'route' has been set, and the action is 'default' OR we are doing_ajax
624
+		// then let's use the route as the action.
625
+		// This covers cases where we're coming in from a list table that isn't on the default route.
626
+		$route = $this->request->getRequestParam('route');
627
+		$route = $route !== '-1' ? $route : 'default';
628
+		$this->_req_action = $route && ($req_action === 'default' || $this->request->isAjax())
629
+			? $route
630
+			: $req_action;
631
+		$this->_current_view = $this->_req_action;
632
+		$this->_req_nonce    = $this->_req_action . '_nonce';
633
+		$this->_define_page_props();
634
+		$this->_current_page_view_url = add_query_arg(
635
+			['page' => $this->_current_page, 'action' => $this->_current_view],
636
+			$this->_admin_base_url
637
+		);
638
+		// set page configs
639
+		$this->_set_page_routes();
640
+		$this->_set_page_config();
641
+		// let's include any referrer data in our default_query_args for this route for "stickiness".
642
+		if ($this->request->requestParamIsSet('wp_referer')) {
643
+			$wp_referer = $this->request->getRequestParam('wp_referer');
644
+			if ($wp_referer) {
645
+				$this->_default_route_query_args['wp_referer'] = $wp_referer;
646
+			}
647
+		}
648
+		// for CPT and other extended functionality.
649
+		// If there is an _extend_page_config_for_cpt
650
+		// then let's run that to modify all the various page configuration arrays.
651
+		if (method_exists($this, '_extend_page_config_for_cpt')) {
652
+			$this->_extend_page_config_for_cpt();
653
+		}
654
+		// filter routes and page_config so addons can add their stuff. Filtering done per class
655
+		$this->_page_routes = apply_filters(
656
+			'FHEE__' . $this->class_name . '__page_setup__page_routes',
657
+			$this->_page_routes,
658
+			$this
659
+		);
660
+		$this->_page_config = apply_filters(
661
+			'FHEE__' . $this->class_name . '__page_setup__page_config',
662
+			$this->_page_config,
663
+			$this
664
+		);
665
+		if ($this->base_class_name !== '') {
666
+			$this->_page_routes = apply_filters(
667
+				'FHEE__' . $this->base_class_name . '__page_setup__page_routes',
668
+				$this->_page_routes,
669
+				$this
670
+			);
671
+			$this->_page_config = apply_filters(
672
+				'FHEE__' . $this->base_class_name . '__page_setup__page_config',
673
+				$this->_page_config,
674
+				$this
675
+			);
676
+		}
677
+		// if AHEE__EE_Admin_Page__route_admin_request_$this->_current_view method is present
678
+		// then we call it hooked into the AHEE__EE_Admin_Page__route_admin_request action
679
+		if (method_exists($this, 'AHEE__EE_Admin_Page__route_admin_request_' . $this->_current_view)) {
680
+			add_action(
681
+				'AHEE__EE_Admin_Page__route_admin_request',
682
+				[$this, 'AHEE__EE_Admin_Page__route_admin_request_' . $this->_current_view],
683
+				10,
684
+				2
685
+			);
686
+		}
687
+		// next route only if routing enabled
688
+		if ($this->_routing && ! $this->request->isAjax()) {
689
+			$this->_verify_routes();
690
+			// next let's just check user_access and kill if no access
691
+			$this->check_user_access();
692
+			if ($this->_is_UI_request) {
693
+				// admin_init stuff - global, all views for this page class, specific view
694
+				add_action('admin_init', [$this, 'admin_init']);
695
+				if (method_exists($this, 'admin_init_' . $this->_current_view)) {
696
+					add_action('admin_init', [$this, 'admin_init_' . $this->_current_view], 15);
697
+				}
698
+			} else {
699
+				// hijack regular WP loading and route admin request immediately
700
+				@ini_set('memory_limit', apply_filters('admin_memory_limit', WP_MAX_MEMORY_LIMIT));
701
+				$this->route_admin_request();
702
+			}
703
+		}
704
+	}
705
+
706
+
707
+	/**
708
+	 * Provides a way for related child admin pages to load stuff on the loaded admin page.
709
+	 *
710
+	 * @return void
711
+	 * @throws EE_Error
712
+	 */
713
+	private function _do_other_page_hooks()
714
+	{
715
+		$registered_pages = apply_filters('FHEE_do_other_page_hooks_' . $this->page_slug, []);
716
+		foreach ($registered_pages as $page) {
717
+			// now let's set up the file name and class that should be present
718
+			$classname = str_replace('.class.php', '', $page);
719
+			// autoloaders should take care of loading file
720
+			if (! class_exists($classname)) {
721
+				$error_msg[] = sprintf(
722
+					esc_html__(
723
+						'Something went wrong with loading the %s admin hooks page.',
724
+						'event_espresso'
725
+					),
726
+					$page
727
+				);
728
+				$error_msg[] = $error_msg[0]
729
+							   . "\r\n"
730
+							   . sprintf(
731
+								   esc_html__(
732
+									   'There is no class in place for the %1$s admin hooks page.%2$sMake sure you have %3$s defined. If this is a non-EE-core admin page then you also must have an autoloader in place for your class',
733
+									   'event_espresso'
734
+								   ),
735
+								   $page,
736
+								   '<br />',
737
+								   '<strong>' . $classname . '</strong>'
738
+							   );
739
+				throw new EE_Error(implode('||', $error_msg));
740
+			}
741
+			// don't load the same class twice
742
+			static $loaded = [];
743
+			if (in_array($classname, $loaded, true)) {
744
+				continue;
745
+			}
746
+			$loaded[] = $classname;
747
+			// notice we are passing the instance of this class to the hook object.
748
+			$this->loader->getShared($classname, [$this]);
749
+		}
750
+	}
751
+
752
+
753
+	/**
754
+	 * @throws ReflectionException
755
+	 * @throws EE_Error
756
+	 */
757
+	public function load_page_dependencies()
758
+	{
759
+		try {
760
+			$this->_load_page_dependencies();
761
+		} catch (EE_Error $e) {
762
+			$e->get_error();
763
+		}
764
+	}
765
+
766
+
767
+	/**
768
+	 * load_page_dependencies
769
+	 * loads things specific to this page class when it's loaded.  Really helps with efficiency.
770
+	 *
771
+	 * @return void
772
+	 * @throws DomainException
773
+	 * @throws EE_Error
774
+	 * @throws InvalidArgumentException
775
+	 * @throws InvalidDataTypeException
776
+	 * @throws InvalidInterfaceException
777
+	 * @throws ReflectionException
778
+	 */
779
+	protected function _load_page_dependencies()
780
+	{
781
+		// let's set the current_screen and screen options to override what WP set
782
+		$this->_current_screen = get_current_screen();
783
+		// load admin_notices - global, page class, and view specific
784
+		add_action('admin_notices', [$this, 'admin_notices_global'], 5);
785
+		add_action('admin_notices', [$this, 'admin_notices']);
786
+		if (method_exists($this, 'admin_notices_' . $this->_current_view)) {
787
+			add_action('admin_notices', [$this, 'admin_notices_' . $this->_current_view], 15);
788
+		}
789
+		// load network admin_notices - global, page class, and view specific
790
+		add_action('network_admin_notices', [$this, 'network_admin_notices_global'], 5);
791
+		if (method_exists($this, 'network_admin_notices_' . $this->_current_view)) {
792
+			add_action('network_admin_notices', [$this, 'network_admin_notices_' . $this->_current_view]);
793
+		}
794
+		// this will save any per_page screen options if they are present
795
+		$this->_set_per_page_screen_options();
796
+		// setup list table properties
797
+		$this->_set_list_table();
798
+		// child classes can "register" a metabox to be automatically handled via the _page_config array property.
799
+		// However in some cases the metaboxes will need to be added within a route handling callback.
800
+		add_action('add_meta_boxes', [$this, 'addRegisteredMetaBoxes'], 99);
801
+		// hack because promos admin was loading the edited promotion object in the metaboxes callback
802
+		// which should NOT be generated on non-UI requests like POST updates/inserts
803
+		if (
804
+			$this->class_name === 'Promotions_Admin_Page'
805
+			&& ($this->_req_action === 'edit' || $this->_req_action === 'create_new')
806
+		) {
807
+			$this->addRegisteredMetaBoxes();
808
+		}
809
+		$this->_add_screen_columns();
810
+		// add screen options - global, page child class, and view specific
811
+		$this->_add_global_screen_options();
812
+		$this->_add_screen_options();
813
+		$add_screen_options = "_add_screen_options_$this->_current_view";
814
+		if (method_exists($this, $add_screen_options)) {
815
+			$this->{$add_screen_options}();
816
+		}
817
+		// add help tab(s) - set via page_config and qtips.
818
+		$this->_add_help_tabs();
819
+		$this->_add_qtips();
820
+		// add feature_pointers - global, page child class, and view specific
821
+		$this->_add_feature_pointers();
822
+		$this->_add_global_feature_pointers();
823
+		$add_feature_pointer = "_add_feature_pointer_$this->_current_view";
824
+		if (method_exists($this, $add_feature_pointer)) {
825
+			$this->{$add_feature_pointer}();
826
+		}
827
+		// enqueue scripts/styles - global, page class, and view specific
828
+		add_action('admin_enqueue_scripts', [$this, 'admin_footer_scripts_eei18n_js_strings'], 1);
829
+		add_action('admin_enqueue_scripts', [$this, 'load_global_scripts_styles'], 5);
830
+		add_action('admin_enqueue_scripts', [$this, 'load_scripts_styles']);
831
+		if (method_exists($this, "load_scripts_styles_$this->_current_view")) {
832
+			add_action('admin_enqueue_scripts', [$this, "load_scripts_styles_$this->_current_view"], 15);
833
+		}
834
+		// admin_print_footer_scripts - global, page child class, and view specific.
835
+		// NOTE, despite the name, whenever possible, scripts should NOT be loaded using this.
836
+		// In most cases that's doing_it_wrong().  But adding hidden container elements etc.
837
+		// is a good use case. Notice the late priority we're giving these
838
+		add_action('admin_print_footer_scripts', [$this, 'admin_footer_scripts_global'], 99);
839
+		add_action('admin_print_footer_scripts', [$this, 'admin_footer_scripts'], 100);
840
+		if (method_exists($this, "admin_footer_scripts_$this->_current_view")) {
841
+			add_action('admin_print_footer_scripts', [$this, "admin_footer_scripts_$this->_current_view"], 101);
842
+		}
843
+		// admin footer scripts
844
+		add_action('admin_footer', [$this, 'admin_footer_global'], 99);
845
+		add_action('admin_footer', [$this, 'admin_footer'], 100);
846
+		if (method_exists($this, "admin_footer_$this->_current_view")) {
847
+			add_action('admin_footer', [$this, "admin_footer_$this->_current_view"], 101);
848
+		}
849
+		do_action('FHEE__EE_Admin_Page___load_page_dependencies__after_load', $this->page_slug);
850
+		// targeted hook
851
+		do_action(
852
+			"FHEE__EE_Admin_Page___load_page_dependencies__after_load__{$this->page_slug}__$this->_req_action"
853
+		);
854
+	}
855
+
856
+
857
+	/**
858
+	 * _set_defaults
859
+	 * This sets some global defaults for class properties.
860
+	 */
861
+	private function _set_defaults()
862
+	{
863
+		// init template args
864
+		$this->set_template_args(
865
+			[
866
+				'admin_page_header'  => '',
867
+				'admin_page_content' => '',
868
+				'post_body_content'  => '',
869
+				'before_list_table'  => '',
870
+				'after_list_table'   => '',
871
+			]
872
+		);
873
+	}
874
+
875
+
876
+	/**
877
+	 * route_admin_request
878
+	 *
879
+	 * @return void
880
+	 * @throws InvalidArgumentException
881
+	 * @throws InvalidInterfaceException
882
+	 * @throws InvalidDataTypeException
883
+	 * @throws EE_Error
884
+	 * @throws ReflectionException
885
+	 * @throws Throwable
886
+	 * @see    _route_admin_request()
887
+	 */
888
+	public function route_admin_request()
889
+	{
890
+		try {
891
+			$this->_route_admin_request();
892
+		} catch (EE_Error $e) {
893
+			$e->get_error();
894
+		}
895
+	}
896
+
897
+
898
+	public function set_wp_page_slug($wp_page_slug)
899
+	{
900
+		$this->_wp_page_slug = $wp_page_slug;
901
+		// if in network admin then we need to append "-network" to the page slug. Why? Because that's how WP rolls...
902
+		if (is_network_admin()) {
903
+			$this->_wp_page_slug .= '-network';
904
+		}
905
+	}
906
+
907
+
908
+	/**
909
+	 * _verify_routes
910
+	 * All this method does is verify the incoming request and make sure that routes exist for it.  We do this early so
911
+	 * we know if we need to drop out.
912
+	 *
913
+	 * @return bool
914
+	 * @throws EE_Error
915
+	 */
916
+	protected function _verify_routes(): bool
917
+	{
918
+		if (! $this->_current_page && ! $this->request->isAjax()) {
919
+			return false;
920
+		}
921
+		// check that the page_routes array is not empty
922
+		if (empty($this->_page_routes)) {
923
+			// user error msg
924
+			$error_msg = sprintf(
925
+				esc_html__('No page routes have been set for the %s admin page.', 'event_espresso'),
926
+				$this->_admin_page_title
927
+			);
928
+			// developer error msg
929
+			$error_msg .= '||' . $error_msg
930
+						  . esc_html__(
931
+							  ' Make sure the "set_page_routes()" method exists, and is setting the "_page_routes" array properly.',
932
+							  'event_espresso'
933
+						  );
934
+			throw new EE_Error($error_msg);
935
+		}
936
+		// route 'editpost' routes to CPT 'edit' routes
937
+		$alt_edit_route = $this instanceof EE_Admin_Page_CPT ? $this->cpt_editpost_route : 'edit';
938
+		if (
939
+			$this->_req_action === 'editpost'
940
+			&& ! isset($this->_page_routes['editpost'])
941
+			&& isset($this->_page_routes[ $alt_edit_route ])
942
+		) {
943
+			$this->_req_action = $alt_edit_route;
944
+		}
945
+		// and that the requested page route exists
946
+		if (array_key_exists($this->_req_action, $this->_page_routes)) {
947
+			$this->_route        = $this->_page_routes[ $this->_req_action ];
948
+			$this->_route_config = $this->_page_config[ $this->_req_action ] ?? [];
949
+		} else {
950
+			// user error msg
951
+			$error_msg = sprintf(
952
+				esc_html__(
953
+					'The requested page route does not exist for the %s admin page.',
954
+					'event_espresso'
955
+				),
956
+				$this->_admin_page_title
957
+			);
958
+			// developer error msg
959
+			$error_msg .= '||' . $error_msg
960
+						  . sprintf(
961
+							  esc_html__(
962
+								  ' Create a key in the "_page_routes" array named "%s" and set its value to the appropriate method.',
963
+								  'event_espresso'
964
+							  ),
965
+							  $this->_req_action
966
+						  );
967
+			throw new EE_Error($error_msg);
968
+		}
969
+		// and that a default route exists
970
+		if (! array_key_exists('default', $this->_page_routes)) {
971
+			// user error msg
972
+			$error_msg = sprintf(
973
+				esc_html__(
974
+					'A default page route has not been set for the % admin page.',
975
+					'event_espresso'
976
+				),
977
+				$this->_admin_page_title
978
+			);
979
+			// developer error msg
980
+			$error_msg .= '||' . $error_msg
981
+						  . esc_html__(
982
+							  ' Create a key in the "_page_routes" array named "default" and set its value to your default page method.',
983
+							  'event_espresso'
984
+						  );
985
+			throw new EE_Error($error_msg);
986
+		}
987
+
988
+		// first lets' catch if the UI request has EVER been set.
989
+		if ($this->_is_UI_request === null) {
990
+			// let's set if this is a UI request or not.
991
+			$this->_is_UI_request = ! $this->request->getRequestParam('noheader', false, DataType::BOOL);
992
+			// wait a minute... we might have a noheader in the route array
993
+			$this->_is_UI_request = ! (isset($this->_route['noheader']) && $this->_route['noheader'])
994
+				? $this->_is_UI_request
995
+				: false;
996
+		}
997
+		$this->_set_current_labels();
998
+		return true;
999
+	}
1000
+
1001
+
1002
+	/**
1003
+	 * this method simply verifies a given route and makes sure it's an actual route available for the loaded page
1004
+	 *
1005
+	 * @param string $route the route name we're verifying
1006
+	 * @return bool we'll throw an exception if this isn't a valid route.
1007
+	 * @throws EE_Error
1008
+	 */
1009
+	protected function _verify_route(string $route): bool
1010
+	{
1011
+		if (array_key_exists($this->_req_action, $this->_page_routes)) {
1012
+			return true;
1013
+		}
1014
+		// user error msg
1015
+		$error_msg = sprintf(
1016
+			esc_html__('The given page route does not exist for the %s admin page.', 'event_espresso'),
1017
+			$this->_admin_page_title
1018
+		);
1019
+		// developer error msg
1020
+		$error_msg .= '||' . $error_msg
1021
+					  . sprintf(
1022
+						  esc_html__(
1023
+							  ' Check the route you are using in your method (%s) and make sure it matches a route set in your "_page_routes" array property',
1024
+							  'event_espresso'
1025
+						  ),
1026
+						  $route
1027
+					  );
1028
+		throw new EE_Error($error_msg);
1029
+	}
1030
+
1031
+
1032
+	/**
1033
+	 * perform nonce verification
1034
+	 * This method has be encapsulated here so that any ajax requests that bypass normal routes can verify their nonces
1035
+	 * using this method (and save retyping!)
1036
+	 *
1037
+	 * @param string $nonce     The nonce sent
1038
+	 * @param string $nonce_ref The nonce reference string (name0)
1039
+	 * @return void
1040
+	 * @throws EE_Error
1041
+	 * @throws InvalidArgumentException
1042
+	 * @throws InvalidDataTypeException
1043
+	 * @throws InvalidInterfaceException
1044
+	 */
1045
+	protected function _verify_nonce(string $nonce = '', string $nonce_ref = '')
1046
+	{
1047
+		$nonce = $nonce ?: $this->request->getRequestParam($this->_req_nonce, '');
1048
+		$nonce_ref = $nonce_ref ?: $this->_req_action;
1049
+		// verify nonce against expected value
1050
+		if (! wp_verify_nonce($nonce, $nonce_ref)) {
1051
+			// these are not the droids you are looking for !!!
1052
+			$msg = sprintf(
1053
+				esc_html__('%sNonce Fail.%s', 'event_espresso'),
1054
+				'<a href="https://www.youtube.com/watch?v=56_S0WeTkzs">',
1055
+				'</a>'
1056
+			);
1057
+			if (WP_DEBUG) {
1058
+				$msg .= "\n  ";
1059
+				$msg .= sprintf(
1060
+					esc_html__(
1061
+						'In order to dynamically generate nonces for your actions, use the %s::add_query_args_and_nonce() method. May the Nonce be with you!',
1062
+						'event_espresso'
1063
+					),
1064
+					__CLASS__
1065
+				);
1066
+			}
1067
+			if (! $this->request->isAjax()) {
1068
+				wp_die($msg);
1069
+			}
1070
+			EE_Error::add_error($msg, __FILE__, __FUNCTION__, __LINE__);
1071
+			$this->_return_json();
1072
+		}
1073
+	}
1074
+
1075
+
1076
+	/**
1077
+	 * _route_admin_request()
1078
+	 * Meat and potatoes of the class.  Basically, this dude checks out what's being requested and sees if there are
1079
+	 * some doodads to work the magic and handle the flingjangy. Translation:  Checks if the requested action is listed
1080
+	 * in the page routes and then will try to load the corresponding method.
1081
+	 *
1082
+	 * @return void
1083
+	 * @throws EE_Error
1084
+	 * @throws InvalidArgumentException
1085
+	 * @throws InvalidDataTypeException
1086
+	 * @throws InvalidInterfaceException
1087
+	 * @throws ReflectionException
1088
+	 * @throws Throwable
1089
+	 */
1090
+	protected function _route_admin_request()
1091
+	{
1092
+		if (! $this->_is_UI_request) {
1093
+			$this->_verify_routes();
1094
+		}
1095
+		$nonce_check = ! isset($this->_route_config['require_nonce']) || $this->_route_config['require_nonce'];
1096
+		if ($this->_req_action !== 'default' && $nonce_check) {
1097
+			// set nonce from post data
1098
+			$nonce = $this->request->getRequestParam($this->_req_nonce, '');
1099
+			$this->_verify_nonce($nonce, $this->_req_nonce);
1100
+		}
1101
+		// set the nav_tabs array but ONLY if this is  UI_request
1102
+		if ($this->_is_UI_request) {
1103
+			$this->_set_nav_tabs();
1104
+		}
1105
+		// grab callback function
1106
+		$func = $this->_route['func'] ?? $this->_route;
1107
+		// check if callback has args
1108
+		$args = $this->_route['args'] ?? [];
1109
+
1110
+		// action right before calling route
1111
+		// (hook is something like 'AHEE__Registrations_Admin_Page__route_admin_request')
1112
+		if (! did_action('AHEE__EE_Admin_Page__route_admin_request')) {
1113
+			do_action('AHEE__EE_Admin_Page__route_admin_request', $this->_current_view, $this);
1114
+		}
1115
+		// strip _wp_http_referer from the server REQUEST_URI
1116
+		// else it grows in length on every submission due to recursion,
1117
+		// ultimately causing a "Request-URI Too Large" error
1118
+		$this->request->unSetRequestParam('_wp_http_referer');
1119
+		$this->request->unSetServerParam('_wp_http_referer');
1120
+		$cleaner_request_uri = remove_query_arg(
1121
+			'_wp_http_referer',
1122
+			wp_unslash($this->request->getServerParam('REQUEST_URI'))
1123
+		);
1124
+		$this->request->setRequestParam('_wp_http_referer', $cleaner_request_uri, true);
1125
+		$this->request->setServerParam('REQUEST_URI', $cleaner_request_uri, true);
1126
+		$route_callback = [];
1127
+		if (! empty($func)) {
1128
+			if (is_array($func) && is_callable($func)) {
1129
+				$route_callback = $func;
1130
+			} elseif (is_string($func)) {
1131
+				if (strpos($func, '::') !== false) {
1132
+					$route_callback = explode('::', $func);
1133
+				} elseif (method_exists($this, $func)) {
1134
+					$route_callback = [$this, $func];
1135
+				} else {
1136
+					$route_callback = $func;
1137
+				}
1138
+			}
1139
+			[$class, $method] = $route_callback;
1140
+			// is it neither a class method NOR a standalone function?
1141
+			if (! is_callable($route_callback)) {
1142
+				// user error msg
1143
+				$error_msg = esc_html__(
1144
+					'An error occurred. The  requested page route could not be found.',
1145
+					'event_espresso'
1146
+				);
1147
+				// developer error msg
1148
+				$error_msg .= '||';
1149
+				$error_msg .= sprintf(
1150
+					esc_html__(
1151
+						'Page route "%s" could not be called. Check that the spelling for method names and actions in the "_page_routes" array are all correct.',
1152
+						'event_espresso'
1153
+					),
1154
+					$method
1155
+				);
1156
+				throw new DomainException($error_msg);
1157
+			}
1158
+			if ($class !== $this && ! in_array($this, $args)) {
1159
+				// send along this admin page object for access by addons.
1160
+				$args['admin_page'] = $this;
1161
+			}
1162
+
1163
+			call_user_func_array($route_callback, $args);
1164
+		}
1165
+		// if we've routed and this route has a no headers route AND a sent_headers_route,
1166
+		// then we need to reset the routing properties to the new route.
1167
+		// now if UI request is FALSE and noheader is true AND we have a headers_sent_route in the route array then let's set UI_request to true because the no header route has a second func after headers have been sent.
1168
+		if (
1169
+			$this->_is_UI_request === false
1170
+			&& is_array($this->_route)
1171
+			&& ! empty($this->_route['headers_sent_route'])
1172
+		) {
1173
+			$this->_reset_routing_properties($this->_route['headers_sent_route']);
1174
+		}
1175
+	}
1176
+
1177
+
1178
+	/**
1179
+	 * This method just allows the resetting of page properties in the case where a no headers
1180
+	 * route redirects to a headers route in its route config.
1181
+	 *
1182
+	 * @param string $new_route New (non header) route to redirect to.
1183
+	 * @return void
1184
+	 * @throws ReflectionException
1185
+	 * @throws InvalidArgumentException
1186
+	 * @throws InvalidInterfaceException
1187
+	 * @throws InvalidDataTypeException
1188
+	 * @throws EE_Error
1189
+	 * @throws Throwable
1190
+	 * @since   4.3.0
1191
+	 */
1192
+	protected function _reset_routing_properties(string $new_route)
1193
+	{
1194
+		$this->_is_UI_request = true;
1195
+		// now we set the current route to whatever the headers_sent_route is set at
1196
+		$this->request->setRequestParam('action', $new_route);
1197
+		// rerun page setup
1198
+		$this->_page_setup();
1199
+	}
1200
+
1201
+
1202
+	/**
1203
+	 * _add_query_arg
1204
+	 * adds nonce to array of arguments then calls WP add_query_arg function
1205
+	 *(internally just uses EEH_URL's function with the same name)
1206
+	 *
1207
+	 * @param array  $args
1208
+	 * @param string $url
1209
+	 * @param bool   $sticky                  if true, then the existing Request params will be appended to the
1210
+	 *                                        generated url in an associative array indexed by the key 'wp_referer';
1211
+	 *                                        Example usage: If the current page is:
1212
+	 *                                        http://mydomain.com/wp-admin/admin.php?page=espresso_registrations
1213
+	 *                                        &action=default&event_id=20&month_range=March%202015
1214
+	 *                                        &_wpnonce=5467821
1215
+	 *                                        and you call:
1216
+	 *                                        EE_Admin_Page::add_query_args_and_nonce(
1217
+	 *                                        array(
1218
+	 *                                        'action' => 'resend_something',
1219
+	 *                                        'page=>espresso_registrations'
1220
+	 *                                        ),
1221
+	 *                                        $some_url,
1222
+	 *                                        true
1223
+	 *                                        );
1224
+	 *                                        It will produce a URL in this structure:
1225
+	 *                                        http://{$some_url}/?page=espresso_registrations&action=resend_something
1226
+	 *                                        &wp_referer[action]=default&wp_referer[event_id]=20&wpreferer[
1227
+	 *                                        month_range]=March%202015
1228
+	 * @param bool   $exclude_nonce           If true, the nonce will be excluded from the generated nonce.
1229
+	 * @param int    $context
1230
+	 * @return string
1231
+	 */
1232
+	public static function add_query_args_and_nonce(
1233
+		array $args = [],
1234
+		string $url = '',
1235
+		bool $sticky = false,
1236
+		bool $exclude_nonce = false,
1237
+		int $context = EEH_URL::CONTEXT_NONE
1238
+	): string {
1239
+		// if there is a _wp_http_referer include the values from the request but only if sticky = true
1240
+		if ($sticky) {
1241
+			/** @var RequestInterface $request */
1242
+			$request = LoaderFactory::getLoader()->getShared(RequestInterface::class);
1243
+			$request->unSetRequestParams(['_wp_http_referer', 'wp_referer'], true);
1244
+			$request->unSetServerParam('_wp_http_referer', true);
1245
+			foreach ($request->requestParams() as $key => $value) {
1246
+				// do not add nonces
1247
+				if (strpos($key, 'nonce') !== false) {
1248
+					continue;
1249
+				}
1250
+				$args[ 'wp_referer[' . $key . ']' ] = is_string($value) ? htmlspecialchars($value) : $value;
1251
+			}
1252
+		}
1253
+		return EEH_URL::add_query_args_and_nonce($args, $url, $exclude_nonce, $context);
1254
+	}
1255
+
1256
+
1257
+	/**
1258
+	 * This returns a generated link that will load the related help tab.
1259
+	 *
1260
+	 * @param string $help_tab_id the id for the connected help tab
1261
+	 * @param string $icon_style  (optional) include css class for the style you want to use for the help icon.
1262
+	 * @param string $help_text   (optional) send help text you want to use for the link if default not to be used
1263
+	 * @return string              generated link
1264
+	 * @uses EEH_Template::get_help_tab_link()
1265
+	 */
1266
+	protected function _get_help_tab_link(string $help_tab_id, string $icon_style = '', string $help_text = ''): string
1267
+	{
1268
+		return EEH_Template::get_help_tab_link(
1269
+			$help_tab_id,
1270
+			$this->page_slug,
1271
+			$this->_req_action,
1272
+			$icon_style,
1273
+			$help_text
1274
+		);
1275
+	}
1276
+
1277
+
1278
+	/**
1279
+	 * _add_help_tabs
1280
+	 * Note child classes define their help tabs within the page_config array.
1281
+	 *
1282
+	 * @link   http://codex.wordpress.org/Function_Reference/add_help_tab
1283
+	 * @return void
1284
+	 * @throws DomainException
1285
+	 * @throws EE_Error
1286
+	 * @throws ReflectionException
1287
+	 */
1288
+	protected function _add_help_tabs()
1289
+	{
1290
+		if (isset($this->_page_config[ $this->_req_action ])) {
1291
+			$config = $this->_page_config[ $this->_req_action ];
1292
+			// let's see if there is a help_sidebar set for the current route and we'll set that up for usage as well.
1293
+			if (is_array($config) && isset($config['help_sidebar'])) {
1294
+				// check that the callback given is valid
1295
+				if (! method_exists($this, $config['help_sidebar'])) {
1296
+					throw new EE_Error(
1297
+						sprintf(
1298
+							esc_html__(
1299
+								'The _page_config array has a callback set for the "help_sidebar" option.  However the callback given (%s) is not a valid callback.  Double check the spelling and make sure this method exists for the class %s',
1300
+								'event_espresso'
1301
+							),
1302
+							$config['help_sidebar'],
1303
+							$this->class_name
1304
+						)
1305
+					);
1306
+				}
1307
+				$content = apply_filters(
1308
+					'FHEE__' . $this->class_name . '__add_help_tabs__help_sidebar',
1309
+					$this->{$config['help_sidebar']}()
1310
+				);
1311
+				$this->_current_screen->set_help_sidebar($content);
1312
+			}
1313
+			if (! isset($config['help_tabs'])) {
1314
+				return;
1315
+			} //no help tabs for this route
1316
+			foreach ((array) $config['help_tabs'] as $tab_id => $cfg) {
1317
+				// we're here so there ARE help tabs!
1318
+				// make sure we've got what we need
1319
+				if (! isset($cfg['title'])) {
1320
+					throw new EE_Error(
1321
+						esc_html__(
1322
+							'The _page_config array is not set up properly for help tabs.  It is missing a title',
1323
+							'event_espresso'
1324
+						)
1325
+					);
1326
+				}
1327
+				if (! isset($cfg['filename']) && ! isset($cfg['callback']) && ! isset($cfg['content'])) {
1328
+					throw new EE_Error(
1329
+						esc_html__(
1330
+							'The _page_config array is not setup properly for help tabs. It is missing a either a filename reference, or a callback reference or a content reference so there is no way to know the content for the help tab',
1331
+							'event_espresso'
1332
+						)
1333
+					);
1334
+				}
1335
+				// first priority goes to content.
1336
+				if (! empty($cfg['content'])) {
1337
+					$content = $cfg['content'];
1338
+					// second priority goes to filename
1339
+				} elseif (! empty($cfg['filename'])) {
1340
+					$file_path = $this->_get_dir() . '/help_tabs/' . $cfg['filename'] . '.help_tab.php';
1341
+					// it's possible that the file is located on decaf route (and above sets up for caf route, if this is the case then lets check decaf route too)
1342
+					$file_path = ! is_readable($file_path) ? EE_ADMIN_PAGES
1343
+															 . basename($this->_get_dir())
1344
+															 . '/help_tabs/'
1345
+															 . $cfg['filename']
1346
+															 . '.help_tab.php' : $file_path;
1347
+					// if file is STILL not readable then let's do an EE_Error so its more graceful than a fatal error.
1348
+					if (! isset($cfg['callback']) && ! is_readable($file_path)) {
1349
+						EE_Error::add_error(
1350
+							sprintf(
1351
+								esc_html__(
1352
+									'The filename given for the help tab %s is not a valid file and there is no other configuration for the tab content.  Please check that the string you set for the help tab on this route (%s) is the correct spelling.  The file should be in %s',
1353
+									'event_espresso'
1354
+								),
1355
+								$tab_id,
1356
+								key($config),
1357
+								$file_path
1358
+							),
1359
+							__FILE__,
1360
+							__FUNCTION__,
1361
+							__LINE__
1362
+						);
1363
+						return;
1364
+					}
1365
+					$template_args['admin_page_obj'] = $this;
1366
+					$content                         = EEH_Template::display_template(
1367
+						$file_path,
1368
+						$template_args,
1369
+						true
1370
+					);
1371
+				} else {
1372
+					$content = '';
1373
+				}
1374
+				// check if callback is valid
1375
+				if (
1376
+					empty($content)
1377
+					&& (
1378
+						! isset($cfg['callback']) || ! method_exists($this, $cfg['callback'])
1379
+					)
1380
+				) {
1381
+					EE_Error::add_error(
1382
+						sprintf(
1383
+							esc_html__(
1384
+								'The callback given for a %s help tab on this page does not content OR a corresponding method for generating the content.  Check the spelling or make sure the method is present.',
1385
+								'event_espresso'
1386
+							),
1387
+							$cfg['title']
1388
+						),
1389
+						__FILE__,
1390
+						__FUNCTION__,
1391
+						__LINE__
1392
+					);
1393
+					return;
1394
+				}
1395
+				// setup config array for help tab method
1396
+				$id  = $this->page_slug . '-' . $this->_req_action . '-' . $tab_id;
1397
+				$_ht = [
1398
+					'id'       => $id,
1399
+					'title'    => $cfg['title'],
1400
+					'callback' => isset($cfg['callback']) && empty($content) ? [$this, $cfg['callback']] : null,
1401
+					'content'  => $content,
1402
+				];
1403
+				$this->_current_screen->add_help_tab($_ht);
1404
+			}
1405
+		}
1406
+	}
1407
+
1408
+
1409
+	/**
1410
+	 * This simply sets up any qtips that have been defined in the page config
1411
+	 *
1412
+	 * @return void
1413
+	 * @throws ReflectionException
1414
+	 * @throws EE_Error
1415
+	 */
1416
+	protected function _add_qtips()
1417
+	{
1418
+		if (isset($this->_route_config['qtips'])) {
1419
+			$qtips = (array) $this->_route_config['qtips'];
1420
+			// load qtip loader
1421
+			$path = [
1422
+				$this->_get_dir() . '/qtips/',
1423
+				EE_ADMIN_PAGES . basename($this->_get_dir()) . '/qtips/',
1424
+			];
1425
+			EEH_Qtip_Loader::instance()->register($qtips, $path);
1426
+		}
1427
+	}
1428
+
1429
+
1430
+	/**
1431
+	 * _set_nav_tabs
1432
+	 * This sets up the nav tabs from the page_routes array.  This method can be overwritten by child classes if you
1433
+	 * wish to add additional tabs or modify accordingly.
1434
+	 *
1435
+	 * @return void
1436
+	 * @throws InvalidArgumentException
1437
+	 * @throws InvalidInterfaceException
1438
+	 * @throws InvalidDataTypeException
1439
+	 */
1440
+	protected function _set_nav_tabs()
1441
+	{
1442
+		$i        = 0;
1443
+		$only_tab = count($this->_page_config) < 2;
1444
+		foreach ($this->_page_config as $slug => $config) {
1445
+			if (! is_array($config) || empty($config['nav'])) {
1446
+				continue;
1447
+			}
1448
+			// no nav tab for this config
1449
+			// check for persistent flag
1450
+			if ($slug !== $this->_req_action && isset($config['nav']['persistent']) && ! $config['nav']['persistent']) {
1451
+				// nav tab is only to appear when route requested.
1452
+				continue;
1453
+			}
1454
+			if (! $this->check_user_access($slug, true)) {
1455
+				// no nav tab because current user does not have access.
1456
+				continue;
1457
+			}
1458
+			$css_class = $config['css_class'] ?? '';
1459
+			$css_class .= $only_tab ? ' ee-only-tab' : '';
1460
+			$css_class .= " ee-nav-tab__$slug";
1461
+
1462
+			$this->_nav_tabs[ $slug ] = [
1463
+				'url'       => $config['nav']['url'] ?? EE_Admin_Page::add_query_args_and_nonce(
1464
+					['action' => $slug],
1465
+					$this->_admin_base_url
1466
+				),
1467
+				'link_text' => $this->navTabLabel($config['nav'], $slug),
1468
+				'css_class' => $this->_req_action === $slug ? $css_class . ' nav-tab-active' : $css_class,
1469
+				'order'     => $config['nav']['order'] ?? $i,
1470
+			];
1471
+			$i++;
1472
+		}
1473
+		// if $this->_nav_tabs is empty then lets set the default
1474
+		if (empty($this->_nav_tabs)) {
1475
+			$this->_nav_tabs[ $this->_default_nav_tab_name ] = [
1476
+				'url'       => $this->_admin_base_url,
1477
+				'link_text' => ucwords(str_replace('_', ' ', $this->_default_nav_tab_name)),
1478
+				'css_class' => 'nav-tab-active',
1479
+				'order'     => 10,
1480
+			];
1481
+		}
1482
+		// now let's sort the tabs according to order
1483
+		usort($this->_nav_tabs, [$this, '_sort_nav_tabs']);
1484
+	}
1485
+
1486
+
1487
+	private function navTabLabel(array $nav_tab, string $slug): string
1488
+	{
1489
+		$label = $nav_tab['label'] ?? ucwords(str_replace('_', ' ', $slug));
1490
+		$icon  = $nav_tab['icon'] ?? null;
1491
+		$icon  = $icon ? '<span class="dashicons ' . $icon . '"></span>' : '';
1492
+		return '
1493 1493
             <span class="ee-admin-screen-tab__label">
1494 1494
                 ' . $icon . '
1495 1495
                 <span class="ee-nav-label__text">' . $label . '</span>
1496 1496
             </span>';
1497
-    }
1498
-
1499
-
1500
-    /**
1501
-     * _set_current_labels
1502
-     * This method modifies the _labels property with any optional specific labels indicated in the _page_routes
1503
-     * property array
1504
-     *
1505
-     * @return void
1506
-     */
1507
-    private function _set_current_labels()
1508
-    {
1509
-        if (isset($this->_route_config['labels'])) {
1510
-            foreach ($this->_route_config['labels'] as $label => $text) {
1511
-                if (is_array($text)) {
1512
-                    foreach ($text as $sublabel => $subtext) {
1513
-                        $this->_labels[ $label ][ $sublabel ] = $subtext;
1514
-                    }
1515
-                } else {
1516
-                    $this->_labels[ $label ] = $text;
1517
-                }
1518
-            }
1519
-        }
1520
-    }
1521
-
1522
-
1523
-    /**
1524
-     *        verifies user access for this admin page
1525
-     *
1526
-     * @param string $route_to_check if present then the capability for the route matching this string is checked.
1527
-     * @param bool   $verify_only    Default is FALSE which means if user check fails then wp_die().  Otherwise just
1528
-     *                               return false if verify fail.
1529
-     * @return bool
1530
-     * @throws InvalidArgumentException
1531
-     * @throws InvalidDataTypeException
1532
-     * @throws InvalidInterfaceException
1533
-     */
1534
-    public function check_user_access(string $route_to_check = '', bool $verify_only = false): bool
1535
-    {
1536
-        // if no route_to_check is passed in then use the current route set via _req_action
1537
-        $action = $route_to_check ?: $this->_req_action;
1538
-        $capability = ! empty($this->_page_routes[ $action ]['capability'])
1539
-            ? $this->_page_routes[ $action ]['capability']
1540
-            : null;
1541
-
1542
-        if (empty($capability)) {
1543
-            $capability = empty($route_to_check) && ! empty($this->_route['capability'])
1544
-                ? $this->_route['capability']
1545
-                : 'manage_options';
1546
-        }
1547
-
1548
-        $id = $this->_route['obj_id'] ?? 0;
1549
-
1550
-        if (
1551
-            ! $this->request->isAjax()
1552
-            && (
1553
-                ! function_exists('is_admin')
1554
-                || ! $this->capabilities->current_user_can($capability, "{$this->page_slug}_$route_to_check", $id)
1555
-            )
1556
-        ) {
1557
-            if ($verify_only) {
1558
-                return false;
1559
-            }
1560
-            if (is_user_logged_in()) {
1561
-                wp_die(esc_html__('You do not have access to this route.', 'event_espresso'));
1562
-            }
1563
-            return false;
1564
-        }
1565
-        return true;
1566
-    }
1567
-
1568
-
1569
-    /**
1570
-     * @param string                 $box_id
1571
-     * @param string                 $title
1572
-     * @param callable|string|null   $callback
1573
-     * @param string|array|WP_Screen $screen
1574
-     * @param string                 $context       Post edit screen contexts include 'normal', 'side', and 'advanced'.
1575
-     *                                              Comments screen contexts include 'normal' and 'side'.
1576
-     *                                              Menus meta boxes (accordion sections) all use the 'side' context.
1577
-     * @param string                 $priority      Accepts 'high', 'core', 'default', or 'low'.
1578
-     * @param array|null             $callback_args
1579
-     */
1580
-    protected function addMetaBox(
1581
-        string $box_id,
1582
-        string $title,
1583
-        $callback,
1584
-        $screen,
1585
-        string $context = 'normal',
1586
-        string $priority = 'default',
1587
-        ?array $callback_args = null
1588
-    ) {
1589
-        if (! (is_callable($callback) || ! function_exists($callback))) {
1590
-            return;
1591
-        }
1592
-
1593
-        add_meta_box($box_id, $title, $callback, $screen, $context, $priority, $callback_args);
1594
-        add_filter(
1595
-            "postbox_classes_{$this->_wp_page_slug}_$box_id",
1596
-            function ($classes) {
1597
-                $classes[] = 'ee-admin-container';
1598
-                return $classes;
1599
-            }
1600
-        );
1601
-    }
1602
-
1603
-
1604
-    /**
1605
-     * admin_init_global
1606
-     * This runs all the code that we want executed within the WP admin_init hook.
1607
-     * This method executes for ALL EE Admin pages.
1608
-     *
1609
-     * @return void
1610
-     */
1611
-    public function admin_init_global()
1612
-    {
1613
-    }
1614
-
1615
-
1616
-    /**
1617
-     * wp_loaded_global
1618
-     * This runs all the code that we want executed within the WP wp_loaded hook.  This method is optional for an
1619
-     * EE_Admin page and will execute on every EE Admin Page load
1620
-     *
1621
-     * @return void
1622
-     */
1623
-    public function wp_loaded()
1624
-    {
1625
-    }
1626
-
1627
-
1628
-    /**
1629
-     * admin_notices
1630
-     * Anything triggered by the 'admin_notices' WP hook should be put in here.  This particular method will apply on
1631
-     * ALL EE_Admin pages.
1632
-     *
1633
-     * @return void
1634
-     */
1635
-    public function admin_notices_global()
1636
-    {
1637
-        $this->_display_no_javascript_warning();
1638
-        $this->_display_espresso_notices();
1639
-    }
1640
-
1641
-
1642
-    public function network_admin_notices_global()
1643
-    {
1644
-        $this->_display_no_javascript_warning();
1645
-        $this->_display_espresso_notices();
1646
-    }
1647
-
1648
-
1649
-    /**
1650
-     * admin_footer_scripts_global
1651
-     * Anything triggered by the 'admin_print_footer_scripts' WP hook should be put in here. This particular method
1652
-     * will apply on ALL EE_Admin pages.
1653
-     *
1654
-     * @return void
1655
-     */
1656
-    public function admin_footer_scripts_global()
1657
-    {
1658
-        $this->_add_admin_page_ajax_loading_img();
1659
-        $this->_add_admin_page_overlay();
1660
-        // if metaboxes are present we need to add the nonce field
1661
-        if (
1662
-            isset($this->_route_config['metaboxes'])
1663
-            || isset($this->_route_config['list_table'])
1664
-            || (isset($this->_route_config['has_metaboxes']) && $this->_route_config['has_metaboxes'])
1665
-        ) {
1666
-            wp_nonce_field('closedpostboxes', 'closedpostboxesnonce', false);
1667
-            wp_nonce_field('meta-box-order', 'meta-box-order-nonce', false);
1668
-        }
1669
-    }
1670
-
1671
-
1672
-    /**
1673
-     * admin_footer_global
1674
-     * Anything triggered by the wp 'admin_footer' wp hook should be put in here.
1675
-     * This particular method will apply on ALL EE_Admin Pages.
1676
-     *
1677
-     * @return void
1678
-     */
1679
-    public function admin_footer_global()
1680
-    {
1681
-        // dialog container for dialog helper
1682
-        echo '
1497
+	}
1498
+
1499
+
1500
+	/**
1501
+	 * _set_current_labels
1502
+	 * This method modifies the _labels property with any optional specific labels indicated in the _page_routes
1503
+	 * property array
1504
+	 *
1505
+	 * @return void
1506
+	 */
1507
+	private function _set_current_labels()
1508
+	{
1509
+		if (isset($this->_route_config['labels'])) {
1510
+			foreach ($this->_route_config['labels'] as $label => $text) {
1511
+				if (is_array($text)) {
1512
+					foreach ($text as $sublabel => $subtext) {
1513
+						$this->_labels[ $label ][ $sublabel ] = $subtext;
1514
+					}
1515
+				} else {
1516
+					$this->_labels[ $label ] = $text;
1517
+				}
1518
+			}
1519
+		}
1520
+	}
1521
+
1522
+
1523
+	/**
1524
+	 *        verifies user access for this admin page
1525
+	 *
1526
+	 * @param string $route_to_check if present then the capability for the route matching this string is checked.
1527
+	 * @param bool   $verify_only    Default is FALSE which means if user check fails then wp_die().  Otherwise just
1528
+	 *                               return false if verify fail.
1529
+	 * @return bool
1530
+	 * @throws InvalidArgumentException
1531
+	 * @throws InvalidDataTypeException
1532
+	 * @throws InvalidInterfaceException
1533
+	 */
1534
+	public function check_user_access(string $route_to_check = '', bool $verify_only = false): bool
1535
+	{
1536
+		// if no route_to_check is passed in then use the current route set via _req_action
1537
+		$action = $route_to_check ?: $this->_req_action;
1538
+		$capability = ! empty($this->_page_routes[ $action ]['capability'])
1539
+			? $this->_page_routes[ $action ]['capability']
1540
+			: null;
1541
+
1542
+		if (empty($capability)) {
1543
+			$capability = empty($route_to_check) && ! empty($this->_route['capability'])
1544
+				? $this->_route['capability']
1545
+				: 'manage_options';
1546
+		}
1547
+
1548
+		$id = $this->_route['obj_id'] ?? 0;
1549
+
1550
+		if (
1551
+			! $this->request->isAjax()
1552
+			&& (
1553
+				! function_exists('is_admin')
1554
+				|| ! $this->capabilities->current_user_can($capability, "{$this->page_slug}_$route_to_check", $id)
1555
+			)
1556
+		) {
1557
+			if ($verify_only) {
1558
+				return false;
1559
+			}
1560
+			if (is_user_logged_in()) {
1561
+				wp_die(esc_html__('You do not have access to this route.', 'event_espresso'));
1562
+			}
1563
+			return false;
1564
+		}
1565
+		return true;
1566
+	}
1567
+
1568
+
1569
+	/**
1570
+	 * @param string                 $box_id
1571
+	 * @param string                 $title
1572
+	 * @param callable|string|null   $callback
1573
+	 * @param string|array|WP_Screen $screen
1574
+	 * @param string                 $context       Post edit screen contexts include 'normal', 'side', and 'advanced'.
1575
+	 *                                              Comments screen contexts include 'normal' and 'side'.
1576
+	 *                                              Menus meta boxes (accordion sections) all use the 'side' context.
1577
+	 * @param string                 $priority      Accepts 'high', 'core', 'default', or 'low'.
1578
+	 * @param array|null             $callback_args
1579
+	 */
1580
+	protected function addMetaBox(
1581
+		string $box_id,
1582
+		string $title,
1583
+		$callback,
1584
+		$screen,
1585
+		string $context = 'normal',
1586
+		string $priority = 'default',
1587
+		?array $callback_args = null
1588
+	) {
1589
+		if (! (is_callable($callback) || ! function_exists($callback))) {
1590
+			return;
1591
+		}
1592
+
1593
+		add_meta_box($box_id, $title, $callback, $screen, $context, $priority, $callback_args);
1594
+		add_filter(
1595
+			"postbox_classes_{$this->_wp_page_slug}_$box_id",
1596
+			function ($classes) {
1597
+				$classes[] = 'ee-admin-container';
1598
+				return $classes;
1599
+			}
1600
+		);
1601
+	}
1602
+
1603
+
1604
+	/**
1605
+	 * admin_init_global
1606
+	 * This runs all the code that we want executed within the WP admin_init hook.
1607
+	 * This method executes for ALL EE Admin pages.
1608
+	 *
1609
+	 * @return void
1610
+	 */
1611
+	public function admin_init_global()
1612
+	{
1613
+	}
1614
+
1615
+
1616
+	/**
1617
+	 * wp_loaded_global
1618
+	 * This runs all the code that we want executed within the WP wp_loaded hook.  This method is optional for an
1619
+	 * EE_Admin page and will execute on every EE Admin Page load
1620
+	 *
1621
+	 * @return void
1622
+	 */
1623
+	public function wp_loaded()
1624
+	{
1625
+	}
1626
+
1627
+
1628
+	/**
1629
+	 * admin_notices
1630
+	 * Anything triggered by the 'admin_notices' WP hook should be put in here.  This particular method will apply on
1631
+	 * ALL EE_Admin pages.
1632
+	 *
1633
+	 * @return void
1634
+	 */
1635
+	public function admin_notices_global()
1636
+	{
1637
+		$this->_display_no_javascript_warning();
1638
+		$this->_display_espresso_notices();
1639
+	}
1640
+
1641
+
1642
+	public function network_admin_notices_global()
1643
+	{
1644
+		$this->_display_no_javascript_warning();
1645
+		$this->_display_espresso_notices();
1646
+	}
1647
+
1648
+
1649
+	/**
1650
+	 * admin_footer_scripts_global
1651
+	 * Anything triggered by the 'admin_print_footer_scripts' WP hook should be put in here. This particular method
1652
+	 * will apply on ALL EE_Admin pages.
1653
+	 *
1654
+	 * @return void
1655
+	 */
1656
+	public function admin_footer_scripts_global()
1657
+	{
1658
+		$this->_add_admin_page_ajax_loading_img();
1659
+		$this->_add_admin_page_overlay();
1660
+		// if metaboxes are present we need to add the nonce field
1661
+		if (
1662
+			isset($this->_route_config['metaboxes'])
1663
+			|| isset($this->_route_config['list_table'])
1664
+			|| (isset($this->_route_config['has_metaboxes']) && $this->_route_config['has_metaboxes'])
1665
+		) {
1666
+			wp_nonce_field('closedpostboxes', 'closedpostboxesnonce', false);
1667
+			wp_nonce_field('meta-box-order', 'meta-box-order-nonce', false);
1668
+		}
1669
+	}
1670
+
1671
+
1672
+	/**
1673
+	 * admin_footer_global
1674
+	 * Anything triggered by the wp 'admin_footer' wp hook should be put in here.
1675
+	 * This particular method will apply on ALL EE_Admin Pages.
1676
+	 *
1677
+	 * @return void
1678
+	 */
1679
+	public function admin_footer_global()
1680
+	{
1681
+		// dialog container for dialog helper
1682
+		echo '
1683 1683
         <div class="ee-admin-dialog-container auto-hide hidden">
1684 1684
             <div class="ee-notices"></div>
1685 1685
             <div class="ee-admin-dialog-container-inner-content"></div>
1686 1686
         </div>
1687 1687
         <span id="current_timezone" class="hidden">' . esc_html(EEH_DTT_Helper::get_timezone()) . '</span>
1688 1688
         <input type="hidden" id="espresso_admin_current_page" value="' . esc_attr($this->_current_page) . '"/>';
1689
-    }
1690
-
1691
-
1692
-    /**
1693
-     * This function sees if there is a method for help popup content existing for the given route.  If there is then
1694
-     * we'll use the retrieved array to output the content using the template. For child classes: If you want to have
1695
-     * help popups then in your templates or your content you set "triggers" for the content using the
1696
-     * "_set_help_trigger('help_trigger_id')" where "help_trigger_id" is what you will use later in your custom method
1697
-     * for the help popup content on that page. Then in your Child_Admin_Page class you need to define a help popup
1698
-     * method for the content in the format "_help_popup_content_{route_name}()"  So if you are setting help content
1699
-     * for the
1700
-     * 'edit_event' route you should have a method named "_help_popup_content_edit_route". In your defined
1701
-     * "help_popup_content_..." method.  You must prepare and return an array in the following format array(
1702
-     *    'help_trigger_id' => array(
1703
-     *        'title' => esc_html__('localized title for popup', 'event_espresso'),
1704
-     *        'content' => esc_html__('localized content for popup', 'event_espresso')
1705
-     *    )
1706
-     * );
1707
-     * Then the EE_Admin_Parent will take care of making sure that is set up properly on the correct route.
1708
-     *
1709
-     * @param array $help_array
1710
-     * @param bool  $display
1711
-     * @return string content
1712
-     * @throws DomainException
1713
-     * @throws EE_Error
1714
-     */
1715
-    protected function _set_help_popup_content(array $help_array = [], bool $display = false): string
1716
-    {
1717
-        $content    = '';
1718
-        $help_array = empty($help_array) ? $this->_get_help_content() : $help_array;
1719
-        // loop through the array and setup content
1720
-        foreach ($help_array as $trigger => $help) {
1721
-            // make sure the array is set up properly
1722
-            if (! isset($help['title'], $help['content'])) {
1723
-                throw new EE_Error(
1724
-                    esc_html__(
1725
-                        'Does not look like the popup content array has been setup correctly.  Might want to double check that.  Read the comments for the _get_help_popup_content method found in "EE_Admin_Page" class',
1726
-                        'event_espresso'
1727
-                    )
1728
-                );
1729
-            }
1730
-            // we're good so let's set up the template vars and then assign parsed template content to our content.
1731
-            $template_args = [
1732
-                'help_popup_id'      => $trigger,
1733
-                'help_popup_title'   => $help['title'],
1734
-                'help_popup_content' => $help['content'],
1735
-            ];
1736
-            $content       .= EEH_Template::display_template(
1737
-                EE_ADMIN_TEMPLATE . 'admin_help_popup.template.php',
1738
-                $template_args,
1739
-                true
1740
-            );
1741
-        }
1742
-        if ($display) {
1743
-            echo wp_kses($content, AllowedTags::getWithFormTags());
1744
-            return '';
1745
-        }
1746
-        return $content;
1747
-    }
1748
-
1749
-
1750
-    /**
1751
-     * All this does is retrieve the help content array if set by the EE_Admin_Page child
1752
-     *
1753
-     * @return array properly formatted array for help popup content
1754
-     * @throws EE_Error
1755
-     */
1756
-    private function _get_help_content(): array
1757
-    {
1758
-        // what is the method we're looking for?
1759
-        $method_name = '_help_popup_content_' . $this->_req_action;
1760
-        // if method doesn't exist let's get out.
1761
-        if (! method_exists($this, $method_name)) {
1762
-            return [];
1763
-        }
1764
-        // k we're good to go let's retrieve the help array
1765
-        $help_array = $this->{$method_name}();
1766
-        // make sure we've got an array!
1767
-        if (! is_array($help_array)) {
1768
-            throw new EE_Error(
1769
-                esc_html__(
1770
-                    'Something went wrong with help popup content generation. Expecting an array and well, this ain\'t no array bub.',
1771
-                    'event_espresso'
1772
-                )
1773
-            );
1774
-        }
1775
-        return $help_array;
1776
-    }
1777
-
1778
-
1779
-    /**
1780
-     * EE Admin Pages can use this to set a properly formatted trigger for a help popup.
1781
-     * By default the trigger html is printed.  Otherwise it can be returned if the $display flag is set "false"
1782
-     * See comments made on the _set_help_content method for understanding other parts to the help popup tool.
1783
-     *
1784
-     * @param string $trigger_id reference for retrieving the trigger content for the popup
1785
-     * @param bool   $display    if false then we return the trigger string
1786
-     * @param array  $dimensions an array of dimensions for the box (array(h,w))
1787
-     * @return string
1788
-     * @throws DomainException
1789
-     * @throws EE_Error
1790
-     */
1791
-    protected function _set_help_trigger(string $trigger_id, bool $display = true, array $dimensions = ['400', '640'])
1792
-    {
1793
-        if ($this->request->isAjax()) {
1794
-            return '';
1795
-        }
1796
-        // let's check and see if there is any content set for this popup.  If there isn't then we'll include a default title and content so that developers know something needs to be corrected
1797
-        $help_array   = $this->_get_help_content();
1798
-        $help_content = '';
1799
-        if (empty($help_array) || ! isset($help_array[ $trigger_id ])) {
1800
-            $help_array[ $trigger_id ] = [
1801
-                'title'   => esc_html__('Missing Content', 'event_espresso'),
1802
-                'content' => esc_html__(
1803
-                    'A trigger has been set that doesn\'t have any corresponding content. Make sure you have set the help content. (see the "_set_help_popup_content" method in the EE_Admin_Page for instructions.)',
1804
-                    'event_espresso'
1805
-                ),
1806
-            ];
1807
-            $help_content              = $this->_set_help_popup_content($help_array);
1808
-        }
1809
-        $height   = esc_attr($dimensions[0]) ?? 400;
1810
-        $width    = esc_attr($dimensions[1]) ?? 640;
1811
-        $inlineId = esc_attr($trigger_id);
1812
-        // let's setup the trigger
1813
-        $content = "
1689
+	}
1690
+
1691
+
1692
+	/**
1693
+	 * This function sees if there is a method for help popup content existing for the given route.  If there is then
1694
+	 * we'll use the retrieved array to output the content using the template. For child classes: If you want to have
1695
+	 * help popups then in your templates or your content you set "triggers" for the content using the
1696
+	 * "_set_help_trigger('help_trigger_id')" where "help_trigger_id" is what you will use later in your custom method
1697
+	 * for the help popup content on that page. Then in your Child_Admin_Page class you need to define a help popup
1698
+	 * method for the content in the format "_help_popup_content_{route_name}()"  So if you are setting help content
1699
+	 * for the
1700
+	 * 'edit_event' route you should have a method named "_help_popup_content_edit_route". In your defined
1701
+	 * "help_popup_content_..." method.  You must prepare and return an array in the following format array(
1702
+	 *    'help_trigger_id' => array(
1703
+	 *        'title' => esc_html__('localized title for popup', 'event_espresso'),
1704
+	 *        'content' => esc_html__('localized content for popup', 'event_espresso')
1705
+	 *    )
1706
+	 * );
1707
+	 * Then the EE_Admin_Parent will take care of making sure that is set up properly on the correct route.
1708
+	 *
1709
+	 * @param array $help_array
1710
+	 * @param bool  $display
1711
+	 * @return string content
1712
+	 * @throws DomainException
1713
+	 * @throws EE_Error
1714
+	 */
1715
+	protected function _set_help_popup_content(array $help_array = [], bool $display = false): string
1716
+	{
1717
+		$content    = '';
1718
+		$help_array = empty($help_array) ? $this->_get_help_content() : $help_array;
1719
+		// loop through the array and setup content
1720
+		foreach ($help_array as $trigger => $help) {
1721
+			// make sure the array is set up properly
1722
+			if (! isset($help['title'], $help['content'])) {
1723
+				throw new EE_Error(
1724
+					esc_html__(
1725
+						'Does not look like the popup content array has been setup correctly.  Might want to double check that.  Read the comments for the _get_help_popup_content method found in "EE_Admin_Page" class',
1726
+						'event_espresso'
1727
+					)
1728
+				);
1729
+			}
1730
+			// we're good so let's set up the template vars and then assign parsed template content to our content.
1731
+			$template_args = [
1732
+				'help_popup_id'      => $trigger,
1733
+				'help_popup_title'   => $help['title'],
1734
+				'help_popup_content' => $help['content'],
1735
+			];
1736
+			$content       .= EEH_Template::display_template(
1737
+				EE_ADMIN_TEMPLATE . 'admin_help_popup.template.php',
1738
+				$template_args,
1739
+				true
1740
+			);
1741
+		}
1742
+		if ($display) {
1743
+			echo wp_kses($content, AllowedTags::getWithFormTags());
1744
+			return '';
1745
+		}
1746
+		return $content;
1747
+	}
1748
+
1749
+
1750
+	/**
1751
+	 * All this does is retrieve the help content array if set by the EE_Admin_Page child
1752
+	 *
1753
+	 * @return array properly formatted array for help popup content
1754
+	 * @throws EE_Error
1755
+	 */
1756
+	private function _get_help_content(): array
1757
+	{
1758
+		// what is the method we're looking for?
1759
+		$method_name = '_help_popup_content_' . $this->_req_action;
1760
+		// if method doesn't exist let's get out.
1761
+		if (! method_exists($this, $method_name)) {
1762
+			return [];
1763
+		}
1764
+		// k we're good to go let's retrieve the help array
1765
+		$help_array = $this->{$method_name}();
1766
+		// make sure we've got an array!
1767
+		if (! is_array($help_array)) {
1768
+			throw new EE_Error(
1769
+				esc_html__(
1770
+					'Something went wrong with help popup content generation. Expecting an array and well, this ain\'t no array bub.',
1771
+					'event_espresso'
1772
+				)
1773
+			);
1774
+		}
1775
+		return $help_array;
1776
+	}
1777
+
1778
+
1779
+	/**
1780
+	 * EE Admin Pages can use this to set a properly formatted trigger for a help popup.
1781
+	 * By default the trigger html is printed.  Otherwise it can be returned if the $display flag is set "false"
1782
+	 * See comments made on the _set_help_content method for understanding other parts to the help popup tool.
1783
+	 *
1784
+	 * @param string $trigger_id reference for retrieving the trigger content for the popup
1785
+	 * @param bool   $display    if false then we return the trigger string
1786
+	 * @param array  $dimensions an array of dimensions for the box (array(h,w))
1787
+	 * @return string
1788
+	 * @throws DomainException
1789
+	 * @throws EE_Error
1790
+	 */
1791
+	protected function _set_help_trigger(string $trigger_id, bool $display = true, array $dimensions = ['400', '640'])
1792
+	{
1793
+		if ($this->request->isAjax()) {
1794
+			return '';
1795
+		}
1796
+		// let's check and see if there is any content set for this popup.  If there isn't then we'll include a default title and content so that developers know something needs to be corrected
1797
+		$help_array   = $this->_get_help_content();
1798
+		$help_content = '';
1799
+		if (empty($help_array) || ! isset($help_array[ $trigger_id ])) {
1800
+			$help_array[ $trigger_id ] = [
1801
+				'title'   => esc_html__('Missing Content', 'event_espresso'),
1802
+				'content' => esc_html__(
1803
+					'A trigger has been set that doesn\'t have any corresponding content. Make sure you have set the help content. (see the "_set_help_popup_content" method in the EE_Admin_Page for instructions.)',
1804
+					'event_espresso'
1805
+				),
1806
+			];
1807
+			$help_content              = $this->_set_help_popup_content($help_array);
1808
+		}
1809
+		$height   = esc_attr($dimensions[0]) ?? 400;
1810
+		$width    = esc_attr($dimensions[1]) ?? 640;
1811
+		$inlineId = esc_attr($trigger_id);
1812
+		// let's setup the trigger
1813
+		$content = "
1814 1814
         <a class='ee-dialog' href='?height=$height&width=$width&inlineId=$inlineId' target='_blank'>
1815 1815
             <span class='question ee-help-popup-question'></span>
1816 1816
         </a>";
1817
-        $content .= $help_content;
1818
-        if ($display) {
1819
-            echo wp_kses($content, AllowedTags::getWithFormTags());
1820
-            return '';
1821
-        }
1822
-        return $content;
1823
-    }
1824
-
1825
-
1826
-    /**
1827
-     * _add_global_screen_options
1828
-     * Add any extra wp_screen_options within this method using built-in WP functions/methods for doing so.
1829
-     * This particular method will add_screen_options on ALL EE_Admin Pages
1830
-     *
1831
-     * @link   http://chrismarslender.com/wp-tutorials/wordpress-screen-options-tutorial/
1832
-     *         see also WP_Screen object documents...
1833
-     * @link   http://codex.wordpress.org/Class_Reference/WP_Screen
1834
-     * @abstract
1835
-     * @return void
1836
-     */
1837
-    private function _add_global_screen_options()
1838
-    {
1839
-    }
1840
-
1841
-
1842
-    /**
1843
-     * _add_global_feature_pointers
1844
-     * This method is used for implementing any "feature pointers" (using built-in WP styling js).
1845
-     * This particular method will implement feature pointers for ALL EE_Admin pages.
1846
-     * Note: this is just a placeholder for now.  Implementation will come down the road
1847
-     *
1848
-     * @see    WP_Internal_Pointers class in wp-admin/includes/template.php for example (it's a final class so can't be
1849
-     *         extended) also see:
1850
-     * @link   http://eamann.com/tech/wordpress-portland/
1851
-     * @abstract
1852
-     * @return void
1853
-     */
1854
-    private function _add_global_feature_pointers()
1855
-    {
1856
-    }
1857
-
1858
-
1859
-    /**
1860
-     * load_global_scripts_styles
1861
-     * The scripts and styles enqueued in here will be loaded on every EE Admin page
1862
-     *
1863
-     * @return void
1864
-     */
1865
-    public function load_global_scripts_styles()
1866
-    {
1867
-        // add debugging styles
1868
-        if (WP_DEBUG) {
1869
-            add_action('admin_head', [$this, 'add_xdebug_style']);
1870
-        }
1871
-        // taking care of metaboxes
1872
-        if (
1873
-            empty($this->_cpt_route)
1874
-            && (isset($this->_route_config['metaboxes']) || isset($this->_route_config['has_metaboxes']))
1875
-        ) {
1876
-            wp_enqueue_script('dashboard');
1877
-        }
1878
-
1879
-        wp_enqueue_script(JqueryAssetManager::JS_HANDLE_JQUERY_UI_TOUCH_PUNCH);
1880
-        wp_enqueue_script(EspressoLegacyAdminAssetManager::JS_HANDLE_EE_ADMIN);
1881
-        // LOCALIZED DATA
1882
-        // localize script for ajax lazy loading
1883
-        wp_localize_script(
1884
-            EspressoLegacyAdminAssetManager::JS_HANDLE_EE_ADMIN,
1885
-            'eeLazyLoadingContainers',
1886
-            apply_filters(
1887
-                'FHEE__EE_Admin_Page_Core__load_global_scripts_styles__loader_containers',
1888
-                ['espresso_news_post_box_content']
1889
-            )
1890
-        );
1891
-        StatusChangeNotice::loadAssets();
1892
-
1893
-        add_filter(
1894
-            'admin_body_class',
1895
-            function ($classes) {
1896
-                if (strpos($classes, 'espresso-admin') === false) {
1897
-                    $classes .= ' espresso-admin';
1898
-                }
1899
-                return $classes;
1900
-            }
1901
-        );
1902
-    }
1903
-
1904
-
1905
-    /**
1906
-     *        admin_footer_scripts_eei18n_js_strings
1907
-     *
1908
-     * @return        void
1909
-     */
1910
-    public function admin_footer_scripts_eei18n_js_strings()
1911
-    {
1912
-        EE_Registry::$i18n_js_strings['confirm_delete'] = wp_strip_all_tags(
1913
-            __(
1914
-                'Are you absolutely sure you want to delete this item?\nThis action will delete ALL DATA associated with this item!!!\nThis can NOT be undone!!!',
1915
-                'event_espresso'
1916
-            )
1917
-        );
1918
-        // now add months and days of the week
1919
-        EE_Registry::$i18n_js_strings['January']   = wp_strip_all_tags(__('January', 'event_espresso'));
1920
-        EE_Registry::$i18n_js_strings['February']  = wp_strip_all_tags(__('February', 'event_espresso'));
1921
-        EE_Registry::$i18n_js_strings['March']     = wp_strip_all_tags(__('March', 'event_espresso'));
1922
-        EE_Registry::$i18n_js_strings['April']     = wp_strip_all_tags(__('April', 'event_espresso'));
1923
-        EE_Registry::$i18n_js_strings['May']       = wp_strip_all_tags(__('May', 'event_espresso'));
1924
-        EE_Registry::$i18n_js_strings['June']      = wp_strip_all_tags(__('June', 'event_espresso'));
1925
-        EE_Registry::$i18n_js_strings['July']      = wp_strip_all_tags(__('July', 'event_espresso'));
1926
-        EE_Registry::$i18n_js_strings['August']    = wp_strip_all_tags(__('August', 'event_espresso'));
1927
-        EE_Registry::$i18n_js_strings['September'] = wp_strip_all_tags(__('September', 'event_espresso'));
1928
-        EE_Registry::$i18n_js_strings['October']   = wp_strip_all_tags(__('October', 'event_espresso'));
1929
-        EE_Registry::$i18n_js_strings['November']  = wp_strip_all_tags(__('November', 'event_espresso'));
1930
-        EE_Registry::$i18n_js_strings['December']  = wp_strip_all_tags(__('December', 'event_espresso'));
1931
-        EE_Registry::$i18n_js_strings['Jan']       = wp_strip_all_tags(__('Jan', 'event_espresso'));
1932
-        EE_Registry::$i18n_js_strings['Feb']       = wp_strip_all_tags(__('Feb', 'event_espresso'));
1933
-        EE_Registry::$i18n_js_strings['Mar']       = wp_strip_all_tags(__('Mar', 'event_espresso'));
1934
-        EE_Registry::$i18n_js_strings['Apr']       = wp_strip_all_tags(__('Apr', 'event_espresso'));
1935
-        EE_Registry::$i18n_js_strings['May']       = wp_strip_all_tags(__('May', 'event_espresso'));
1936
-        EE_Registry::$i18n_js_strings['Jun']       = wp_strip_all_tags(__('Jun', 'event_espresso'));
1937
-        EE_Registry::$i18n_js_strings['Jul']       = wp_strip_all_tags(__('Jul', 'event_espresso'));
1938
-        EE_Registry::$i18n_js_strings['Aug']       = wp_strip_all_tags(__('Aug', 'event_espresso'));
1939
-        EE_Registry::$i18n_js_strings['Sep']       = wp_strip_all_tags(__('Sep', 'event_espresso'));
1940
-        EE_Registry::$i18n_js_strings['Oct']       = wp_strip_all_tags(__('Oct', 'event_espresso'));
1941
-        EE_Registry::$i18n_js_strings['Nov']       = wp_strip_all_tags(__('Nov', 'event_espresso'));
1942
-        EE_Registry::$i18n_js_strings['Dec']       = wp_strip_all_tags(__('Dec', 'event_espresso'));
1943
-        EE_Registry::$i18n_js_strings['Sunday']    = wp_strip_all_tags(__('Sunday', 'event_espresso'));
1944
-        EE_Registry::$i18n_js_strings['Monday']    = wp_strip_all_tags(__('Monday', 'event_espresso'));
1945
-        EE_Registry::$i18n_js_strings['Tuesday']   = wp_strip_all_tags(__('Tuesday', 'event_espresso'));
1946
-        EE_Registry::$i18n_js_strings['Wednesday'] = wp_strip_all_tags(__('Wednesday', 'event_espresso'));
1947
-        EE_Registry::$i18n_js_strings['Thursday']  = wp_strip_all_tags(__('Thursday', 'event_espresso'));
1948
-        EE_Registry::$i18n_js_strings['Friday']    = wp_strip_all_tags(__('Friday', 'event_espresso'));
1949
-        EE_Registry::$i18n_js_strings['Saturday']  = wp_strip_all_tags(__('Saturday', 'event_espresso'));
1950
-        EE_Registry::$i18n_js_strings['Sun']       = wp_strip_all_tags(__('Sun', 'event_espresso'));
1951
-        EE_Registry::$i18n_js_strings['Mon']       = wp_strip_all_tags(__('Mon', 'event_espresso'));
1952
-        EE_Registry::$i18n_js_strings['Tue']       = wp_strip_all_tags(__('Tue', 'event_espresso'));
1953
-        EE_Registry::$i18n_js_strings['Wed']       = wp_strip_all_tags(__('Wed', 'event_espresso'));
1954
-        EE_Registry::$i18n_js_strings['Thu']       = wp_strip_all_tags(__('Thu', 'event_espresso'));
1955
-        EE_Registry::$i18n_js_strings['Fri']       = wp_strip_all_tags(__('Fri', 'event_espresso'));
1956
-        EE_Registry::$i18n_js_strings['Sat']       = wp_strip_all_tags(__('Sat', 'event_espresso'));
1957
-    }
1958
-
1959
-
1960
-    /**
1961
-     *        load enhanced xdebug styles for ppl with failing eyesight
1962
-     *
1963
-     * @return        void
1964
-     */
1965
-    public function add_xdebug_style()
1966
-    {
1967
-        echo '<style>.xdebug-error { font-size:1.5em; }</style>';
1968
-    }
1969
-
1970
-
1971
-    /************************/
1972
-    /** LIST TABLE METHODS **/
1973
-    /************************/
1974
-    /**
1975
-     * this sets up the list table if the current view requires it.
1976
-     *
1977
-     * @return void
1978
-     * @throws EE_Error
1979
-     * @throws InvalidArgumentException
1980
-     * @throws InvalidDataTypeException
1981
-     * @throws InvalidInterfaceException
1982
-     */
1983
-    protected function _set_list_table()
1984
-    {
1985
-        // first is this a list_table view?
1986
-        if (! isset($this->_route_config['list_table'])) {
1987
-            return;
1988
-        } //not a list_table view so get out.
1989
-        // list table functions are per view specific (because some admin pages might have more than one list table!)
1990
-        $list_table_view = '_set_list_table_views_' . $this->_req_action;
1991
-        if (! method_exists($this, $list_table_view)) {
1992
-            // user error msg
1993
-            $error_msg = esc_html__(
1994
-                'An error occurred. The requested list table views could not be found.',
1995
-                'event_espresso'
1996
-            );
1997
-            // developer error msg
1998
-            $error_msg .= '||'
1999
-                          . sprintf(
2000
-                              esc_html__(
2001
-                                  'List table views for "%s" route could not be setup. Check that you have the corresponding method, "%s" set up for defining list_table_views for this route.',
2002
-                                  'event_espresso'
2003
-                              ),
2004
-                              $this->_req_action,
2005
-                              $list_table_view
2006
-                          );
2007
-            throw new EE_Error($error_msg);
2008
-        }
2009
-        $this->{$list_table_view}();
2010
-        // let's provide the ability to filter the views per PAGE AND ROUTE, per PAGE, and globally
2011
-        $this->_views = apply_filters(
2012
-            'FHEE_list_table_views_' . $this->page_slug . '_' . $this->_req_action,
2013
-            $this->_views
2014
-        );
2015
-        $this->_views = apply_filters('FHEE_list_table_views_' . $this->page_slug, $this->_views);
2016
-        $this->_views = apply_filters('FHEE_list_table_views', $this->_views);
2017
-        $this->_set_list_table_view();
2018
-        $this->_set_list_table_object();
2019
-    }
2020
-
2021
-
2022
-    /**
2023
-     * set current view for List Table
2024
-     *
2025
-     * @return void
2026
-     */
2027
-    protected function _set_list_table_view()
2028
-    {
2029
-        $this->_view = isset($this->_views['in_use']) ? 'in_use' : 'all';
2030
-        $status      = $this->request->getRequestParam('status', null, DataType::KEY);
2031
-        $this->_view = $status && array_key_exists($status, $this->_views)
2032
-            ? $status
2033
-            : $this->_view;
2034
-    }
2035
-
2036
-
2037
-    /**
2038
-     * _set_list_table_object
2039
-     * WP_List_Table objects need to be loaded fairly early so automatic stuff WP does is taken care of.
2040
-     *
2041
-     * @throws InvalidInterfaceException
2042
-     * @throws InvalidArgumentException
2043
-     * @throws InvalidDataTypeException
2044
-     * @throws EE_Error
2045
-     * @throws InvalidInterfaceException
2046
-     */
2047
-    protected function _set_list_table_object()
2048
-    {
2049
-        if (isset($this->_route_config['list_table'])) {
2050
-            if (! class_exists($this->_route_config['list_table'])) {
2051
-                throw new EE_Error(
2052
-                    sprintf(
2053
-                        esc_html__(
2054
-                            'The %s class defined for the list table does not exist.  Please check the spelling of the class ref in the $_page_config property on %s.',
2055
-                            'event_espresso'
2056
-                        ),
2057
-                        $this->_route_config['list_table'],
2058
-                        $this->class_name
2059
-                    )
2060
-                );
2061
-            }
2062
-            $this->_list_table_object = $this->loader->getShared(
2063
-                $this->_route_config['list_table'],
2064
-                [
2065
-                    $this,
2066
-                    LoaderFactory::getShared(AdminListTableFilters::class),
2067
-                ]
2068
-            );
2069
-        }
2070
-    }
2071
-
2072
-
2073
-    /**
2074
-     * get_list_table_view_RLs - get it? View RL ?? VU-RL???  URL ??
2075
-     *
2076
-     * @param array $extra_query_args                     Optional. An array of extra query args to add to the generated
2077
-     *                                                    urls.  The array should be indexed by the view it is being
2078
-     *                                                    added to.
2079
-     * @return array
2080
-     */
2081
-    public function get_list_table_view_RLs(array $extra_query_args = []): array
2082
-    {
2083
-        $extra_query_args = apply_filters(
2084
-            'FHEE__EE_Admin_Page__get_list_table_view_RLs__extra_query_args',
2085
-            $extra_query_args,
2086
-            $this
2087
-        );
2088
-        $action_nonce = "{$this->_req_action}_nonce";
2089
-        $nonce = wp_create_nonce($action_nonce);
2090
-        // cycle thru views
2091
-        foreach ($this->_views as $key => $view) {
2092
-            $query_args = [];
2093
-            if ( ! isset($this->_views[ $key ]['class'])) {
2094
-                $this->_views[ $key ]['class'] = '';
2095
-            }
2096
-            // check for current view
2097
-            $this->_views[ $key ]['class'] .= $this->_view === $view['slug'] ? ' current' : '';
2098
-            $query_args['action']          = $this->_req_action;
2099
-            $query_args[ $action_nonce ]   = $nonce;
2100
-            $query_args['status']          = $view['slug'];
2101
-            // merge any other arguments sent in.
2102
-            if (isset($extra_query_args[ $view['slug'] ])) {
2103
-                $query_args = array_merge($query_args, $extra_query_args[ $view['slug'] ]);
2104
-            }
2105
-            $this->_views[ $key ]['url'] = EE_Admin_Page::add_query_args_and_nonce($query_args, $this->_admin_base_url);
2106
-        }
2107
-        return $this->_views;
2108
-    }
2109
-
2110
-
2111
-    /**
2112
-     * generates a dropdown box for selecting the number of visible rows in an admin page list table
2113
-     *
2114
-     * @param int $max_entries total number of rows in the table
2115
-     * @return string
2116
-     * @todo   : Note: ideally this should be added to the screen options dropdown as that would be consistent with how
2117
-     *                         WP does it.
2118
-     */
2119
-    protected function _entries_per_page_dropdown(int $max_entries = 0): string
2120
-    {
2121
-        $values   = [10, 25, 50, 100];
2122
-        $per_page = $this->request->getRequestParam('per_page', 10, DataType::INT);
2123
-        if ($max_entries) {
2124
-            $values[] = $max_entries;
2125
-            sort($values);
2126
-        }
2127
-        $entries_per_page_dropdown = '
1817
+		$content .= $help_content;
1818
+		if ($display) {
1819
+			echo wp_kses($content, AllowedTags::getWithFormTags());
1820
+			return '';
1821
+		}
1822
+		return $content;
1823
+	}
1824
+
1825
+
1826
+	/**
1827
+	 * _add_global_screen_options
1828
+	 * Add any extra wp_screen_options within this method using built-in WP functions/methods for doing so.
1829
+	 * This particular method will add_screen_options on ALL EE_Admin Pages
1830
+	 *
1831
+	 * @link   http://chrismarslender.com/wp-tutorials/wordpress-screen-options-tutorial/
1832
+	 *         see also WP_Screen object documents...
1833
+	 * @link   http://codex.wordpress.org/Class_Reference/WP_Screen
1834
+	 * @abstract
1835
+	 * @return void
1836
+	 */
1837
+	private function _add_global_screen_options()
1838
+	{
1839
+	}
1840
+
1841
+
1842
+	/**
1843
+	 * _add_global_feature_pointers
1844
+	 * This method is used for implementing any "feature pointers" (using built-in WP styling js).
1845
+	 * This particular method will implement feature pointers for ALL EE_Admin pages.
1846
+	 * Note: this is just a placeholder for now.  Implementation will come down the road
1847
+	 *
1848
+	 * @see    WP_Internal_Pointers class in wp-admin/includes/template.php for example (it's a final class so can't be
1849
+	 *         extended) also see:
1850
+	 * @link   http://eamann.com/tech/wordpress-portland/
1851
+	 * @abstract
1852
+	 * @return void
1853
+	 */
1854
+	private function _add_global_feature_pointers()
1855
+	{
1856
+	}
1857
+
1858
+
1859
+	/**
1860
+	 * load_global_scripts_styles
1861
+	 * The scripts and styles enqueued in here will be loaded on every EE Admin page
1862
+	 *
1863
+	 * @return void
1864
+	 */
1865
+	public function load_global_scripts_styles()
1866
+	{
1867
+		// add debugging styles
1868
+		if (WP_DEBUG) {
1869
+			add_action('admin_head', [$this, 'add_xdebug_style']);
1870
+		}
1871
+		// taking care of metaboxes
1872
+		if (
1873
+			empty($this->_cpt_route)
1874
+			&& (isset($this->_route_config['metaboxes']) || isset($this->_route_config['has_metaboxes']))
1875
+		) {
1876
+			wp_enqueue_script('dashboard');
1877
+		}
1878
+
1879
+		wp_enqueue_script(JqueryAssetManager::JS_HANDLE_JQUERY_UI_TOUCH_PUNCH);
1880
+		wp_enqueue_script(EspressoLegacyAdminAssetManager::JS_HANDLE_EE_ADMIN);
1881
+		// LOCALIZED DATA
1882
+		// localize script for ajax lazy loading
1883
+		wp_localize_script(
1884
+			EspressoLegacyAdminAssetManager::JS_HANDLE_EE_ADMIN,
1885
+			'eeLazyLoadingContainers',
1886
+			apply_filters(
1887
+				'FHEE__EE_Admin_Page_Core__load_global_scripts_styles__loader_containers',
1888
+				['espresso_news_post_box_content']
1889
+			)
1890
+		);
1891
+		StatusChangeNotice::loadAssets();
1892
+
1893
+		add_filter(
1894
+			'admin_body_class',
1895
+			function ($classes) {
1896
+				if (strpos($classes, 'espresso-admin') === false) {
1897
+					$classes .= ' espresso-admin';
1898
+				}
1899
+				return $classes;
1900
+			}
1901
+		);
1902
+	}
1903
+
1904
+
1905
+	/**
1906
+	 *        admin_footer_scripts_eei18n_js_strings
1907
+	 *
1908
+	 * @return        void
1909
+	 */
1910
+	public function admin_footer_scripts_eei18n_js_strings()
1911
+	{
1912
+		EE_Registry::$i18n_js_strings['confirm_delete'] = wp_strip_all_tags(
1913
+			__(
1914
+				'Are you absolutely sure you want to delete this item?\nThis action will delete ALL DATA associated with this item!!!\nThis can NOT be undone!!!',
1915
+				'event_espresso'
1916
+			)
1917
+		);
1918
+		// now add months and days of the week
1919
+		EE_Registry::$i18n_js_strings['January']   = wp_strip_all_tags(__('January', 'event_espresso'));
1920
+		EE_Registry::$i18n_js_strings['February']  = wp_strip_all_tags(__('February', 'event_espresso'));
1921
+		EE_Registry::$i18n_js_strings['March']     = wp_strip_all_tags(__('March', 'event_espresso'));
1922
+		EE_Registry::$i18n_js_strings['April']     = wp_strip_all_tags(__('April', 'event_espresso'));
1923
+		EE_Registry::$i18n_js_strings['May']       = wp_strip_all_tags(__('May', 'event_espresso'));
1924
+		EE_Registry::$i18n_js_strings['June']      = wp_strip_all_tags(__('June', 'event_espresso'));
1925
+		EE_Registry::$i18n_js_strings['July']      = wp_strip_all_tags(__('July', 'event_espresso'));
1926
+		EE_Registry::$i18n_js_strings['August']    = wp_strip_all_tags(__('August', 'event_espresso'));
1927
+		EE_Registry::$i18n_js_strings['September'] = wp_strip_all_tags(__('September', 'event_espresso'));
1928
+		EE_Registry::$i18n_js_strings['October']   = wp_strip_all_tags(__('October', 'event_espresso'));
1929
+		EE_Registry::$i18n_js_strings['November']  = wp_strip_all_tags(__('November', 'event_espresso'));
1930
+		EE_Registry::$i18n_js_strings['December']  = wp_strip_all_tags(__('December', 'event_espresso'));
1931
+		EE_Registry::$i18n_js_strings['Jan']       = wp_strip_all_tags(__('Jan', 'event_espresso'));
1932
+		EE_Registry::$i18n_js_strings['Feb']       = wp_strip_all_tags(__('Feb', 'event_espresso'));
1933
+		EE_Registry::$i18n_js_strings['Mar']       = wp_strip_all_tags(__('Mar', 'event_espresso'));
1934
+		EE_Registry::$i18n_js_strings['Apr']       = wp_strip_all_tags(__('Apr', 'event_espresso'));
1935
+		EE_Registry::$i18n_js_strings['May']       = wp_strip_all_tags(__('May', 'event_espresso'));
1936
+		EE_Registry::$i18n_js_strings['Jun']       = wp_strip_all_tags(__('Jun', 'event_espresso'));
1937
+		EE_Registry::$i18n_js_strings['Jul']       = wp_strip_all_tags(__('Jul', 'event_espresso'));
1938
+		EE_Registry::$i18n_js_strings['Aug']       = wp_strip_all_tags(__('Aug', 'event_espresso'));
1939
+		EE_Registry::$i18n_js_strings['Sep']       = wp_strip_all_tags(__('Sep', 'event_espresso'));
1940
+		EE_Registry::$i18n_js_strings['Oct']       = wp_strip_all_tags(__('Oct', 'event_espresso'));
1941
+		EE_Registry::$i18n_js_strings['Nov']       = wp_strip_all_tags(__('Nov', 'event_espresso'));
1942
+		EE_Registry::$i18n_js_strings['Dec']       = wp_strip_all_tags(__('Dec', 'event_espresso'));
1943
+		EE_Registry::$i18n_js_strings['Sunday']    = wp_strip_all_tags(__('Sunday', 'event_espresso'));
1944
+		EE_Registry::$i18n_js_strings['Monday']    = wp_strip_all_tags(__('Monday', 'event_espresso'));
1945
+		EE_Registry::$i18n_js_strings['Tuesday']   = wp_strip_all_tags(__('Tuesday', 'event_espresso'));
1946
+		EE_Registry::$i18n_js_strings['Wednesday'] = wp_strip_all_tags(__('Wednesday', 'event_espresso'));
1947
+		EE_Registry::$i18n_js_strings['Thursday']  = wp_strip_all_tags(__('Thursday', 'event_espresso'));
1948
+		EE_Registry::$i18n_js_strings['Friday']    = wp_strip_all_tags(__('Friday', 'event_espresso'));
1949
+		EE_Registry::$i18n_js_strings['Saturday']  = wp_strip_all_tags(__('Saturday', 'event_espresso'));
1950
+		EE_Registry::$i18n_js_strings['Sun']       = wp_strip_all_tags(__('Sun', 'event_espresso'));
1951
+		EE_Registry::$i18n_js_strings['Mon']       = wp_strip_all_tags(__('Mon', 'event_espresso'));
1952
+		EE_Registry::$i18n_js_strings['Tue']       = wp_strip_all_tags(__('Tue', 'event_espresso'));
1953
+		EE_Registry::$i18n_js_strings['Wed']       = wp_strip_all_tags(__('Wed', 'event_espresso'));
1954
+		EE_Registry::$i18n_js_strings['Thu']       = wp_strip_all_tags(__('Thu', 'event_espresso'));
1955
+		EE_Registry::$i18n_js_strings['Fri']       = wp_strip_all_tags(__('Fri', 'event_espresso'));
1956
+		EE_Registry::$i18n_js_strings['Sat']       = wp_strip_all_tags(__('Sat', 'event_espresso'));
1957
+	}
1958
+
1959
+
1960
+	/**
1961
+	 *        load enhanced xdebug styles for ppl with failing eyesight
1962
+	 *
1963
+	 * @return        void
1964
+	 */
1965
+	public function add_xdebug_style()
1966
+	{
1967
+		echo '<style>.xdebug-error { font-size:1.5em; }</style>';
1968
+	}
1969
+
1970
+
1971
+	/************************/
1972
+	/** LIST TABLE METHODS **/
1973
+	/************************/
1974
+	/**
1975
+	 * this sets up the list table if the current view requires it.
1976
+	 *
1977
+	 * @return void
1978
+	 * @throws EE_Error
1979
+	 * @throws InvalidArgumentException
1980
+	 * @throws InvalidDataTypeException
1981
+	 * @throws InvalidInterfaceException
1982
+	 */
1983
+	protected function _set_list_table()
1984
+	{
1985
+		// first is this a list_table view?
1986
+		if (! isset($this->_route_config['list_table'])) {
1987
+			return;
1988
+		} //not a list_table view so get out.
1989
+		// list table functions are per view specific (because some admin pages might have more than one list table!)
1990
+		$list_table_view = '_set_list_table_views_' . $this->_req_action;
1991
+		if (! method_exists($this, $list_table_view)) {
1992
+			// user error msg
1993
+			$error_msg = esc_html__(
1994
+				'An error occurred. The requested list table views could not be found.',
1995
+				'event_espresso'
1996
+			);
1997
+			// developer error msg
1998
+			$error_msg .= '||'
1999
+						  . sprintf(
2000
+							  esc_html__(
2001
+								  'List table views for "%s" route could not be setup. Check that you have the corresponding method, "%s" set up for defining list_table_views for this route.',
2002
+								  'event_espresso'
2003
+							  ),
2004
+							  $this->_req_action,
2005
+							  $list_table_view
2006
+						  );
2007
+			throw new EE_Error($error_msg);
2008
+		}
2009
+		$this->{$list_table_view}();
2010
+		// let's provide the ability to filter the views per PAGE AND ROUTE, per PAGE, and globally
2011
+		$this->_views = apply_filters(
2012
+			'FHEE_list_table_views_' . $this->page_slug . '_' . $this->_req_action,
2013
+			$this->_views
2014
+		);
2015
+		$this->_views = apply_filters('FHEE_list_table_views_' . $this->page_slug, $this->_views);
2016
+		$this->_views = apply_filters('FHEE_list_table_views', $this->_views);
2017
+		$this->_set_list_table_view();
2018
+		$this->_set_list_table_object();
2019
+	}
2020
+
2021
+
2022
+	/**
2023
+	 * set current view for List Table
2024
+	 *
2025
+	 * @return void
2026
+	 */
2027
+	protected function _set_list_table_view()
2028
+	{
2029
+		$this->_view = isset($this->_views['in_use']) ? 'in_use' : 'all';
2030
+		$status      = $this->request->getRequestParam('status', null, DataType::KEY);
2031
+		$this->_view = $status && array_key_exists($status, $this->_views)
2032
+			? $status
2033
+			: $this->_view;
2034
+	}
2035
+
2036
+
2037
+	/**
2038
+	 * _set_list_table_object
2039
+	 * WP_List_Table objects need to be loaded fairly early so automatic stuff WP does is taken care of.
2040
+	 *
2041
+	 * @throws InvalidInterfaceException
2042
+	 * @throws InvalidArgumentException
2043
+	 * @throws InvalidDataTypeException
2044
+	 * @throws EE_Error
2045
+	 * @throws InvalidInterfaceException
2046
+	 */
2047
+	protected function _set_list_table_object()
2048
+	{
2049
+		if (isset($this->_route_config['list_table'])) {
2050
+			if (! class_exists($this->_route_config['list_table'])) {
2051
+				throw new EE_Error(
2052
+					sprintf(
2053
+						esc_html__(
2054
+							'The %s class defined for the list table does not exist.  Please check the spelling of the class ref in the $_page_config property on %s.',
2055
+							'event_espresso'
2056
+						),
2057
+						$this->_route_config['list_table'],
2058
+						$this->class_name
2059
+					)
2060
+				);
2061
+			}
2062
+			$this->_list_table_object = $this->loader->getShared(
2063
+				$this->_route_config['list_table'],
2064
+				[
2065
+					$this,
2066
+					LoaderFactory::getShared(AdminListTableFilters::class),
2067
+				]
2068
+			);
2069
+		}
2070
+	}
2071
+
2072
+
2073
+	/**
2074
+	 * get_list_table_view_RLs - get it? View RL ?? VU-RL???  URL ??
2075
+	 *
2076
+	 * @param array $extra_query_args                     Optional. An array of extra query args to add to the generated
2077
+	 *                                                    urls.  The array should be indexed by the view it is being
2078
+	 *                                                    added to.
2079
+	 * @return array
2080
+	 */
2081
+	public function get_list_table_view_RLs(array $extra_query_args = []): array
2082
+	{
2083
+		$extra_query_args = apply_filters(
2084
+			'FHEE__EE_Admin_Page__get_list_table_view_RLs__extra_query_args',
2085
+			$extra_query_args,
2086
+			$this
2087
+		);
2088
+		$action_nonce = "{$this->_req_action}_nonce";
2089
+		$nonce = wp_create_nonce($action_nonce);
2090
+		// cycle thru views
2091
+		foreach ($this->_views as $key => $view) {
2092
+			$query_args = [];
2093
+			if ( ! isset($this->_views[ $key ]['class'])) {
2094
+				$this->_views[ $key ]['class'] = '';
2095
+			}
2096
+			// check for current view
2097
+			$this->_views[ $key ]['class'] .= $this->_view === $view['slug'] ? ' current' : '';
2098
+			$query_args['action']          = $this->_req_action;
2099
+			$query_args[ $action_nonce ]   = $nonce;
2100
+			$query_args['status']          = $view['slug'];
2101
+			// merge any other arguments sent in.
2102
+			if (isset($extra_query_args[ $view['slug'] ])) {
2103
+				$query_args = array_merge($query_args, $extra_query_args[ $view['slug'] ]);
2104
+			}
2105
+			$this->_views[ $key ]['url'] = EE_Admin_Page::add_query_args_and_nonce($query_args, $this->_admin_base_url);
2106
+		}
2107
+		return $this->_views;
2108
+	}
2109
+
2110
+
2111
+	/**
2112
+	 * generates a dropdown box for selecting the number of visible rows in an admin page list table
2113
+	 *
2114
+	 * @param int $max_entries total number of rows in the table
2115
+	 * @return string
2116
+	 * @todo   : Note: ideally this should be added to the screen options dropdown as that would be consistent with how
2117
+	 *                         WP does it.
2118
+	 */
2119
+	protected function _entries_per_page_dropdown(int $max_entries = 0): string
2120
+	{
2121
+		$values   = [10, 25, 50, 100];
2122
+		$per_page = $this->request->getRequestParam('per_page', 10, DataType::INT);
2123
+		if ($max_entries) {
2124
+			$values[] = $max_entries;
2125
+			sort($values);
2126
+		}
2127
+		$entries_per_page_dropdown = '
2128 2128
 			<div id="entries-per-page-dv" class="alignleft actions">
2129 2129
 				<label class="hide-if-no-js">
2130 2130
 					Show
2131 2131
 					<select id="entries-per-page-slct" name="entries-per-page-slct">';
2132
-        foreach ($values as $value) {
2133
-            if ($value < $max_entries) {
2134
-                $selected                  = $value === $per_page ? ' selected="' . $per_page . '"' : '';
2135
-                $entries_per_page_dropdown .= '
2132
+		foreach ($values as $value) {
2133
+			if ($value < $max_entries) {
2134
+				$selected                  = $value === $per_page ? ' selected="' . $per_page . '"' : '';
2135
+				$entries_per_page_dropdown .= '
2136 2136
 						<option value="' . $value . '"' . $selected . '>' . $value . '&nbsp;&nbsp;</option>';
2137
-            }
2138
-        }
2139
-        $selected                  = $max_entries === $per_page ? ' selected="' . $per_page . '"' : '';
2140
-        $entries_per_page_dropdown .= '
2137
+			}
2138
+		}
2139
+		$selected                  = $max_entries === $per_page ? ' selected="' . $per_page . '"' : '';
2140
+		$entries_per_page_dropdown .= '
2141 2141
 						<option value="' . $max_entries . '"' . $selected . '>All&nbsp;&nbsp;</option>';
2142
-        $entries_per_page_dropdown .= '
2142
+		$entries_per_page_dropdown .= '
2143 2143
 					</select>
2144 2144
 					entries
2145 2145
 				</label>
2146 2146
 				<input id="entries-per-page-btn" class="button button--secondary" type="submit" value="Go" >
2147 2147
 			</div>
2148 2148
 		';
2149
-        return $entries_per_page_dropdown;
2150
-    }
2151
-
2152
-
2153
-    /**
2154
-     *        _set_search_attributes
2155
-     *
2156
-     * @return        void
2157
-     */
2158
-    public function _set_search_attributes()
2159
-    {
2160
-        $this->_template_args['search']['btn_label'] = sprintf(
2161
-            esc_html__('Search %s', 'event_espresso'),
2162
-            empty($this->_search_btn_label) ? $this->page_label
2163
-                : $this->_search_btn_label
2164
-        );
2165
-        $this->_template_args['search']['callback']  = 'search_' . $this->page_slug;
2166
-    }
2167
-
2168
-
2169
-
2170
-    /*** END LIST TABLE METHODS **/
2171
-
2172
-    /**
2173
-     * @return void
2174
-     * @throws EE_Error
2175
-     */
2176
-    public function addRegisteredMetaBoxes()
2177
-    {
2178
-        remove_action('add_meta_boxes', [$this, 'addRegisteredMetaBoxes'], 99);
2179
-        $this->_add_registered_meta_boxes();
2180
-    }
2181
-
2182
-
2183
-    /**
2184
-     * _add_registered_metaboxes
2185
-     *  this loads any registered metaboxes via the 'metaboxes' index in the _page_config property array.
2186
-     *
2187
-     * @link   http://codex.wordpress.org/Function_Reference/add_meta_box
2188
-     * @return void
2189
-     * @throws EE_Error
2190
-     */
2191
-    private function _add_registered_meta_boxes()
2192
-    {
2193
-        // we only add meta boxes if the page_route calls for it
2194
-        if (isset($this->_route_config['metaboxes']) && is_array($this->_route_config['metaboxes'])) {
2195
-            // this simply loops through the callbacks provided
2196
-            // and checks if there is a corresponding callback registered by the child
2197
-            // if there is then we go ahead and process the metabox loader.
2198
-            foreach ($this->_route_config['metaboxes'] as $key => $metabox_callback) {
2199
-                // first check for Closures
2200
-                if ($metabox_callback instanceof Closure) {
2201
-                    $result = $metabox_callback();
2202
-                } elseif (is_callable($metabox_callback)) {
2203
-                    $result = call_user_func($metabox_callback);
2204
-                } elseif (method_exists($this, $metabox_callback)) {
2205
-                    $result = $this->{$metabox_callback}();
2206
-                } else {
2207
-                    $result = false;
2208
-                }
2209
-                if ($result === false) {
2210
-                    // user error msg
2211
-                    $error_msg = esc_html__(
2212
-                        'An error occurred. The  requested metabox could not be found.',
2213
-                        'event_espresso'
2214
-                    );
2215
-                    // developer error msg
2216
-                    $error_msg .= '||'
2217
-                                  . sprintf(
2218
-                                      esc_html__(
2219
-                                          'The metabox with the string "%s" could not be called. Check that the spelling for method names and actions in the "_page_config[\'metaboxes\']" array are all correct.',
2220
-                                          'event_espresso'
2221
-                                      ),
2222
-                                      $metabox_callback
2223
-                                  );
2224
-                    throw new EE_Error($error_msg);
2225
-                }
2226
-                unset($this->_route_config['metaboxes'][ $key ]);
2227
-            }
2228
-        }
2229
-    }
2230
-
2231
-
2232
-    /**
2233
-     * _add_screen_columns
2234
-     * This will check the _page_config array and if there is "columns" key index indicated, we'll set the template as
2235
-     * the dynamic column template and we'll set up the column options for the page.
2236
-     *
2237
-     * @return void
2238
-     */
2239
-    private function _add_screen_columns()
2240
-    {
2241
-        if (
2242
-            isset($this->_route_config['columns'])
2243
-            && is_array($this->_route_config['columns'])
2244
-            && count($this->_route_config['columns']) === 2
2245
-        ) {
2246
-            add_screen_option(
2247
-                'layout_columns',
2248
-                [
2249
-                    'max'     => (int) $this->_route_config['columns'][0],
2250
-                    'default' => (int) $this->_route_config['columns'][1],
2251
-                ]
2252
-            );
2253
-            $this->_template_args['num_columns']                 = $this->_route_config['columns'][0];
2254
-            $screen_id                                           = $this->_current_screen->id;
2255
-            $screen_columns                                      = (int) get_user_option("screen_layout_$screen_id");
2256
-            $total_columns                                       = ! empty($screen_columns)
2257
-                ? $screen_columns
2258
-                : $this->_route_config['columns'][1];
2259
-            $this->_template_args['current_screen_widget_class'] = 'columns-' . $total_columns;
2260
-            $this->_template_args['current_page']                = $this->_wp_page_slug;
2261
-            $this->_template_args['screen']                      = $this->_current_screen;
2262
-            $this->_column_template_path                         = EE_ADMIN_TEMPLATE
2263
-                                                                   . 'admin_details_metabox_column_wrapper.template.php';
2264
-            // finally if we don't have has_metaboxes set in the route config
2265
-            // let's make sure it IS set otherwise the necessary hidden fields for this won't be loaded.
2266
-            $this->_route_config['has_metaboxes'] = true;
2267
-        }
2268
-    }
2269
-
2270
-
2271
-
2272
-    /** GLOBALLY AVAILABLE METABOXES **/
2273
-
2274
-
2275
-    /**
2276
-     * In this section we put any globally available EE metaboxes for all EE Admin pages.  They are called by simply
2277
-     * referencing the callback in the _page_config array property.  This way you can be very specific about what pages
2278
-     * these get loaded on.
2279
-     */
2280
-    private function _espresso_news_post_box()
2281
-    {
2282
-        $news_box_title = apply_filters(
2283
-            'FHEE__EE_Admin_Page___espresso_news_post_box__news_box_title',
2284
-            esc_html__('New @ Event Espresso', 'event_espresso')
2285
-        );
2286
-        $this->addMetaBox(
2287
-            'espresso_news_post_box',
2288
-            $news_box_title,
2289
-            [
2290
-                $this,
2291
-                'espresso_news_post_box',
2292
-            ],
2293
-            $this->_wp_page_slug,
2294
-            'side',
2295
-            'low'
2296
-        );
2297
-    }
2298
-
2299
-
2300
-    /**
2301
-     * Code for setting up espresso ratings request metabox.
2302
-     */
2303
-    protected function _espresso_ratings_request()
2304
-    {
2305
-        if (! apply_filters('FHEE_show_ratings_request_meta_box', true)) {
2306
-            return;
2307
-        }
2308
-        $ratings_box_title = apply_filters(
2309
-            'FHEE__EE_Admin_Page___espresso_news_post_box__news_box_title',
2310
-            esc_html__('Keep Event Espresso Decaf Free', 'event_espresso')
2311
-        );
2312
-        $this->addMetaBox(
2313
-            'espresso_ratings_request',
2314
-            $ratings_box_title,
2315
-            [
2316
-                $this,
2317
-                'espresso_ratings_request',
2318
-            ],
2319
-            $this->_wp_page_slug,
2320
-            'side'
2321
-        );
2322
-    }
2323
-
2324
-
2325
-    /**
2326
-     * Code for setting up espresso ratings request metabox content.
2327
-     *
2328
-     * @throws DomainException
2329
-     */
2330
-    public function espresso_ratings_request()
2331
-    {
2332
-        EEH_Template::display_template(EE_ADMIN_TEMPLATE . 'espresso_ratings_request_content.template.php');
2333
-    }
2334
-
2335
-
2336
-    public static function cached_rss_display(string $rss_id, string $url): bool
2337
-    {
2338
-        $loading   = '<p class="widget-loading hide-if-no-js">'
2339
-                     . esc_html__('Loading&#8230;', 'event_espresso')
2340
-                     . '</p><p class="hide-if-js">'
2341
-                     . esc_html__('This widget requires JavaScript.', 'event_espresso')
2342
-                     . '</p>';
2343
-        $pre       = '<div class="espresso-rss-display">' . "\n\t";
2344
-        $pre       .= '<span id="' . esc_attr($rss_id) . '_url" class="hidden">' . esc_url_raw($url) . '</span>';
2345
-        $post      = '</div>' . "\n";
2346
-        $cache_key = 'ee_rss_' . md5($rss_id);
2347
-        $output    = get_transient($cache_key);
2348
-        if ($output !== false) {
2349
-            echo wp_kses($pre . $output . $post, AllowedTags::getWithFormTags());
2350
-            return true;
2351
-        }
2352
-        if (! (defined('DOING_AJAX') && DOING_AJAX)) {
2353
-            echo wp_kses($pre . $loading . $post, AllowedTags::getWithFormTags());
2354
-            return false;
2355
-        }
2356
-        ob_start();
2357
-        wp_widget_rss_output($url, ['show_date' => 0, 'items' => 5]);
2358
-        set_transient($cache_key, ob_get_flush(), 12 * HOUR_IN_SECONDS);
2359
-        return true;
2360
-    }
2361
-
2362
-
2363
-    public function espresso_news_post_box()
2364
-    {
2365
-        ?>
2149
+		return $entries_per_page_dropdown;
2150
+	}
2151
+
2152
+
2153
+	/**
2154
+	 *        _set_search_attributes
2155
+	 *
2156
+	 * @return        void
2157
+	 */
2158
+	public function _set_search_attributes()
2159
+	{
2160
+		$this->_template_args['search']['btn_label'] = sprintf(
2161
+			esc_html__('Search %s', 'event_espresso'),
2162
+			empty($this->_search_btn_label) ? $this->page_label
2163
+				: $this->_search_btn_label
2164
+		);
2165
+		$this->_template_args['search']['callback']  = 'search_' . $this->page_slug;
2166
+	}
2167
+
2168
+
2169
+
2170
+	/*** END LIST TABLE METHODS **/
2171
+
2172
+	/**
2173
+	 * @return void
2174
+	 * @throws EE_Error
2175
+	 */
2176
+	public function addRegisteredMetaBoxes()
2177
+	{
2178
+		remove_action('add_meta_boxes', [$this, 'addRegisteredMetaBoxes'], 99);
2179
+		$this->_add_registered_meta_boxes();
2180
+	}
2181
+
2182
+
2183
+	/**
2184
+	 * _add_registered_metaboxes
2185
+	 *  this loads any registered metaboxes via the 'metaboxes' index in the _page_config property array.
2186
+	 *
2187
+	 * @link   http://codex.wordpress.org/Function_Reference/add_meta_box
2188
+	 * @return void
2189
+	 * @throws EE_Error
2190
+	 */
2191
+	private function _add_registered_meta_boxes()
2192
+	{
2193
+		// we only add meta boxes if the page_route calls for it
2194
+		if (isset($this->_route_config['metaboxes']) && is_array($this->_route_config['metaboxes'])) {
2195
+			// this simply loops through the callbacks provided
2196
+			// and checks if there is a corresponding callback registered by the child
2197
+			// if there is then we go ahead and process the metabox loader.
2198
+			foreach ($this->_route_config['metaboxes'] as $key => $metabox_callback) {
2199
+				// first check for Closures
2200
+				if ($metabox_callback instanceof Closure) {
2201
+					$result = $metabox_callback();
2202
+				} elseif (is_callable($metabox_callback)) {
2203
+					$result = call_user_func($metabox_callback);
2204
+				} elseif (method_exists($this, $metabox_callback)) {
2205
+					$result = $this->{$metabox_callback}();
2206
+				} else {
2207
+					$result = false;
2208
+				}
2209
+				if ($result === false) {
2210
+					// user error msg
2211
+					$error_msg = esc_html__(
2212
+						'An error occurred. The  requested metabox could not be found.',
2213
+						'event_espresso'
2214
+					);
2215
+					// developer error msg
2216
+					$error_msg .= '||'
2217
+								  . sprintf(
2218
+									  esc_html__(
2219
+										  'The metabox with the string "%s" could not be called. Check that the spelling for method names and actions in the "_page_config[\'metaboxes\']" array are all correct.',
2220
+										  'event_espresso'
2221
+									  ),
2222
+									  $metabox_callback
2223
+								  );
2224
+					throw new EE_Error($error_msg);
2225
+				}
2226
+				unset($this->_route_config['metaboxes'][ $key ]);
2227
+			}
2228
+		}
2229
+	}
2230
+
2231
+
2232
+	/**
2233
+	 * _add_screen_columns
2234
+	 * This will check the _page_config array and if there is "columns" key index indicated, we'll set the template as
2235
+	 * the dynamic column template and we'll set up the column options for the page.
2236
+	 *
2237
+	 * @return void
2238
+	 */
2239
+	private function _add_screen_columns()
2240
+	{
2241
+		if (
2242
+			isset($this->_route_config['columns'])
2243
+			&& is_array($this->_route_config['columns'])
2244
+			&& count($this->_route_config['columns']) === 2
2245
+		) {
2246
+			add_screen_option(
2247
+				'layout_columns',
2248
+				[
2249
+					'max'     => (int) $this->_route_config['columns'][0],
2250
+					'default' => (int) $this->_route_config['columns'][1],
2251
+				]
2252
+			);
2253
+			$this->_template_args['num_columns']                 = $this->_route_config['columns'][0];
2254
+			$screen_id                                           = $this->_current_screen->id;
2255
+			$screen_columns                                      = (int) get_user_option("screen_layout_$screen_id");
2256
+			$total_columns                                       = ! empty($screen_columns)
2257
+				? $screen_columns
2258
+				: $this->_route_config['columns'][1];
2259
+			$this->_template_args['current_screen_widget_class'] = 'columns-' . $total_columns;
2260
+			$this->_template_args['current_page']                = $this->_wp_page_slug;
2261
+			$this->_template_args['screen']                      = $this->_current_screen;
2262
+			$this->_column_template_path                         = EE_ADMIN_TEMPLATE
2263
+																   . 'admin_details_metabox_column_wrapper.template.php';
2264
+			// finally if we don't have has_metaboxes set in the route config
2265
+			// let's make sure it IS set otherwise the necessary hidden fields for this won't be loaded.
2266
+			$this->_route_config['has_metaboxes'] = true;
2267
+		}
2268
+	}
2269
+
2270
+
2271
+
2272
+	/** GLOBALLY AVAILABLE METABOXES **/
2273
+
2274
+
2275
+	/**
2276
+	 * In this section we put any globally available EE metaboxes for all EE Admin pages.  They are called by simply
2277
+	 * referencing the callback in the _page_config array property.  This way you can be very specific about what pages
2278
+	 * these get loaded on.
2279
+	 */
2280
+	private function _espresso_news_post_box()
2281
+	{
2282
+		$news_box_title = apply_filters(
2283
+			'FHEE__EE_Admin_Page___espresso_news_post_box__news_box_title',
2284
+			esc_html__('New @ Event Espresso', 'event_espresso')
2285
+		);
2286
+		$this->addMetaBox(
2287
+			'espresso_news_post_box',
2288
+			$news_box_title,
2289
+			[
2290
+				$this,
2291
+				'espresso_news_post_box',
2292
+			],
2293
+			$this->_wp_page_slug,
2294
+			'side',
2295
+			'low'
2296
+		);
2297
+	}
2298
+
2299
+
2300
+	/**
2301
+	 * Code for setting up espresso ratings request metabox.
2302
+	 */
2303
+	protected function _espresso_ratings_request()
2304
+	{
2305
+		if (! apply_filters('FHEE_show_ratings_request_meta_box', true)) {
2306
+			return;
2307
+		}
2308
+		$ratings_box_title = apply_filters(
2309
+			'FHEE__EE_Admin_Page___espresso_news_post_box__news_box_title',
2310
+			esc_html__('Keep Event Espresso Decaf Free', 'event_espresso')
2311
+		);
2312
+		$this->addMetaBox(
2313
+			'espresso_ratings_request',
2314
+			$ratings_box_title,
2315
+			[
2316
+				$this,
2317
+				'espresso_ratings_request',
2318
+			],
2319
+			$this->_wp_page_slug,
2320
+			'side'
2321
+		);
2322
+	}
2323
+
2324
+
2325
+	/**
2326
+	 * Code for setting up espresso ratings request metabox content.
2327
+	 *
2328
+	 * @throws DomainException
2329
+	 */
2330
+	public function espresso_ratings_request()
2331
+	{
2332
+		EEH_Template::display_template(EE_ADMIN_TEMPLATE . 'espresso_ratings_request_content.template.php');
2333
+	}
2334
+
2335
+
2336
+	public static function cached_rss_display(string $rss_id, string $url): bool
2337
+	{
2338
+		$loading   = '<p class="widget-loading hide-if-no-js">'
2339
+					 . esc_html__('Loading&#8230;', 'event_espresso')
2340
+					 . '</p><p class="hide-if-js">'
2341
+					 . esc_html__('This widget requires JavaScript.', 'event_espresso')
2342
+					 . '</p>';
2343
+		$pre       = '<div class="espresso-rss-display">' . "\n\t";
2344
+		$pre       .= '<span id="' . esc_attr($rss_id) . '_url" class="hidden">' . esc_url_raw($url) . '</span>';
2345
+		$post      = '</div>' . "\n";
2346
+		$cache_key = 'ee_rss_' . md5($rss_id);
2347
+		$output    = get_transient($cache_key);
2348
+		if ($output !== false) {
2349
+			echo wp_kses($pre . $output . $post, AllowedTags::getWithFormTags());
2350
+			return true;
2351
+		}
2352
+		if (! (defined('DOING_AJAX') && DOING_AJAX)) {
2353
+			echo wp_kses($pre . $loading . $post, AllowedTags::getWithFormTags());
2354
+			return false;
2355
+		}
2356
+		ob_start();
2357
+		wp_widget_rss_output($url, ['show_date' => 0, 'items' => 5]);
2358
+		set_transient($cache_key, ob_get_flush(), 12 * HOUR_IN_SECONDS);
2359
+		return true;
2360
+	}
2361
+
2362
+
2363
+	public function espresso_news_post_box()
2364
+	{
2365
+		?>
2366 2366
 <div class="padding">
2367 2367
     <div id="espresso_news_post_box_content" class="infolinks">
2368 2368
         <?php
2369
-                // Get RSS Feed(s)
2370
-                EE_Admin_Page::cached_rss_display(
2371
-                    'espresso_news_post_box_content',
2372
-                    esc_url_raw(
2373
-                        apply_filters(
2374
-                            'FHEE__EE_Admin_Page__espresso_news_post_box__feed_url',
2375
-                            'https://eventespresso.com/feed/'
2376
-                        )
2377
-                    )
2378
-                );
2379
-        ?>
2369
+				// Get RSS Feed(s)
2370
+				EE_Admin_Page::cached_rss_display(
2371
+					'espresso_news_post_box_content',
2372
+					esc_url_raw(
2373
+						apply_filters(
2374
+							'FHEE__EE_Admin_Page__espresso_news_post_box__feed_url',
2375
+							'https://eventespresso.com/feed/'
2376
+						)
2377
+					)
2378
+				);
2379
+		?>
2380 2380
     </div>
2381 2381
     <?php do_action('AHEE__EE_Admin_Page__espresso_news_post_box__after_content'); ?>
2382 2382
 </div>
2383 2383
 <?php
2384
-    }
2385
-
2386
-
2387
-    private function _espresso_links_post_box()
2388
-    {
2389
-        // Hiding until we actually have content to put in here...
2390
-        // $this->addMetaBox('espresso_links_post_box', esc_html__('Helpful Plugin Links', 'event_espresso'), array( $this, 'espresso_links_post_box'), $this->_wp_page_slug, 'side');
2391
-    }
2392
-
2393
-
2394
-    public function espresso_links_post_box()
2395
-    {
2396
-        // Hiding until we actually have content to put in here...
2397
-        // EEH_Template::display_template(
2398
-        //     EE_ADMIN_TEMPLATE . 'admin_general_metabox_contents_espresso_links.template.php'
2399
-        // );
2400
-    }
2401
-
2402
-
2403
-    protected function _espresso_sponsors_post_box()
2404
-    {
2405
-        if (apply_filters('FHEE_show_sponsors_meta_box', true)) {
2406
-            $this->addMetaBox(
2407
-                'espresso_sponsors_post_box',
2408
-                esc_html__('Event Espresso Highlights', 'event_espresso'),
2409
-                [$this, 'espresso_sponsors_post_box'],
2410
-                $this->_wp_page_slug,
2411
-                'side'
2412
-            );
2413
-        }
2414
-    }
2415
-
2416
-
2417
-    public function espresso_sponsors_post_box()
2418
-    {
2419
-        EEH_Template::display_template(
2420
-            EE_ADMIN_TEMPLATE . 'admin_general_metabox_contents_espresso_sponsors.template.php'
2421
-        );
2422
-    }
2423
-
2424
-
2425
-    /**
2426
-     * if there is [ 'label' => [ 'publishbox' => 'some title' ]]
2427
-     * present in the _page_config array, then we'll use that for the metabox label.
2428
-     * Otherwise we'll just use publish
2429
-     * (publishbox itself could be an array of labels indexed by routes)
2430
-     *
2431
-     * @return string
2432
-     * @since   5.0.0.p
2433
-     */
2434
-    protected function getPublishBoxTitle(): string
2435
-    {
2436
-        $publish_box_title = esc_html__('Publish', 'event_espresso');
2437
-        if (! empty($this->_labels['publishbox'])) {
2438
-            if (is_array($this->_labels['publishbox'])) {
2439
-                $publish_box_title = $this->_labels['publishbox'][ $this->_req_action ] ?? $publish_box_title;
2440
-            } else {
2441
-                $publish_box_title = $this->_labels['publishbox'];
2442
-            }
2443
-        }
2444
-        return apply_filters(
2445
-            'FHEE__EE_Admin_Page___publish_post_box__box_label',
2446
-            $publish_box_title,
2447
-            $this->_req_action,
2448
-            $this
2449
-        );
2450
-    }
2451
-
2452
-
2453
-    /**
2454
-     * @throws EE_Error
2455
-     */
2456
-    private function _publish_post_box()
2457
-    {
2458
-        $title = $this->getPublishBoxTitle();
2459
-        if (empty($this->_template_args['save_buttons'])) {
2460
-            $this->_set_publish_post_box_vars(sanitize_key($title), "espresso_{$this->page_slug}_editor_overview");
2461
-        } else {
2462
-            $this->addPublishPostMetaBoxHiddenFields(
2463
-                sanitize_key($title),
2464
-                ['type' => 'hidden', 'value' => "espresso_{$this->page_slug}_editor_overview"]
2465
-            );
2466
-        }
2467
-        $this->addMetaBox(
2468
-            "espresso_{$this->page_slug}_editor_overview",
2469
-            $title,
2470
-            [$this, 'editor_overview'],
2471
-            $this->_current_screen->id,
2472
-            'side',
2473
-            'high'
2474
-        );
2475
-    }
2476
-
2477
-
2478
-    public function editor_overview()
2479
-    {
2480
-        /**
2481
-         * @var string $publish_box_extra_content
2482
-         * @var string $publish_hidden_fields
2483
-         * @var string $publish_delete_link
2484
-         * @var string $save_buttons
2485
-         */
2486
-        // if we have extra content set let's add it in if not make sure its empty
2487
-        $this->_template_args['publish_box_extra_content'] = $this->_template_args['publish_box_extra_content'] ?? '';
2488
-        echo EEH_Template::display_template(
2489
-            EE_ADMIN_TEMPLATE . 'admin_details_publish_metabox.template.php',
2490
-            $this->_template_args,
2491
-            true
2492
-        );
2493
-    }
2494
-
2495
-
2496
-    /** end of globally available metaboxes section **/
2497
-
2498
-
2499
-    /**
2500
-     * Sets the _template_args arguments used by the _publish_post_box shortcut
2501
-     * Note: currently there is no validation for this.  However, if you want the delete button, the
2502
-     * save, and save and close buttons to work properly, then you will want to include a
2503
-     * values for the name and id arguments.
2504
-     *
2505
-     * @param string|null $name                     key used for the action ID (i.e. event_id)
2506
-     * @param int|string  $id                       id attached to the item published
2507
-     * @param string|null $delete                   page route callback for the delete action
2508
-     * @param string|null $save_close_redirect_URL  custom URL to redirect to after Save & Close has been completed
2509
-     * @param bool        $both_btns                whether to display BOTH the "Save & Close" and "Save" buttons
2510
-     *                                              or just the "Save" button
2511
-     * @throws EE_Error
2512
-     * @throws InvalidArgumentException
2513
-     * @throws InvalidDataTypeException
2514
-     * @throws InvalidInterfaceException
2515
-     * @todo  Add in validation for name/id arguments.
2516
-     */
2517
-    protected function _set_publish_post_box_vars(
2518
-        ?string $name = '',
2519
-        $id = 0,
2520
-        ?string $delete = '',
2521
-        ?string $save_close_redirect_URL = '',
2522
-        bool $both_btns = true
2523
-    ) {
2524
-        // if Save & Close, use a custom redirect URL or default to the main page?
2525
-        $save_close_redirect_URL = ! empty($save_close_redirect_URL)
2526
-            ? $save_close_redirect_URL
2527
-            : $this->_admin_base_url;
2528
-        // create the Save & Close and Save buttons
2529
-        $this->_set_save_buttons($both_btns, [], [], $save_close_redirect_URL);
2530
-        // if we have extra content set let's add it in if not make sure its empty
2531
-        $this->_template_args['publish_box_extra_content'] = $this->_template_args['publish_box_extra_content'] ?? '';
2532
-        if ($delete && ! empty($id) && empty($this->_template_args['publish_delete_link'])) {
2533
-            // make sure we have a default if just true is sent.
2534
-            $delete                                      = ! empty($delete) ? $delete : 'delete';
2535
-            $this->_template_args['publish_delete_link'] = $this->get_action_link_or_button(
2536
-                $delete,
2537
-                $delete,
2538
-                [$name => $id],
2539
-                'submitdelete deletion button button--outline button--caution'
2540
-            );
2541
-        }
2542
-        if (! isset($this->_template_args['publish_delete_link'])) {
2543
-            $this->_template_args['publish_delete_link'] = '';
2544
-        }
2545
-        if (! empty($name) && ! empty($id)) {
2546
-            $this->addPublishPostMetaBoxHiddenFields($name, ['type' => 'hidden', 'value' => $id]);
2547
-        }
2548
-        $hidden_fields = $this->_generate_admin_form_fields($this->publish_post_meta_box_hidden_fields, 'array');
2549
-        // add hidden fields
2550
-        $this->_template_args['publish_hidden_fields'] = $this->_template_args['publish_hidden_fields'] ?? '';
2551
-        foreach ($hidden_fields as $hidden_field) {
2552
-            $this->_template_args['publish_hidden_fields'] .= $hidden_field['field'] ?? '';
2553
-        }
2554
-    }
2555
-
2556
-
2557
-    /**
2558
-     * @param string|null $name
2559
-     * @param int|string  $id
2560
-     * @param string|null $delete
2561
-     * @param string|null $save_close_redirect_URL
2562
-     * @param bool        $both_btns
2563
-     * @throws EE_Error
2564
-     */
2565
-    public function set_publish_post_box_vars(
2566
-        ?string $name = '',
2567
-        $id = 0,
2568
-        ?string $delete = '',
2569
-        ?string $save_close_redirect_URL = '',
2570
-        bool $both_btns = false
2571
-    ) {
2572
-        $this->_set_publish_post_box_vars($name, $id, $delete, $save_close_redirect_URL, $both_btns);
2573
-    }
2574
-
2575
-
2576
-    protected function addPublishPostMetaBoxHiddenFields(string $field_name, array $field_attributes)
2577
-    {
2578
-        $this->publish_post_meta_box_hidden_fields[ $field_name ] = $field_attributes;
2579
-    }
2580
-
2581
-
2582
-    /**
2583
-     * displays an error message to ppl who have javascript disabled
2584
-     *
2585
-     * @return void
2586
-     */
2587
-    private function _display_no_javascript_warning()
2588
-    {
2589
-        ?>
2384
+	}
2385
+
2386
+
2387
+	private function _espresso_links_post_box()
2388
+	{
2389
+		// Hiding until we actually have content to put in here...
2390
+		// $this->addMetaBox('espresso_links_post_box', esc_html__('Helpful Plugin Links', 'event_espresso'), array( $this, 'espresso_links_post_box'), $this->_wp_page_slug, 'side');
2391
+	}
2392
+
2393
+
2394
+	public function espresso_links_post_box()
2395
+	{
2396
+		// Hiding until we actually have content to put in here...
2397
+		// EEH_Template::display_template(
2398
+		//     EE_ADMIN_TEMPLATE . 'admin_general_metabox_contents_espresso_links.template.php'
2399
+		// );
2400
+	}
2401
+
2402
+
2403
+	protected function _espresso_sponsors_post_box()
2404
+	{
2405
+		if (apply_filters('FHEE_show_sponsors_meta_box', true)) {
2406
+			$this->addMetaBox(
2407
+				'espresso_sponsors_post_box',
2408
+				esc_html__('Event Espresso Highlights', 'event_espresso'),
2409
+				[$this, 'espresso_sponsors_post_box'],
2410
+				$this->_wp_page_slug,
2411
+				'side'
2412
+			);
2413
+		}
2414
+	}
2415
+
2416
+
2417
+	public function espresso_sponsors_post_box()
2418
+	{
2419
+		EEH_Template::display_template(
2420
+			EE_ADMIN_TEMPLATE . 'admin_general_metabox_contents_espresso_sponsors.template.php'
2421
+		);
2422
+	}
2423
+
2424
+
2425
+	/**
2426
+	 * if there is [ 'label' => [ 'publishbox' => 'some title' ]]
2427
+	 * present in the _page_config array, then we'll use that for the metabox label.
2428
+	 * Otherwise we'll just use publish
2429
+	 * (publishbox itself could be an array of labels indexed by routes)
2430
+	 *
2431
+	 * @return string
2432
+	 * @since   5.0.0.p
2433
+	 */
2434
+	protected function getPublishBoxTitle(): string
2435
+	{
2436
+		$publish_box_title = esc_html__('Publish', 'event_espresso');
2437
+		if (! empty($this->_labels['publishbox'])) {
2438
+			if (is_array($this->_labels['publishbox'])) {
2439
+				$publish_box_title = $this->_labels['publishbox'][ $this->_req_action ] ?? $publish_box_title;
2440
+			} else {
2441
+				$publish_box_title = $this->_labels['publishbox'];
2442
+			}
2443
+		}
2444
+		return apply_filters(
2445
+			'FHEE__EE_Admin_Page___publish_post_box__box_label',
2446
+			$publish_box_title,
2447
+			$this->_req_action,
2448
+			$this
2449
+		);
2450
+	}
2451
+
2452
+
2453
+	/**
2454
+	 * @throws EE_Error
2455
+	 */
2456
+	private function _publish_post_box()
2457
+	{
2458
+		$title = $this->getPublishBoxTitle();
2459
+		if (empty($this->_template_args['save_buttons'])) {
2460
+			$this->_set_publish_post_box_vars(sanitize_key($title), "espresso_{$this->page_slug}_editor_overview");
2461
+		} else {
2462
+			$this->addPublishPostMetaBoxHiddenFields(
2463
+				sanitize_key($title),
2464
+				['type' => 'hidden', 'value' => "espresso_{$this->page_slug}_editor_overview"]
2465
+			);
2466
+		}
2467
+		$this->addMetaBox(
2468
+			"espresso_{$this->page_slug}_editor_overview",
2469
+			$title,
2470
+			[$this, 'editor_overview'],
2471
+			$this->_current_screen->id,
2472
+			'side',
2473
+			'high'
2474
+		);
2475
+	}
2476
+
2477
+
2478
+	public function editor_overview()
2479
+	{
2480
+		/**
2481
+		 * @var string $publish_box_extra_content
2482
+		 * @var string $publish_hidden_fields
2483
+		 * @var string $publish_delete_link
2484
+		 * @var string $save_buttons
2485
+		 */
2486
+		// if we have extra content set let's add it in if not make sure its empty
2487
+		$this->_template_args['publish_box_extra_content'] = $this->_template_args['publish_box_extra_content'] ?? '';
2488
+		echo EEH_Template::display_template(
2489
+			EE_ADMIN_TEMPLATE . 'admin_details_publish_metabox.template.php',
2490
+			$this->_template_args,
2491
+			true
2492
+		);
2493
+	}
2494
+
2495
+
2496
+	/** end of globally available metaboxes section **/
2497
+
2498
+
2499
+	/**
2500
+	 * Sets the _template_args arguments used by the _publish_post_box shortcut
2501
+	 * Note: currently there is no validation for this.  However, if you want the delete button, the
2502
+	 * save, and save and close buttons to work properly, then you will want to include a
2503
+	 * values for the name and id arguments.
2504
+	 *
2505
+	 * @param string|null $name                     key used for the action ID (i.e. event_id)
2506
+	 * @param int|string  $id                       id attached to the item published
2507
+	 * @param string|null $delete                   page route callback for the delete action
2508
+	 * @param string|null $save_close_redirect_URL  custom URL to redirect to after Save & Close has been completed
2509
+	 * @param bool        $both_btns                whether to display BOTH the "Save & Close" and "Save" buttons
2510
+	 *                                              or just the "Save" button
2511
+	 * @throws EE_Error
2512
+	 * @throws InvalidArgumentException
2513
+	 * @throws InvalidDataTypeException
2514
+	 * @throws InvalidInterfaceException
2515
+	 * @todo  Add in validation for name/id arguments.
2516
+	 */
2517
+	protected function _set_publish_post_box_vars(
2518
+		?string $name = '',
2519
+		$id = 0,
2520
+		?string $delete = '',
2521
+		?string $save_close_redirect_URL = '',
2522
+		bool $both_btns = true
2523
+	) {
2524
+		// if Save & Close, use a custom redirect URL or default to the main page?
2525
+		$save_close_redirect_URL = ! empty($save_close_redirect_URL)
2526
+			? $save_close_redirect_URL
2527
+			: $this->_admin_base_url;
2528
+		// create the Save & Close and Save buttons
2529
+		$this->_set_save_buttons($both_btns, [], [], $save_close_redirect_URL);
2530
+		// if we have extra content set let's add it in if not make sure its empty
2531
+		$this->_template_args['publish_box_extra_content'] = $this->_template_args['publish_box_extra_content'] ?? '';
2532
+		if ($delete && ! empty($id) && empty($this->_template_args['publish_delete_link'])) {
2533
+			// make sure we have a default if just true is sent.
2534
+			$delete                                      = ! empty($delete) ? $delete : 'delete';
2535
+			$this->_template_args['publish_delete_link'] = $this->get_action_link_or_button(
2536
+				$delete,
2537
+				$delete,
2538
+				[$name => $id],
2539
+				'submitdelete deletion button button--outline button--caution'
2540
+			);
2541
+		}
2542
+		if (! isset($this->_template_args['publish_delete_link'])) {
2543
+			$this->_template_args['publish_delete_link'] = '';
2544
+		}
2545
+		if (! empty($name) && ! empty($id)) {
2546
+			$this->addPublishPostMetaBoxHiddenFields($name, ['type' => 'hidden', 'value' => $id]);
2547
+		}
2548
+		$hidden_fields = $this->_generate_admin_form_fields($this->publish_post_meta_box_hidden_fields, 'array');
2549
+		// add hidden fields
2550
+		$this->_template_args['publish_hidden_fields'] = $this->_template_args['publish_hidden_fields'] ?? '';
2551
+		foreach ($hidden_fields as $hidden_field) {
2552
+			$this->_template_args['publish_hidden_fields'] .= $hidden_field['field'] ?? '';
2553
+		}
2554
+	}
2555
+
2556
+
2557
+	/**
2558
+	 * @param string|null $name
2559
+	 * @param int|string  $id
2560
+	 * @param string|null $delete
2561
+	 * @param string|null $save_close_redirect_URL
2562
+	 * @param bool        $both_btns
2563
+	 * @throws EE_Error
2564
+	 */
2565
+	public function set_publish_post_box_vars(
2566
+		?string $name = '',
2567
+		$id = 0,
2568
+		?string $delete = '',
2569
+		?string $save_close_redirect_URL = '',
2570
+		bool $both_btns = false
2571
+	) {
2572
+		$this->_set_publish_post_box_vars($name, $id, $delete, $save_close_redirect_URL, $both_btns);
2573
+	}
2574
+
2575
+
2576
+	protected function addPublishPostMetaBoxHiddenFields(string $field_name, array $field_attributes)
2577
+	{
2578
+		$this->publish_post_meta_box_hidden_fields[ $field_name ] = $field_attributes;
2579
+	}
2580
+
2581
+
2582
+	/**
2583
+	 * displays an error message to ppl who have javascript disabled
2584
+	 *
2585
+	 * @return void
2586
+	 */
2587
+	private function _display_no_javascript_warning()
2588
+	{
2589
+		?>
2590 2590
 <noscript>
2591 2591
     <div id="no-js-message" class="error">
2592 2592
         <p style="font-size:1.3em;">
2593 2593
             <span style="color:red;"><?php esc_html_e('Warning!', 'event_espresso'); ?></span>
2594 2594
             <?php esc_html_e(
2595
-                'Javascript is currently turned off for your browser. Javascript must be enabled in order for all of the features on this page to function properly. Please turn your javascript back on.',
2596
-                'event_espresso'
2597
-            ); ?>
2595
+				'Javascript is currently turned off for your browser. Javascript must be enabled in order for all of the features on this page to function properly. Please turn your javascript back on.',
2596
+				'event_espresso'
2597
+			); ?>
2598 2598
         </p>
2599 2599
     </div>
2600 2600
 </noscript>
2601 2601
 <?php
2602
-    }
2603
-
2604
-
2605
-    /**
2606
-     * displays espresso success and/or error notices
2607
-     *
2608
-     * @return void
2609
-     */
2610
-    protected function _display_espresso_notices()
2611
-    {
2612
-        $notices = (array) $this->_get_transient(true);
2613
-        foreach ($notices as $notice) {
2614
-            echo $notice ? stripslashes($notice) : '';
2615
-        }
2616
-    }
2617
-
2618
-
2619
-    /**
2620
-     * spinny things pacify the masses
2621
-     *
2622
-     * @return void
2623
-     */
2624
-    protected function _add_admin_page_ajax_loading_img()
2625
-    {
2626
-        ?>
2602
+	}
2603
+
2604
+
2605
+	/**
2606
+	 * displays espresso success and/or error notices
2607
+	 *
2608
+	 * @return void
2609
+	 */
2610
+	protected function _display_espresso_notices()
2611
+	{
2612
+		$notices = (array) $this->_get_transient(true);
2613
+		foreach ($notices as $notice) {
2614
+			echo $notice ? stripslashes($notice) : '';
2615
+		}
2616
+	}
2617
+
2618
+
2619
+	/**
2620
+	 * spinny things pacify the masses
2621
+	 *
2622
+	 * @return void
2623
+	 */
2624
+	protected function _add_admin_page_ajax_loading_img()
2625
+	{
2626
+		?>
2627 2627
 <div id="espresso-ajax-loading" class="ajax-loading-grey">
2628 2628
     <span class="ee-spinner ee-spin"></span><span class="hidden"><?php
2629
-                esc_html_e('loading...', 'event_espresso'); ?></span>
2629
+				esc_html_e('loading...', 'event_espresso'); ?></span>
2630 2630
 </div>
2631 2631
 <?php
2632
-    }
2632
+	}
2633 2633
 
2634 2634
 
2635
-    /**
2636
-     * add admin page overlay for modal boxes
2637
-     *
2638
-     * @return void
2639
-     */
2640
-    protected function _add_admin_page_overlay()
2641
-    {
2642
-        ?>
2635
+	/**
2636
+	 * add admin page overlay for modal boxes
2637
+	 *
2638
+	 * @return void
2639
+	 */
2640
+	protected function _add_admin_page_overlay()
2641
+	{
2642
+		?>
2643 2643
 <div id="espresso-admin-page-overlay-dv" class=""></div>
2644 2644
 <?php
2645
-    }
2646
-
2647
-
2648
-    /**
2649
-     * facade for $this->addMetaBox()
2650
-     *
2651
-     * @param string   $action        where the metabox gets displayed
2652
-     * @param string   $title         Title of Metabox (output in metabox header)
2653
-     * @param callable $callback      If not empty and $create_fun is set to false then we'll use a custom callback
2654
-     *                                instead of the one created in here.
2655
-     * @param array    $callback_args an array of args supplied for the metabox
2656
-     * @param string   $column        what metabox column
2657
-     * @param string   $priority      give this metabox a priority (using accepted priorities for wp meta boxes)
2658
-     * @param bool     $create_func   default is true.  Basically we can say we don't WANT to have the runtime function
2659
-     *                                created but just set our own callback for wp's add_meta_box.
2660
-     * @throws DomainException
2661
-     */
2662
-    public function _add_admin_page_meta_box(
2663
-        string $action,
2664
-        string $title,
2665
-        callable $callback,
2666
-        array $callback_args,
2667
-        string $column = 'normal',
2668
-        string $priority = 'high',
2669
-        bool $create_func = true
2670
-    ) {
2671
-        // if we have empty callback args and we want to automatically create the metabox callback then we need to make sure the callback args are generated.
2672
-        if (empty($callback_args) && $create_func) {
2673
-            $callback_args = [
2674
-                'template_path' => $this->_template_path,
2675
-                'template_args' => $this->_template_args,
2676
-            ];
2677
-        }
2678
-        // if $create_func is true (default) then we automatically create the function for displaying the actual meta box.  If false then we take the $callback reference passed through and use it instead (so callers can define their own callback function/method if they wish)
2679
-        $call_back_func = $create_func
2680
-            ? static function ($post, $metabox) {
2681
-                echo EEH_Template::display_template(
2682
-                    $metabox['args']['template_path'],
2683
-                    $metabox['args']['template_args'],
2684
-                    true
2685
-                );
2686
-            }
2687
-            : $callback;
2688
-        $this->addMetaBox(
2689
-            str_replace('_', '-', $action) . '-mbox',
2690
-            $title,
2691
-            $call_back_func,
2692
-            $this->_wp_page_slug,
2693
-            $column,
2694
-            $priority,
2695
-            $callback_args
2696
-        );
2697
-    }
2698
-
2699
-
2700
-    /**
2701
-     * generates HTML wrapper for and admin details page that contains metaboxes in columns
2702
-     *
2703
-     * @throws DomainException
2704
-     * @throws EE_Error
2705
-     * @throws InvalidArgumentException
2706
-     * @throws InvalidDataTypeException
2707
-     * @throws InvalidInterfaceException
2708
-     */
2709
-    public function display_admin_page_with_metabox_columns()
2710
-    {
2711
-        $this->_template_args['post_body_content']  = $this->_template_args['admin_page_content'];
2712
-        $this->_template_args['admin_page_content'] = EEH_Template::display_template(
2713
-            $this->_column_template_path,
2714
-            $this->_template_args,
2715
-            true
2716
-        );
2717
-        // the final wrapper
2718
-        $this->admin_page_wrapper();
2719
-    }
2720
-
2721
-
2722
-    /**
2723
-     * generates  HTML wrapper for an admin details page
2724
-     *
2725
-     * @return void
2726
-     * @throws DomainException
2727
-     * @throws EE_Error
2728
-     * @throws InvalidArgumentException
2729
-     * @throws InvalidDataTypeException
2730
-     * @throws InvalidInterfaceException
2731
-     */
2732
-    public function display_admin_page_with_sidebar()
2733
-    {
2734
-        $this->_display_admin_page(true);
2735
-    }
2736
-
2737
-
2738
-    /**
2739
-     * generates  HTML wrapper for an admin details page (except no sidebar)
2740
-     *
2741
-     * @return void
2742
-     * @throws DomainException
2743
-     * @throws EE_Error
2744
-     * @throws InvalidArgumentException
2745
-     * @throws InvalidDataTypeException
2746
-     * @throws InvalidInterfaceException
2747
-     */
2748
-    public function display_admin_page_with_no_sidebar()
2749
-    {
2750
-        $this->_display_admin_page();
2751
-    }
2752
-
2753
-
2754
-    /**
2755
-     * generates HTML wrapper for an EE about admin page (no sidebar)
2756
-     *
2757
-     * @return void
2758
-     * @throws DomainException
2759
-     * @throws EE_Error
2760
-     * @throws InvalidArgumentException
2761
-     * @throws InvalidDataTypeException
2762
-     * @throws InvalidInterfaceException
2763
-     */
2764
-    public function display_about_admin_page()
2765
-    {
2766
-        $this->_display_admin_page(false, true);
2767
-    }
2768
-
2769
-
2770
-    /**
2771
-     * display_admin_page
2772
-     * contains the code for actually displaying an admin page
2773
-     *
2774
-     * @param bool $sidebar true with sidebar, false without
2775
-     * @param bool $about   use the About admin wrapper instead of the default.
2776
-     * @return void
2777
-     * @throws DomainException
2778
-     * @throws EE_Error
2779
-     * @throws InvalidArgumentException
2780
-     * @throws InvalidDataTypeException
2781
-     * @throws InvalidInterfaceException
2782
-     */
2783
-    private function _display_admin_page(bool $sidebar = false, bool $about = false): void
2784
-    {
2785
-        // custom remove metaboxes hook to add or remove any metaboxes to/from Admin pages.
2786
-        do_action('AHEE__EE_Admin_Page___display_admin_page__modify_metaboxes');
2787
-
2788
-        // set current wp page slug - looks like: event-espresso_page_event_categories
2789
-        // keep in mind "event-espresso" COULD be something else if the top level menu label has been translated.
2790
-        $post_body_content = $this->_template_args['before_admin_page_content'] ?? '';
2791
-
2792
-        $this->_template_args['add_page_frame'] = $this->_req_action !== 'system_status'
2793
-                                                  && $this->_req_action !== 'data_reset'
2794
-                                                  && $this->_wp_page_slug !== 'event-espresso_page_espresso_packages'
2795
-                                                  && strpos($post_body_content, 'wp-list-table') === false;
2796
-
2797
-        $this->_template_args['current_page']                 = $this->_wp_page_slug;
2798
-        $this->_template_args['admin_page_wrapper_div_id']    = $this->_cpt_route
2799
-            ? 'poststuff'
2800
-            : 'espresso-default-admin';
2801
-        $this->_template_args['admin_page_wrapper_div_class'] = str_replace(
2802
-            'event-espresso_page_espresso_',
2803
-            '',
2804
-            $this->_wp_page_slug
2805
-        ) . ' ' . $this->_req_action . '-route';
2806
-
2807
-        $template_path = $sidebar
2808
-            ? EE_ADMIN_TEMPLATE . 'admin_details_wrapper.template.php'
2809
-            : EE_ADMIN_TEMPLATE . 'admin_details_wrapper_no_sidebar.template.php';
2810
-
2811
-        $this->_template_args['is_ajax'] = $this->request->isAjax();
2812
-        if ($this->request->isAjax()) {
2813
-            $template_path = EE_ADMIN_TEMPLATE . 'admin_details_wrapper_no_sidebar_ajax.template.php';
2814
-        }
2815
-        $template_path = ! empty($this->_column_template_path) ? $this->_column_template_path : $template_path;
2816
-
2817
-        $this->_template_args['post_body_content']         = $this->_template_args['admin_page_content'] ?? '';
2818
-        $this->_template_args['before_admin_page_content'] = $post_body_content;
2819
-        $this->_template_args['after_admin_page_content']  = $this->_template_args['after_admin_page_content'] ?? '';
2820
-
2821
-        // ensure $post_type and $post are set
2822
-        // to prevent WooCommerce from blowing things up if not using CPT
2823
-        global $post_type, $post;
2824
-        $this->_template_args['post_type'] = $post_type ?? '';
2825
-        $this->_template_args['post']  = $post ?? new WP_Post((object) [ 'ID' => 0, 'filter' => 'raw' ]);
2826
-
2827
-        $this->_template_args['post_body_content'] = EEH_Template::display_template(
2828
-            EE_ADMIN_TEMPLATE . 'admin_details_wrapper_post_body_content.template.php',
2829
-            $this->_template_args,
2830
-            true
2831
-        );
2832
-
2833
-        $this->_template_args['admin_page_content'] = EEH_Template::display_template(
2834
-            $template_path,
2835
-            $this->_template_args,
2836
-            true
2837
-        );
2838
-        // the final template wrapper
2839
-        $this->admin_page_wrapper($about);
2840
-    }
2841
-
2842
-
2843
-    /**
2844
-     * This is used to display caf preview pages.
2845
-     *
2846
-     * @param string $utm_campaign_source what is the key used for Google Analytics link
2847
-     * @param bool   $display_sidebar     whether to use the sidebar template or the full template for the page.  TRUE
2848
-     *                                    = SHOW sidebar, FALSE = no sidebar. Default no sidebar.
2849
-     * @return void
2850
-     * @throws DomainException
2851
-     * @throws EE_Error
2852
-     * @throws InvalidArgumentException
2853
-     * @throws InvalidDataTypeException
2854
-     * @throws InvalidInterfaceException
2855
-     * @since 4.3.2
2856
-     */
2857
-    public function display_admin_caf_preview_page(string $utm_campaign_source = '', bool $display_sidebar = true)
2858
-    {
2859
-        // let's generate a default preview action button if there isn't one already present.
2860
-        $this->_labels['buttons']['buy_now']           = esc_html__(
2861
-            'Upgrade to Event Espresso 4 Right Now',
2862
-            'event_espresso'
2863
-        );
2864
-        $buy_now_url                                   = add_query_arg(
2865
-            [
2866
-                'ee_ver'       => 'ee4',
2867
-                'utm_source'   => 'ee4_plugin_admin',
2868
-                'utm_medium'   => 'link',
2869
-                'utm_campaign' => $utm_campaign_source,
2870
-                'utm_content'  => 'buy_now_button',
2871
-            ],
2872
-            'https://eventespresso.com/pricing/'
2873
-        );
2874
-        $this->_template_args['preview_action_button'] = ! isset($this->_template_args['preview_action_button'])
2875
-            ? $this->get_action_link_or_button(
2876
-                '',
2877
-                'buy_now',
2878
-                [],
2879
-                'button button--primary button--big',
2880
-                esc_url_raw($buy_now_url),
2881
-                true
2882
-            )
2883
-            : $this->_template_args['preview_action_button'];
2884
-        $this->_template_args['admin_page_content']    = EEH_Template::display_template(
2885
-            EE_ADMIN_TEMPLATE . 'admin_caf_full_page_preview.template.php',
2886
-            $this->_template_args,
2887
-            true
2888
-        );
2889
-        $this->_display_admin_page($display_sidebar);
2890
-    }
2891
-
2892
-
2893
-    /**
2894
-     * display_admin_list_table_page_with_sidebar
2895
-     * generates HTML wrapper for an admin_page with list_table
2896
-     *
2897
-     * @return void
2898
-     * @throws DomainException
2899
-     * @throws EE_Error
2900
-     * @throws InvalidArgumentException
2901
-     * @throws InvalidDataTypeException
2902
-     * @throws InvalidInterfaceException
2903
-     */
2904
-    public function display_admin_list_table_page_with_sidebar()
2905
-    {
2906
-        $this->_display_admin_list_table_page(true);
2907
-    }
2908
-
2909
-
2910
-    /**
2911
-     * display_admin_list_table_page_with_no_sidebar
2912
-     * generates HTML wrapper for an admin_page with list_table (but with no sidebar)
2913
-     *
2914
-     * @return void
2915
-     * @throws DomainException
2916
-     * @throws EE_Error
2917
-     * @throws InvalidArgumentException
2918
-     * @throws InvalidDataTypeException
2919
-     * @throws InvalidInterfaceException
2920
-     */
2921
-    public function display_admin_list_table_page_with_no_sidebar()
2922
-    {
2923
-        $this->_display_admin_list_table_page();
2924
-    }
2925
-
2926
-
2927
-    /**
2928
-     * generates html wrapper for an admin_list_table page
2929
-     *
2930
-     * @param bool $sidebar whether to display with sidebar or not.
2931
-     * @return void
2932
-     * @throws DomainException
2933
-     * @throws EE_Error
2934
-     * @throws InvalidArgumentException
2935
-     * @throws InvalidDataTypeException
2936
-     * @throws InvalidInterfaceException
2937
-     */
2938
-    private function _display_admin_list_table_page(bool $sidebar = false)
2939
-    {
2940
-        // setup search attributes
2941
-        $this->_set_search_attributes();
2942
-        $this->_template_args['current_page']     = $this->_wp_page_slug;
2943
-        $template_path                            = EE_ADMIN_TEMPLATE . 'admin_list_wrapper.template.php';
2944
-        $this->_template_args['table_url']        = $this->request->isAjax()
2945
-            ? add_query_arg(['noheader' => 'true', 'route' => $this->_req_action], $this->_admin_base_url)
2946
-            : add_query_arg(['route' => $this->_req_action], $this->_admin_base_url);
2947
-        $this->_template_args['list_table']       = $this->_list_table_object;
2948
-        $this->_template_args['current_route']    = $this->_req_action;
2949
-        $this->_template_args['list_table_class'] = get_class($this->_list_table_object);
2950
-        $ajax_sorting_callback                    = $this->_list_table_object->get_ajax_sorting_callback();
2951
-        if (! empty($ajax_sorting_callback)) {
2952
-            $sortable_list_table_form_fields = wp_nonce_field(
2953
-                $ajax_sorting_callback . '_nonce',
2954
-                $ajax_sorting_callback . '_nonce',
2955
-                false,
2956
-                false
2957
-            );
2958
-            $sortable_list_table_form_fields .= '<input type="hidden" id="ajax_table_sort_page" name="ajax_table_sort_page" value="'
2959
-                                                . $this->page_slug
2960
-                                                . '" />';
2961
-            $sortable_list_table_form_fields .= '<input type="hidden" id="ajax_table_sort_action" name="ajax_table_sort_action" value="'
2962
-                                                . $ajax_sorting_callback
2963
-                                                . '" />';
2964
-        } else {
2965
-            $sortable_list_table_form_fields = '';
2966
-        }
2967
-        $this->_template_args['sortable_list_table_form_fields'] = $sortable_list_table_form_fields;
2968
-
2969
-        $hidden_form_fields = $this->_template_args['list_table_hidden_fields'] ?? '';
2970
-
2971
-        $nonce_ref          = $this->_req_action . '_nonce';
2972
-        $hidden_form_fields .= '
2645
+	}
2646
+
2647
+
2648
+	/**
2649
+	 * facade for $this->addMetaBox()
2650
+	 *
2651
+	 * @param string   $action        where the metabox gets displayed
2652
+	 * @param string   $title         Title of Metabox (output in metabox header)
2653
+	 * @param callable $callback      If not empty and $create_fun is set to false then we'll use a custom callback
2654
+	 *                                instead of the one created in here.
2655
+	 * @param array    $callback_args an array of args supplied for the metabox
2656
+	 * @param string   $column        what metabox column
2657
+	 * @param string   $priority      give this metabox a priority (using accepted priorities for wp meta boxes)
2658
+	 * @param bool     $create_func   default is true.  Basically we can say we don't WANT to have the runtime function
2659
+	 *                                created but just set our own callback for wp's add_meta_box.
2660
+	 * @throws DomainException
2661
+	 */
2662
+	public function _add_admin_page_meta_box(
2663
+		string $action,
2664
+		string $title,
2665
+		callable $callback,
2666
+		array $callback_args,
2667
+		string $column = 'normal',
2668
+		string $priority = 'high',
2669
+		bool $create_func = true
2670
+	) {
2671
+		// if we have empty callback args and we want to automatically create the metabox callback then we need to make sure the callback args are generated.
2672
+		if (empty($callback_args) && $create_func) {
2673
+			$callback_args = [
2674
+				'template_path' => $this->_template_path,
2675
+				'template_args' => $this->_template_args,
2676
+			];
2677
+		}
2678
+		// if $create_func is true (default) then we automatically create the function for displaying the actual meta box.  If false then we take the $callback reference passed through and use it instead (so callers can define their own callback function/method if they wish)
2679
+		$call_back_func = $create_func
2680
+			? static function ($post, $metabox) {
2681
+				echo EEH_Template::display_template(
2682
+					$metabox['args']['template_path'],
2683
+					$metabox['args']['template_args'],
2684
+					true
2685
+				);
2686
+			}
2687
+			: $callback;
2688
+		$this->addMetaBox(
2689
+			str_replace('_', '-', $action) . '-mbox',
2690
+			$title,
2691
+			$call_back_func,
2692
+			$this->_wp_page_slug,
2693
+			$column,
2694
+			$priority,
2695
+			$callback_args
2696
+		);
2697
+	}
2698
+
2699
+
2700
+	/**
2701
+	 * generates HTML wrapper for and admin details page that contains metaboxes in columns
2702
+	 *
2703
+	 * @throws DomainException
2704
+	 * @throws EE_Error
2705
+	 * @throws InvalidArgumentException
2706
+	 * @throws InvalidDataTypeException
2707
+	 * @throws InvalidInterfaceException
2708
+	 */
2709
+	public function display_admin_page_with_metabox_columns()
2710
+	{
2711
+		$this->_template_args['post_body_content']  = $this->_template_args['admin_page_content'];
2712
+		$this->_template_args['admin_page_content'] = EEH_Template::display_template(
2713
+			$this->_column_template_path,
2714
+			$this->_template_args,
2715
+			true
2716
+		);
2717
+		// the final wrapper
2718
+		$this->admin_page_wrapper();
2719
+	}
2720
+
2721
+
2722
+	/**
2723
+	 * generates  HTML wrapper for an admin details page
2724
+	 *
2725
+	 * @return void
2726
+	 * @throws DomainException
2727
+	 * @throws EE_Error
2728
+	 * @throws InvalidArgumentException
2729
+	 * @throws InvalidDataTypeException
2730
+	 * @throws InvalidInterfaceException
2731
+	 */
2732
+	public function display_admin_page_with_sidebar()
2733
+	{
2734
+		$this->_display_admin_page(true);
2735
+	}
2736
+
2737
+
2738
+	/**
2739
+	 * generates  HTML wrapper for an admin details page (except no sidebar)
2740
+	 *
2741
+	 * @return void
2742
+	 * @throws DomainException
2743
+	 * @throws EE_Error
2744
+	 * @throws InvalidArgumentException
2745
+	 * @throws InvalidDataTypeException
2746
+	 * @throws InvalidInterfaceException
2747
+	 */
2748
+	public function display_admin_page_with_no_sidebar()
2749
+	{
2750
+		$this->_display_admin_page();
2751
+	}
2752
+
2753
+
2754
+	/**
2755
+	 * generates HTML wrapper for an EE about admin page (no sidebar)
2756
+	 *
2757
+	 * @return void
2758
+	 * @throws DomainException
2759
+	 * @throws EE_Error
2760
+	 * @throws InvalidArgumentException
2761
+	 * @throws InvalidDataTypeException
2762
+	 * @throws InvalidInterfaceException
2763
+	 */
2764
+	public function display_about_admin_page()
2765
+	{
2766
+		$this->_display_admin_page(false, true);
2767
+	}
2768
+
2769
+
2770
+	/**
2771
+	 * display_admin_page
2772
+	 * contains the code for actually displaying an admin page
2773
+	 *
2774
+	 * @param bool $sidebar true with sidebar, false without
2775
+	 * @param bool $about   use the About admin wrapper instead of the default.
2776
+	 * @return void
2777
+	 * @throws DomainException
2778
+	 * @throws EE_Error
2779
+	 * @throws InvalidArgumentException
2780
+	 * @throws InvalidDataTypeException
2781
+	 * @throws InvalidInterfaceException
2782
+	 */
2783
+	private function _display_admin_page(bool $sidebar = false, bool $about = false): void
2784
+	{
2785
+		// custom remove metaboxes hook to add or remove any metaboxes to/from Admin pages.
2786
+		do_action('AHEE__EE_Admin_Page___display_admin_page__modify_metaboxes');
2787
+
2788
+		// set current wp page slug - looks like: event-espresso_page_event_categories
2789
+		// keep in mind "event-espresso" COULD be something else if the top level menu label has been translated.
2790
+		$post_body_content = $this->_template_args['before_admin_page_content'] ?? '';
2791
+
2792
+		$this->_template_args['add_page_frame'] = $this->_req_action !== 'system_status'
2793
+												  && $this->_req_action !== 'data_reset'
2794
+												  && $this->_wp_page_slug !== 'event-espresso_page_espresso_packages'
2795
+												  && strpos($post_body_content, 'wp-list-table') === false;
2796
+
2797
+		$this->_template_args['current_page']                 = $this->_wp_page_slug;
2798
+		$this->_template_args['admin_page_wrapper_div_id']    = $this->_cpt_route
2799
+			? 'poststuff'
2800
+			: 'espresso-default-admin';
2801
+		$this->_template_args['admin_page_wrapper_div_class'] = str_replace(
2802
+			'event-espresso_page_espresso_',
2803
+			'',
2804
+			$this->_wp_page_slug
2805
+		) . ' ' . $this->_req_action . '-route';
2806
+
2807
+		$template_path = $sidebar
2808
+			? EE_ADMIN_TEMPLATE . 'admin_details_wrapper.template.php'
2809
+			: EE_ADMIN_TEMPLATE . 'admin_details_wrapper_no_sidebar.template.php';
2810
+
2811
+		$this->_template_args['is_ajax'] = $this->request->isAjax();
2812
+		if ($this->request->isAjax()) {
2813
+			$template_path = EE_ADMIN_TEMPLATE . 'admin_details_wrapper_no_sidebar_ajax.template.php';
2814
+		}
2815
+		$template_path = ! empty($this->_column_template_path) ? $this->_column_template_path : $template_path;
2816
+
2817
+		$this->_template_args['post_body_content']         = $this->_template_args['admin_page_content'] ?? '';
2818
+		$this->_template_args['before_admin_page_content'] = $post_body_content;
2819
+		$this->_template_args['after_admin_page_content']  = $this->_template_args['after_admin_page_content'] ?? '';
2820
+
2821
+		// ensure $post_type and $post are set
2822
+		// to prevent WooCommerce from blowing things up if not using CPT
2823
+		global $post_type, $post;
2824
+		$this->_template_args['post_type'] = $post_type ?? '';
2825
+		$this->_template_args['post']  = $post ?? new WP_Post((object) [ 'ID' => 0, 'filter' => 'raw' ]);
2826
+
2827
+		$this->_template_args['post_body_content'] = EEH_Template::display_template(
2828
+			EE_ADMIN_TEMPLATE . 'admin_details_wrapper_post_body_content.template.php',
2829
+			$this->_template_args,
2830
+			true
2831
+		);
2832
+
2833
+		$this->_template_args['admin_page_content'] = EEH_Template::display_template(
2834
+			$template_path,
2835
+			$this->_template_args,
2836
+			true
2837
+		);
2838
+		// the final template wrapper
2839
+		$this->admin_page_wrapper($about);
2840
+	}
2841
+
2842
+
2843
+	/**
2844
+	 * This is used to display caf preview pages.
2845
+	 *
2846
+	 * @param string $utm_campaign_source what is the key used for Google Analytics link
2847
+	 * @param bool   $display_sidebar     whether to use the sidebar template or the full template for the page.  TRUE
2848
+	 *                                    = SHOW sidebar, FALSE = no sidebar. Default no sidebar.
2849
+	 * @return void
2850
+	 * @throws DomainException
2851
+	 * @throws EE_Error
2852
+	 * @throws InvalidArgumentException
2853
+	 * @throws InvalidDataTypeException
2854
+	 * @throws InvalidInterfaceException
2855
+	 * @since 4.3.2
2856
+	 */
2857
+	public function display_admin_caf_preview_page(string $utm_campaign_source = '', bool $display_sidebar = true)
2858
+	{
2859
+		// let's generate a default preview action button if there isn't one already present.
2860
+		$this->_labels['buttons']['buy_now']           = esc_html__(
2861
+			'Upgrade to Event Espresso 4 Right Now',
2862
+			'event_espresso'
2863
+		);
2864
+		$buy_now_url                                   = add_query_arg(
2865
+			[
2866
+				'ee_ver'       => 'ee4',
2867
+				'utm_source'   => 'ee4_plugin_admin',
2868
+				'utm_medium'   => 'link',
2869
+				'utm_campaign' => $utm_campaign_source,
2870
+				'utm_content'  => 'buy_now_button',
2871
+			],
2872
+			'https://eventespresso.com/pricing/'
2873
+		);
2874
+		$this->_template_args['preview_action_button'] = ! isset($this->_template_args['preview_action_button'])
2875
+			? $this->get_action_link_or_button(
2876
+				'',
2877
+				'buy_now',
2878
+				[],
2879
+				'button button--primary button--big',
2880
+				esc_url_raw($buy_now_url),
2881
+				true
2882
+			)
2883
+			: $this->_template_args['preview_action_button'];
2884
+		$this->_template_args['admin_page_content']    = EEH_Template::display_template(
2885
+			EE_ADMIN_TEMPLATE . 'admin_caf_full_page_preview.template.php',
2886
+			$this->_template_args,
2887
+			true
2888
+		);
2889
+		$this->_display_admin_page($display_sidebar);
2890
+	}
2891
+
2892
+
2893
+	/**
2894
+	 * display_admin_list_table_page_with_sidebar
2895
+	 * generates HTML wrapper for an admin_page with list_table
2896
+	 *
2897
+	 * @return void
2898
+	 * @throws DomainException
2899
+	 * @throws EE_Error
2900
+	 * @throws InvalidArgumentException
2901
+	 * @throws InvalidDataTypeException
2902
+	 * @throws InvalidInterfaceException
2903
+	 */
2904
+	public function display_admin_list_table_page_with_sidebar()
2905
+	{
2906
+		$this->_display_admin_list_table_page(true);
2907
+	}
2908
+
2909
+
2910
+	/**
2911
+	 * display_admin_list_table_page_with_no_sidebar
2912
+	 * generates HTML wrapper for an admin_page with list_table (but with no sidebar)
2913
+	 *
2914
+	 * @return void
2915
+	 * @throws DomainException
2916
+	 * @throws EE_Error
2917
+	 * @throws InvalidArgumentException
2918
+	 * @throws InvalidDataTypeException
2919
+	 * @throws InvalidInterfaceException
2920
+	 */
2921
+	public function display_admin_list_table_page_with_no_sidebar()
2922
+	{
2923
+		$this->_display_admin_list_table_page();
2924
+	}
2925
+
2926
+
2927
+	/**
2928
+	 * generates html wrapper for an admin_list_table page
2929
+	 *
2930
+	 * @param bool $sidebar whether to display with sidebar or not.
2931
+	 * @return void
2932
+	 * @throws DomainException
2933
+	 * @throws EE_Error
2934
+	 * @throws InvalidArgumentException
2935
+	 * @throws InvalidDataTypeException
2936
+	 * @throws InvalidInterfaceException
2937
+	 */
2938
+	private function _display_admin_list_table_page(bool $sidebar = false)
2939
+	{
2940
+		// setup search attributes
2941
+		$this->_set_search_attributes();
2942
+		$this->_template_args['current_page']     = $this->_wp_page_slug;
2943
+		$template_path                            = EE_ADMIN_TEMPLATE . 'admin_list_wrapper.template.php';
2944
+		$this->_template_args['table_url']        = $this->request->isAjax()
2945
+			? add_query_arg(['noheader' => 'true', 'route' => $this->_req_action], $this->_admin_base_url)
2946
+			: add_query_arg(['route' => $this->_req_action], $this->_admin_base_url);
2947
+		$this->_template_args['list_table']       = $this->_list_table_object;
2948
+		$this->_template_args['current_route']    = $this->_req_action;
2949
+		$this->_template_args['list_table_class'] = get_class($this->_list_table_object);
2950
+		$ajax_sorting_callback                    = $this->_list_table_object->get_ajax_sorting_callback();
2951
+		if (! empty($ajax_sorting_callback)) {
2952
+			$sortable_list_table_form_fields = wp_nonce_field(
2953
+				$ajax_sorting_callback . '_nonce',
2954
+				$ajax_sorting_callback . '_nonce',
2955
+				false,
2956
+				false
2957
+			);
2958
+			$sortable_list_table_form_fields .= '<input type="hidden" id="ajax_table_sort_page" name="ajax_table_sort_page" value="'
2959
+												. $this->page_slug
2960
+												. '" />';
2961
+			$sortable_list_table_form_fields .= '<input type="hidden" id="ajax_table_sort_action" name="ajax_table_sort_action" value="'
2962
+												. $ajax_sorting_callback
2963
+												. '" />';
2964
+		} else {
2965
+			$sortable_list_table_form_fields = '';
2966
+		}
2967
+		$this->_template_args['sortable_list_table_form_fields'] = $sortable_list_table_form_fields;
2968
+
2969
+		$hidden_form_fields = $this->_template_args['list_table_hidden_fields'] ?? '';
2970
+
2971
+		$nonce_ref          = $this->_req_action . '_nonce';
2972
+		$hidden_form_fields .= '
2973 2973
             <input type="hidden" name="' . $nonce_ref . '" value="' . wp_create_nonce($nonce_ref) . '">';
2974 2974
 
2975
-        $this->_template_args['list_table_hidden_fields'] = $hidden_form_fields;
2976
-        // display message about search results?
2977
-        $search                                    = $this->request->getRequestParam('s');
2978
-        $this->_template_args['before_list_table'] .= ! empty($search)
2979
-            ? '<p class="ee-search-results">' . sprintf(
2980
-                esc_html__('Displaying search results for the search string: %1$s', 'event_espresso'),
2981
-                trim($search, '%')
2982
-            ) . '</p>'
2983
-            : '';
2984
-        // filter before_list_table template arg
2985
-        $this->_template_args['before_list_table'] = apply_filters(
2986
-            'FHEE__EE_Admin_Page___display_admin_list_table_page__before_list_table__template_arg',
2987
-            $this->_template_args['before_list_table'],
2988
-            $this->page_slug,
2989
-            $this->request->requestParams(),
2990
-            $this->_req_action
2991
-        );
2992
-        // convert to array and filter again
2993
-        // arrays are easier to inject new items in a specific location,
2994
-        // but would not be backwards compatible, so we have to add a new filter
2995
-        $this->_template_args['before_list_table'] = implode(
2996
-            " \n",
2997
-            (array) apply_filters(
2998
-                'FHEE__EE_Admin_Page___display_admin_list_table_page__before_list_table__template_args_array',
2999
-                (array) $this->_template_args['before_list_table'],
3000
-                $this->page_slug,
3001
-                $this->request->requestParams(),
3002
-                $this->_req_action
3003
-            )
3004
-        );
3005
-        // filter after_list_table template arg
3006
-        $this->_template_args['after_list_table'] = apply_filters(
3007
-            'FHEE__EE_Admin_Page___display_admin_list_table_page__after_list_table__template_arg',
3008
-            $this->_template_args['after_list_table'],
3009
-            $this->page_slug,
3010
-            $this->request->requestParams(),
3011
-            $this->_req_action
3012
-        );
3013
-        // convert to array and filter again
3014
-        // arrays are easier to inject new items in a specific location,
3015
-        // but would not be backwards compatible, so we have to add a new filter
3016
-        $this->_template_args['after_list_table']   = implode(
3017
-            " \n",
3018
-            (array) apply_filters(
3019
-                'FHEE__EE_Admin_Page___display_admin_list_table_page__after_list_table__template_args_array',
3020
-                (array) $this->_template_args['after_list_table'],
3021
-                $this->page_slug,
3022
-                $this->request->requestParams(),
3023
-                $this->_req_action
3024
-            )
3025
-        );
3026
-        $this->_template_args['admin_page_content'] = EEH_Template::display_template(
3027
-            $template_path,
3028
-            $this->_template_args,
3029
-            true
3030
-        );
3031
-        // the final template wrapper
3032
-        if ($sidebar) {
3033
-            $this->display_admin_page_with_sidebar();
3034
-        } else {
3035
-            $this->display_admin_page_with_no_sidebar();
3036
-        }
3037
-    }
3038
-
3039
-
3040
-    /**
3041
-     * This just prepares a legend using the given items and the admin_details_legend.template.php file and returns the
3042
-     * html string for the legend.
3043
-     * $items are expected in an array in the following format:
3044
-     * $legend_items = array(
3045
-     *        'item_id' => array(
3046
-     *            'icon' => 'http://url_to_icon_being_described.png',
3047
-     *            'desc' => esc_html__('localized description of item');
3048
-     *        )
3049
-     * );
3050
-     *
3051
-     * @param array $items see above for format of array
3052
-     * @return string html string of legend
3053
-     * @throws DomainException
3054
-     */
3055
-    protected function _display_legend(array $items): string
3056
-    {
3057
-        $this->_template_args['items'] = (array) apply_filters(
3058
-            'FHEE__EE_Admin_Page___display_legend__items',
3059
-            $items,
3060
-            $this
3061
-        );
3062
-        /** @var StatusChangeNotice $status_change_notice */
3063
-        $status_change_notice                         = $this->loader->getShared(
3064
-            'EventEspresso\core\domain\services\admin\notices\status_change\StatusChangeNotice'
3065
-        );
3066
-        $this->_template_args['status_change_notice'] = $status_change_notice->display(
3067
-            '__admin-legend',
3068
-            $this->page_slug
3069
-        );
3070
-        return EEH_Template::display_template(
3071
-            EE_ADMIN_TEMPLATE . 'admin_details_legend.template.php',
3072
-            $this->_template_args,
3073
-            true
3074
-        );
3075
-    }
3076
-
3077
-
3078
-    /**
3079
-     * This is used whenever we're DOING_AJAX to return a formatted json array that our calling javascript can expect
3080
-     * The returned json object is created from an array in the following format:
3081
-     * array(
3082
-     *  'error' => FALSE, //(default FALSE), contains any errors and/or exceptions (exceptions return json early),
3083
-     *  'success' => FALSE, //(default FALSE) - contains any special success message.
3084
-     *  'notices' => '', // - contains any EE_Error formatted notices
3085
-     *  'content' => 'string can be html', //this is a string of formatted content (can be html)
3086
-     *  'data' => array() //this can be any key/value pairs that a method returns for later json parsing by the js.
3087
-     *  We're also going to include the template args with every package (so js can pick out any specific template args
3088
-     *  that might be included in here)
3089
-     * )
3090
-     * The json object is populated by whatever is set in the $_template_args property.
3091
-     *
3092
-     * @param bool  $sticky_notices    Used to indicate whether you want to ensure notices are added to a transient
3093
-     *                                 instead of displayed.
3094
-     * @param array $notices_arguments Use this to pass any additional args on to the _process_notices.
3095
-     * @return void
3096
-     * @throws EE_Error
3097
-     * @throws InvalidArgumentException
3098
-     * @throws InvalidDataTypeException
3099
-     * @throws InvalidInterfaceException
3100
-     */
3101
-    protected function _return_json(bool $sticky_notices = false, array $notices_arguments = [])
3102
-    {
3103
-        // make sure any EE_Error notices have been handled.
3104
-        $this->_process_notices($notices_arguments, true, $sticky_notices);
3105
-        $data = $this->_template_args['data'] ?? [];
3106
-        unset($this->_template_args['data']);
3107
-        $json = [
3108
-            'error'     => $this->_template_args['error'] ?? false,
3109
-            'success'   => $this->_template_args['success'] ?? false,
3110
-            'errors'    => $this->_template_args['errors'] ?? false,
3111
-            'attention' => $this->_template_args['attention'] ?? false,
3112
-            'notices'   => EE_Error::get_notices(),
3113
-            'content'   => $this->_template_args['admin_page_content'] ?? '',
3114
-            'data'      => array_merge($data, ['template_args' => $this->_template_args]),
3115
-            'isEEajax'  => true,
3116
-            // special flag so any ajax.Success methods in js can identify this return package as a EEajax package.
3117
-        ];
3118
-        // make sure there are no php errors or headers_sent.  Then we can set correct json header.
3119
-        if (null === error_get_last() || ! headers_sent()) {
3120
-            header('Content-Type: application/json; charset=UTF-8');
3121
-        }
3122
-        echo wp_json_encode($json);
3123
-        exit();
3124
-    }
3125
-
3126
-
3127
-    /**
3128
-     * Simply a wrapper for the protected method so we can call this outside the class (ONLY when doing ajax)
3129
-     *
3130
-     * @return void
3131
-     * @throws EE_Error
3132
-     * @throws InvalidArgumentException
3133
-     * @throws InvalidDataTypeException
3134
-     * @throws InvalidInterfaceException
3135
-     */
3136
-    public function return_json()
3137
-    {
3138
-        if ($this->request->isAjax()) {
3139
-            $this->_return_json();
3140
-        } else {
3141
-            throw new EE_Error(
3142
-                sprintf(
3143
-                    esc_html__('The public %s method can only be called when DOING_AJAX = TRUE', 'event_espresso'),
3144
-                    __FUNCTION__
3145
-                )
3146
-            );
3147
-        }
3148
-    }
3149
-
3150
-
3151
-    /**
3152
-     * This provides a way for child hook classes to send along themselves by reference so methods/properties within
3153
-     * them can be accessed by EE_Admin_child pages. This is assigned to the $_hook_obj property.
3154
-     *
3155
-     * @param EE_Admin_Hooks $hook_obj This will be the object for the EE_Admin_Hooks child
3156
-     * @deprecated  5.0.8.p
3157
-     */
3158
-    public function set_hook_object(EE_Admin_Hooks $hook_obj)
3159
-    {
3160
-        $this->_hook_obj = $hook_obj;
3161
-    }
3162
-
3163
-
3164
-    /**
3165
-     *        generates  HTML wrapper with Tabbed nav for an admin page
3166
-     *
3167
-     * @param bool $about whether to use the special about page wrapper or default.
3168
-     * @return void
3169
-     * @throws DomainException
3170
-     * @throws EE_Error
3171
-     * @throws InvalidArgumentException
3172
-     * @throws InvalidDataTypeException
3173
-     * @throws InvalidInterfaceException
3174
-     */
3175
-    public function admin_page_wrapper(bool $about = false)
3176
-    {
3177
-        $this->_template_args['nav_tabs']         = $this->_get_main_nav_tabs();
3178
-        $this->_template_args['admin_page_title'] = $this->_admin_page_title;
3179
-
3180
-        $this->_template_args['before_admin_page_content'] = apply_filters(
3181
-            "FHEE_before_admin_page_content$this->_current_page$this->_current_view",
3182
-            $this->_template_args['before_admin_page_content'] ?? ''
3183
-        );
3184
-
3185
-        $this->_template_args['after_admin_page_content'] = apply_filters(
3186
-            "FHEE_after_admin_page_content$this->_current_page$this->_current_view",
3187
-            $this->_template_args['after_admin_page_content'] ?? ''
3188
-        );
3189
-        $this->_template_args['after_admin_page_content'] .= $this->_set_help_popup_content();
3190
-
3191
-        if ($this->request->isAjax()) {
3192
-            $this->_template_args['admin_page_content'] = EEH_Template::display_template(
3193
-            // $template_path,
3194
-                EE_ADMIN_TEMPLATE . 'admin_wrapper_ajax.template.php',
3195
-                $this->_template_args,
3196
-                true
3197
-            );
3198
-            $this->_return_json();
3199
-        }
3200
-        // load settings page wrapper template
3201
-        $template_path = $about
3202
-            ? EE_ADMIN_TEMPLATE . 'about_admin_wrapper.template.php'
3203
-            : EE_ADMIN_TEMPLATE . 'admin_wrapper.template.php';
3204
-
3205
-        EEH_Template::display_template($template_path, $this->_template_args);
3206
-    }
3207
-
3208
-
3209
-    /**
3210
-     * This returns the admin_nav tabs html using the configuration in the _nav_tabs property
3211
-     *
3212
-     * @return string html
3213
-     * @throws EE_Error
3214
-     */
3215
-    protected function _get_main_nav_tabs(): string
3216
-    {
3217
-        // let's generate the html using the EEH_Tabbed_Content helper.
3218
-        // We do this here so that it's possible for child classes to add in nav tabs dynamically at the last minute
3219
-        // (rather than setting in the page_routes array)
3220
-        return EEH_Tabbed_Content::display_admin_nav_tabs($this->_nav_tabs, $this->page_slug);
3221
-    }
3222
-
3223
-
3224
-    /**
3225
-     *        sort nav tabs
3226
-     *
3227
-     * @param array $a
3228
-     * @param array $b
3229
-     * @return int
3230
-     */
3231
-    private function _sort_nav_tabs(array $a, array $b): int
3232
-    {
3233
-        if ($a['order'] === $b['order']) {
3234
-            return 0;
3235
-        }
3236
-        return ($a['order'] < $b['order']) ? -1 : 1;
3237
-    }
3238
-
3239
-
3240
-    /**
3241
-     * generates HTML for the forms used on admin pages
3242
-     *
3243
-     * @param array  $input_vars - array of input field details
3244
-     * @param string $generator  indicates which generator to use: options are 'string' or 'array'
3245
-     * @param string $id
3246
-     * @return array|string
3247
-     * @uses   EEH_Form_Fields::get_form_fields (/helper/EEH_Form_Fields.helper.php)
3248
-     * @uses   EEH_Form_Fields::get_form_fields_array (/helper/EEH_Form_Fields.helper.php)
3249
-     */
3250
-    protected function _generate_admin_form_fields(
3251
-        array $input_vars = [],
3252
-        string $generator = 'string',
3253
-        string $id = ''
3254
-    ) {
3255
-        return $generator === 'string'
3256
-            ? EEH_Form_Fields::get_form_fields($input_vars, $id)
3257
-            : EEH_Form_Fields::get_form_fields_array($input_vars);
3258
-    }
3259
-
3260
-
3261
-    /**
3262
-     * generates the "Save" and "Save & Close" buttons for edit forms
3263
-     *
3264
-     * @param bool             $both     if true then both buttons will be generated.  If false then just the "Save &
3265
-     *                                   Close" button.
3266
-     * @param array            $text     if included, generator will use the given text for the buttons ( array([0] =>
3267
-     *                                   'Save', [1] => 'save & close')
3268
-     * @param array            $actions  if included allows us to set the actions that each button will carry out (i.e.
3269
-     *                                   via the "name" value in the button).  We can also use this to just dump
3270
-     *                                   default actions by submitting some other value.
3271
-     * @param bool|string|null $referrer if false then we just do the default action on save and close.  Otherwise it
3272
-     *                                   will use the $referrer string. IF null, then we don't do ANYTHING on save and
3273
-     *                                   close (normal form handling).
3274
-     */
3275
-    protected function _set_save_buttons(bool $both = true, array $text = [], array $actions = [], $referrer = null)
3276
-    {
3277
-        $referrer_url  = ! empty($referrer) ? $referrer : $this->request->getServerParam('REQUEST_URI');
3278
-        $button_text   = ! empty($text)
3279
-            ? $text
3280
-            : [
3281
-                esc_html__('Save', 'event_espresso'),
3282
-                esc_html__('Save and Close', 'event_espresso'),
3283
-            ];
3284
-        $default_names = ['save', 'save_and_close'];
3285
-        $buttons       = '';
3286
-        foreach ($button_text as $key => $button) {
3287
-            $ref     = $default_names[ $key ];
3288
-            $name    = ! empty($actions) ? $actions[ $key ] : $ref;
3289
-            $buttons .= '<input type="submit" class="button button--primary ' . $ref . '" '
3290
-                        . 'value="' . $button . '" name="' . $name . '" '
3291
-                        . 'id="' . $this->_current_view . '_' . $ref . '" />';
3292
-            if (! $both) {
3293
-                break;
3294
-            }
3295
-        }
3296
-        // add in a hidden index for the current page (so save and close redirects properly)
3297
-        $buttons .= '<input type="hidden" id="save_and_close_referrer" name="save_and_close_referrer" value="'
3298
-                    . $referrer_url
3299
-                    . '" />';
3300
-
3301
-        $this->_template_args['save_buttons'] = $buttons;
3302
-    }
3303
-
3304
-
3305
-    /**
3306
-     * Wrapper for the protected function.  Allows plugins/addons to call this to set the form tags.
3307
-     *
3308
-     * @param string $route
3309
-     * @param array  $additional_hidden_fields
3310
-     * @see   $this->_set_add_edit_form_tags() for details on params
3311
-     * @since 4.6.0
3312
-     */
3313
-    public function set_add_edit_form_tags(string $route = '', array $additional_hidden_fields = [])
3314
-    {
3315
-        $this->_set_add_edit_form_tags($route, $additional_hidden_fields);
3316
-    }
3317
-
3318
-
3319
-    /**
3320
-     * set form open and close tags on add/edit pages.
3321
-     *
3322
-     * @param string $route                    the route you want the form to direct to
3323
-     * @param array  $additional_hidden_fields any additional hidden fields required in the form header
3324
-     * @return void
3325
-     */
3326
-    protected function _set_add_edit_form_tags(string $route = '', array $additional_hidden_fields = [])
3327
-    {
3328
-        if (empty($route)) {
3329
-            $user_msg = esc_html__(
3330
-                'An error occurred. No action was set for this page\'s form.',
3331
-                'event_espresso'
3332
-            );
3333
-            $dev_msg  = $user_msg . "\n"
3334
-                        . sprintf(
3335
-                            esc_html__('The $route argument is required for the %s->%s method.', 'event_espresso'),
3336
-                            __FUNCTION__,
3337
-                            __CLASS__
3338
-                        );
3339
-            EE_Error::add_error($user_msg . '||' . $dev_msg, __FILE__, __FUNCTION__, __LINE__);
3340
-        }
3341
-        // open form
3342
-        $action                                            = $this->_admin_base_url;
3343
-        $this->_template_args['before_admin_page_content'] = "
2975
+		$this->_template_args['list_table_hidden_fields'] = $hidden_form_fields;
2976
+		// display message about search results?
2977
+		$search                                    = $this->request->getRequestParam('s');
2978
+		$this->_template_args['before_list_table'] .= ! empty($search)
2979
+			? '<p class="ee-search-results">' . sprintf(
2980
+				esc_html__('Displaying search results for the search string: %1$s', 'event_espresso'),
2981
+				trim($search, '%')
2982
+			) . '</p>'
2983
+			: '';
2984
+		// filter before_list_table template arg
2985
+		$this->_template_args['before_list_table'] = apply_filters(
2986
+			'FHEE__EE_Admin_Page___display_admin_list_table_page__before_list_table__template_arg',
2987
+			$this->_template_args['before_list_table'],
2988
+			$this->page_slug,
2989
+			$this->request->requestParams(),
2990
+			$this->_req_action
2991
+		);
2992
+		// convert to array and filter again
2993
+		// arrays are easier to inject new items in a specific location,
2994
+		// but would not be backwards compatible, so we have to add a new filter
2995
+		$this->_template_args['before_list_table'] = implode(
2996
+			" \n",
2997
+			(array) apply_filters(
2998
+				'FHEE__EE_Admin_Page___display_admin_list_table_page__before_list_table__template_args_array',
2999
+				(array) $this->_template_args['before_list_table'],
3000
+				$this->page_slug,
3001
+				$this->request->requestParams(),
3002
+				$this->_req_action
3003
+			)
3004
+		);
3005
+		// filter after_list_table template arg
3006
+		$this->_template_args['after_list_table'] = apply_filters(
3007
+			'FHEE__EE_Admin_Page___display_admin_list_table_page__after_list_table__template_arg',
3008
+			$this->_template_args['after_list_table'],
3009
+			$this->page_slug,
3010
+			$this->request->requestParams(),
3011
+			$this->_req_action
3012
+		);
3013
+		// convert to array and filter again
3014
+		// arrays are easier to inject new items in a specific location,
3015
+		// but would not be backwards compatible, so we have to add a new filter
3016
+		$this->_template_args['after_list_table']   = implode(
3017
+			" \n",
3018
+			(array) apply_filters(
3019
+				'FHEE__EE_Admin_Page___display_admin_list_table_page__after_list_table__template_args_array',
3020
+				(array) $this->_template_args['after_list_table'],
3021
+				$this->page_slug,
3022
+				$this->request->requestParams(),
3023
+				$this->_req_action
3024
+			)
3025
+		);
3026
+		$this->_template_args['admin_page_content'] = EEH_Template::display_template(
3027
+			$template_path,
3028
+			$this->_template_args,
3029
+			true
3030
+		);
3031
+		// the final template wrapper
3032
+		if ($sidebar) {
3033
+			$this->display_admin_page_with_sidebar();
3034
+		} else {
3035
+			$this->display_admin_page_with_no_sidebar();
3036
+		}
3037
+	}
3038
+
3039
+
3040
+	/**
3041
+	 * This just prepares a legend using the given items and the admin_details_legend.template.php file and returns the
3042
+	 * html string for the legend.
3043
+	 * $items are expected in an array in the following format:
3044
+	 * $legend_items = array(
3045
+	 *        'item_id' => array(
3046
+	 *            'icon' => 'http://url_to_icon_being_described.png',
3047
+	 *            'desc' => esc_html__('localized description of item');
3048
+	 *        )
3049
+	 * );
3050
+	 *
3051
+	 * @param array $items see above for format of array
3052
+	 * @return string html string of legend
3053
+	 * @throws DomainException
3054
+	 */
3055
+	protected function _display_legend(array $items): string
3056
+	{
3057
+		$this->_template_args['items'] = (array) apply_filters(
3058
+			'FHEE__EE_Admin_Page___display_legend__items',
3059
+			$items,
3060
+			$this
3061
+		);
3062
+		/** @var StatusChangeNotice $status_change_notice */
3063
+		$status_change_notice                         = $this->loader->getShared(
3064
+			'EventEspresso\core\domain\services\admin\notices\status_change\StatusChangeNotice'
3065
+		);
3066
+		$this->_template_args['status_change_notice'] = $status_change_notice->display(
3067
+			'__admin-legend',
3068
+			$this->page_slug
3069
+		);
3070
+		return EEH_Template::display_template(
3071
+			EE_ADMIN_TEMPLATE . 'admin_details_legend.template.php',
3072
+			$this->_template_args,
3073
+			true
3074
+		);
3075
+	}
3076
+
3077
+
3078
+	/**
3079
+	 * This is used whenever we're DOING_AJAX to return a formatted json array that our calling javascript can expect
3080
+	 * The returned json object is created from an array in the following format:
3081
+	 * array(
3082
+	 *  'error' => FALSE, //(default FALSE), contains any errors and/or exceptions (exceptions return json early),
3083
+	 *  'success' => FALSE, //(default FALSE) - contains any special success message.
3084
+	 *  'notices' => '', // - contains any EE_Error formatted notices
3085
+	 *  'content' => 'string can be html', //this is a string of formatted content (can be html)
3086
+	 *  'data' => array() //this can be any key/value pairs that a method returns for later json parsing by the js.
3087
+	 *  We're also going to include the template args with every package (so js can pick out any specific template args
3088
+	 *  that might be included in here)
3089
+	 * )
3090
+	 * The json object is populated by whatever is set in the $_template_args property.
3091
+	 *
3092
+	 * @param bool  $sticky_notices    Used to indicate whether you want to ensure notices are added to a transient
3093
+	 *                                 instead of displayed.
3094
+	 * @param array $notices_arguments Use this to pass any additional args on to the _process_notices.
3095
+	 * @return void
3096
+	 * @throws EE_Error
3097
+	 * @throws InvalidArgumentException
3098
+	 * @throws InvalidDataTypeException
3099
+	 * @throws InvalidInterfaceException
3100
+	 */
3101
+	protected function _return_json(bool $sticky_notices = false, array $notices_arguments = [])
3102
+	{
3103
+		// make sure any EE_Error notices have been handled.
3104
+		$this->_process_notices($notices_arguments, true, $sticky_notices);
3105
+		$data = $this->_template_args['data'] ?? [];
3106
+		unset($this->_template_args['data']);
3107
+		$json = [
3108
+			'error'     => $this->_template_args['error'] ?? false,
3109
+			'success'   => $this->_template_args['success'] ?? false,
3110
+			'errors'    => $this->_template_args['errors'] ?? false,
3111
+			'attention' => $this->_template_args['attention'] ?? false,
3112
+			'notices'   => EE_Error::get_notices(),
3113
+			'content'   => $this->_template_args['admin_page_content'] ?? '',
3114
+			'data'      => array_merge($data, ['template_args' => $this->_template_args]),
3115
+			'isEEajax'  => true,
3116
+			// special flag so any ajax.Success methods in js can identify this return package as a EEajax package.
3117
+		];
3118
+		// make sure there are no php errors or headers_sent.  Then we can set correct json header.
3119
+		if (null === error_get_last() || ! headers_sent()) {
3120
+			header('Content-Type: application/json; charset=UTF-8');
3121
+		}
3122
+		echo wp_json_encode($json);
3123
+		exit();
3124
+	}
3125
+
3126
+
3127
+	/**
3128
+	 * Simply a wrapper for the protected method so we can call this outside the class (ONLY when doing ajax)
3129
+	 *
3130
+	 * @return void
3131
+	 * @throws EE_Error
3132
+	 * @throws InvalidArgumentException
3133
+	 * @throws InvalidDataTypeException
3134
+	 * @throws InvalidInterfaceException
3135
+	 */
3136
+	public function return_json()
3137
+	{
3138
+		if ($this->request->isAjax()) {
3139
+			$this->_return_json();
3140
+		} else {
3141
+			throw new EE_Error(
3142
+				sprintf(
3143
+					esc_html__('The public %s method can only be called when DOING_AJAX = TRUE', 'event_espresso'),
3144
+					__FUNCTION__
3145
+				)
3146
+			);
3147
+		}
3148
+	}
3149
+
3150
+
3151
+	/**
3152
+	 * This provides a way for child hook classes to send along themselves by reference so methods/properties within
3153
+	 * them can be accessed by EE_Admin_child pages. This is assigned to the $_hook_obj property.
3154
+	 *
3155
+	 * @param EE_Admin_Hooks $hook_obj This will be the object for the EE_Admin_Hooks child
3156
+	 * @deprecated  5.0.8.p
3157
+	 */
3158
+	public function set_hook_object(EE_Admin_Hooks $hook_obj)
3159
+	{
3160
+		$this->_hook_obj = $hook_obj;
3161
+	}
3162
+
3163
+
3164
+	/**
3165
+	 *        generates  HTML wrapper with Tabbed nav for an admin page
3166
+	 *
3167
+	 * @param bool $about whether to use the special about page wrapper or default.
3168
+	 * @return void
3169
+	 * @throws DomainException
3170
+	 * @throws EE_Error
3171
+	 * @throws InvalidArgumentException
3172
+	 * @throws InvalidDataTypeException
3173
+	 * @throws InvalidInterfaceException
3174
+	 */
3175
+	public function admin_page_wrapper(bool $about = false)
3176
+	{
3177
+		$this->_template_args['nav_tabs']         = $this->_get_main_nav_tabs();
3178
+		$this->_template_args['admin_page_title'] = $this->_admin_page_title;
3179
+
3180
+		$this->_template_args['before_admin_page_content'] = apply_filters(
3181
+			"FHEE_before_admin_page_content$this->_current_page$this->_current_view",
3182
+			$this->_template_args['before_admin_page_content'] ?? ''
3183
+		);
3184
+
3185
+		$this->_template_args['after_admin_page_content'] = apply_filters(
3186
+			"FHEE_after_admin_page_content$this->_current_page$this->_current_view",
3187
+			$this->_template_args['after_admin_page_content'] ?? ''
3188
+		);
3189
+		$this->_template_args['after_admin_page_content'] .= $this->_set_help_popup_content();
3190
+
3191
+		if ($this->request->isAjax()) {
3192
+			$this->_template_args['admin_page_content'] = EEH_Template::display_template(
3193
+			// $template_path,
3194
+				EE_ADMIN_TEMPLATE . 'admin_wrapper_ajax.template.php',
3195
+				$this->_template_args,
3196
+				true
3197
+			);
3198
+			$this->_return_json();
3199
+		}
3200
+		// load settings page wrapper template
3201
+		$template_path = $about
3202
+			? EE_ADMIN_TEMPLATE . 'about_admin_wrapper.template.php'
3203
+			: EE_ADMIN_TEMPLATE . 'admin_wrapper.template.php';
3204
+
3205
+		EEH_Template::display_template($template_path, $this->_template_args);
3206
+	}
3207
+
3208
+
3209
+	/**
3210
+	 * This returns the admin_nav tabs html using the configuration in the _nav_tabs property
3211
+	 *
3212
+	 * @return string html
3213
+	 * @throws EE_Error
3214
+	 */
3215
+	protected function _get_main_nav_tabs(): string
3216
+	{
3217
+		// let's generate the html using the EEH_Tabbed_Content helper.
3218
+		// We do this here so that it's possible for child classes to add in nav tabs dynamically at the last minute
3219
+		// (rather than setting in the page_routes array)
3220
+		return EEH_Tabbed_Content::display_admin_nav_tabs($this->_nav_tabs, $this->page_slug);
3221
+	}
3222
+
3223
+
3224
+	/**
3225
+	 *        sort nav tabs
3226
+	 *
3227
+	 * @param array $a
3228
+	 * @param array $b
3229
+	 * @return int
3230
+	 */
3231
+	private function _sort_nav_tabs(array $a, array $b): int
3232
+	{
3233
+		if ($a['order'] === $b['order']) {
3234
+			return 0;
3235
+		}
3236
+		return ($a['order'] < $b['order']) ? -1 : 1;
3237
+	}
3238
+
3239
+
3240
+	/**
3241
+	 * generates HTML for the forms used on admin pages
3242
+	 *
3243
+	 * @param array  $input_vars - array of input field details
3244
+	 * @param string $generator  indicates which generator to use: options are 'string' or 'array'
3245
+	 * @param string $id
3246
+	 * @return array|string
3247
+	 * @uses   EEH_Form_Fields::get_form_fields (/helper/EEH_Form_Fields.helper.php)
3248
+	 * @uses   EEH_Form_Fields::get_form_fields_array (/helper/EEH_Form_Fields.helper.php)
3249
+	 */
3250
+	protected function _generate_admin_form_fields(
3251
+		array $input_vars = [],
3252
+		string $generator = 'string',
3253
+		string $id = ''
3254
+	) {
3255
+		return $generator === 'string'
3256
+			? EEH_Form_Fields::get_form_fields($input_vars, $id)
3257
+			: EEH_Form_Fields::get_form_fields_array($input_vars);
3258
+	}
3259
+
3260
+
3261
+	/**
3262
+	 * generates the "Save" and "Save & Close" buttons for edit forms
3263
+	 *
3264
+	 * @param bool             $both     if true then both buttons will be generated.  If false then just the "Save &
3265
+	 *                                   Close" button.
3266
+	 * @param array            $text     if included, generator will use the given text for the buttons ( array([0] =>
3267
+	 *                                   'Save', [1] => 'save & close')
3268
+	 * @param array            $actions  if included allows us to set the actions that each button will carry out (i.e.
3269
+	 *                                   via the "name" value in the button).  We can also use this to just dump
3270
+	 *                                   default actions by submitting some other value.
3271
+	 * @param bool|string|null $referrer if false then we just do the default action on save and close.  Otherwise it
3272
+	 *                                   will use the $referrer string. IF null, then we don't do ANYTHING on save and
3273
+	 *                                   close (normal form handling).
3274
+	 */
3275
+	protected function _set_save_buttons(bool $both = true, array $text = [], array $actions = [], $referrer = null)
3276
+	{
3277
+		$referrer_url  = ! empty($referrer) ? $referrer : $this->request->getServerParam('REQUEST_URI');
3278
+		$button_text   = ! empty($text)
3279
+			? $text
3280
+			: [
3281
+				esc_html__('Save', 'event_espresso'),
3282
+				esc_html__('Save and Close', 'event_espresso'),
3283
+			];
3284
+		$default_names = ['save', 'save_and_close'];
3285
+		$buttons       = '';
3286
+		foreach ($button_text as $key => $button) {
3287
+			$ref     = $default_names[ $key ];
3288
+			$name    = ! empty($actions) ? $actions[ $key ] : $ref;
3289
+			$buttons .= '<input type="submit" class="button button--primary ' . $ref . '" '
3290
+						. 'value="' . $button . '" name="' . $name . '" '
3291
+						. 'id="' . $this->_current_view . '_' . $ref . '" />';
3292
+			if (! $both) {
3293
+				break;
3294
+			}
3295
+		}
3296
+		// add in a hidden index for the current page (so save and close redirects properly)
3297
+		$buttons .= '<input type="hidden" id="save_and_close_referrer" name="save_and_close_referrer" value="'
3298
+					. $referrer_url
3299
+					. '" />';
3300
+
3301
+		$this->_template_args['save_buttons'] = $buttons;
3302
+	}
3303
+
3304
+
3305
+	/**
3306
+	 * Wrapper for the protected function.  Allows plugins/addons to call this to set the form tags.
3307
+	 *
3308
+	 * @param string $route
3309
+	 * @param array  $additional_hidden_fields
3310
+	 * @see   $this->_set_add_edit_form_tags() for details on params
3311
+	 * @since 4.6.0
3312
+	 */
3313
+	public function set_add_edit_form_tags(string $route = '', array $additional_hidden_fields = [])
3314
+	{
3315
+		$this->_set_add_edit_form_tags($route, $additional_hidden_fields);
3316
+	}
3317
+
3318
+
3319
+	/**
3320
+	 * set form open and close tags on add/edit pages.
3321
+	 *
3322
+	 * @param string $route                    the route you want the form to direct to
3323
+	 * @param array  $additional_hidden_fields any additional hidden fields required in the form header
3324
+	 * @return void
3325
+	 */
3326
+	protected function _set_add_edit_form_tags(string $route = '', array $additional_hidden_fields = [])
3327
+	{
3328
+		if (empty($route)) {
3329
+			$user_msg = esc_html__(
3330
+				'An error occurred. No action was set for this page\'s form.',
3331
+				'event_espresso'
3332
+			);
3333
+			$dev_msg  = $user_msg . "\n"
3334
+						. sprintf(
3335
+							esc_html__('The $route argument is required for the %s->%s method.', 'event_espresso'),
3336
+							__FUNCTION__,
3337
+							__CLASS__
3338
+						);
3339
+			EE_Error::add_error($user_msg . '||' . $dev_msg, __FILE__, __FUNCTION__, __LINE__);
3340
+		}
3341
+		// open form
3342
+		$action                                            = $this->_admin_base_url;
3343
+		$this->_template_args['before_admin_page_content'] = "
3344 3344
             <form name='form' method='post' action='$action' id='{$route}_event_form' class='ee-admin-page-form' >
3345 3345
             ";
3346
-        // add nonce
3347
-        $nonce                                             =
3348
-            wp_nonce_field($route . '_nonce', $route . '_nonce', false, false);
3349
-        $this->_template_args['before_admin_page_content'] .= "\n\t" . $nonce;
3350
-        // add REQUIRED form action
3351
-        $hidden_fields = [
3352
-            'action' => ['type' => 'hidden', 'value' => $route],
3353
-        ];
3354
-        // merge arrays
3355
-        $hidden_fields = is_array($additional_hidden_fields)
3356
-            ? array_merge($hidden_fields, $additional_hidden_fields)
3357
-            : $hidden_fields;
3358
-        // generate form fields
3359
-        $form_fields = $this->_generate_admin_form_fields($hidden_fields, 'array');
3360
-        // add fields to form
3361
-        foreach ((array) $form_fields as $form_field) {
3362
-            $this->_template_args['before_admin_page_content'] .= "\n\t" . $form_field['field'];
3363
-        }
3364
-        // close form
3365
-        $this->_template_args['after_admin_page_content'] = '</form>';
3366
-    }
3367
-
3368
-
3369
-    /**
3370
-     * Public Wrapper for _redirect_after_action() method since its
3371
-     * discovered it would be useful for external code to have access.
3372
-     *
3373
-     * @param bool|int $success
3374
-     * @param string   $what
3375
-     * @param string   $action_desc
3376
-     * @param array    $query_args
3377
-     * @param bool     $override_overwrite
3378
-     * @throws EE_Error
3379
-     * @see   EE_Admin_Page::_redirect_after_action() for params.
3380
-     * @since 4.5.0
3381
-     */
3382
-    public function redirect_after_action(
3383
-        $success = false,
3384
-        string $what = 'item',
3385
-        string $action_desc = 'processed',
3386
-        array $query_args = [],
3387
-        bool $override_overwrite = false
3388
-    ) {
3389
-        $this->_redirect_after_action(
3390
-            $success,
3391
-            $what,
3392
-            $action_desc,
3393
-            $query_args,
3394
-            $override_overwrite
3395
-        );
3396
-    }
3397
-
3398
-
3399
-    /**
3400
-     * Helper method for merging existing request data with the returned redirect url.
3401
-     * This is typically used for redirects after an action so that if the original view was a filtered view those
3402
-     * filters are still applied.
3403
-     *
3404
-     * @param array $new_route_data
3405
-     * @return array
3406
-     */
3407
-    protected function mergeExistingRequestParamsWithRedirectArgs(array $new_route_data): array
3408
-    {
3409
-        foreach ($this->request->requestParams() as $ref => $value) {
3410
-            // unset nonces
3411
-            if (strpos($ref, 'nonce') !== false) {
3412
-                $this->request->unSetRequestParam($ref);
3413
-                continue;
3414
-            }
3415
-            // urlencode values.
3416
-            $value = is_array($value) ? array_map('urlencode', $value) : urlencode($value);
3417
-            $this->request->setRequestParam($ref, $value);
3418
-        }
3419
-        return array_merge($this->request->requestParams(), $new_route_data);
3420
-    }
3421
-
3422
-
3423
-    /**
3424
-     * @param int|float|string $success            - whether success was for two or more records, or just one, or none
3425
-     * @param string           $what               - what the action was performed on
3426
-     * @param string           $action_desc        - what was done ie: updated, deleted, etc
3427
-     * @param array            $query_args         - an array of query_args to be added to the URL to redirect to
3428
-     * @param BOOL             $override_overwrite - by default all EE_Error::success messages are overwritten,
3429
-     *                                             this allows you to override this so that they show.
3430
-     * @return void
3431
-     * @throws EE_Error
3432
-     * @throws InvalidArgumentException
3433
-     * @throws InvalidDataTypeException
3434
-     * @throws InvalidInterfaceException
3435
-     */
3436
-    protected function _redirect_after_action(
3437
-        $success = 0,
3438
-        string $what = 'item',
3439
-        string $action_desc = 'processed',
3440
-        array $query_args = [],
3441
-        bool $override_overwrite = false
3442
-    ) {
3443
-        $notices = EE_Error::get_notices(false);
3444
-        // overwrite default success messages //BUT ONLY if overwrite not overridden
3445
-        if (! $override_overwrite || ! empty($notices['errors'])) {
3446
-            EE_Error::overwrite_success();
3447
-        }
3448
-        if (! $override_overwrite && ! empty($what) && ! empty($action_desc) && empty($notices['errors'])) {
3449
-            // how many records affected ? more than one record ? or just one ?
3450
-            EE_Error::add_success(
3451
-                sprintf(
3452
-                    esc_html(
3453
-                        _n(
3454
-                            'The "%1$s" has been successfully %2$s.',
3455
-                            'The "%1$s" have been successfully %2$s.',
3456
-                            $success,
3457
-                            'event_espresso'
3458
-                        )
3459
-                    ),
3460
-                    $what,
3461
-                    $action_desc
3462
-                ),
3463
-                __FILE__,
3464
-                __FUNCTION__,
3465
-                __LINE__
3466
-            );
3467
-        }
3468
-        // check that $query_args isn't something crazy
3469
-        $query_args = is_array($query_args) ? $query_args : [];
3470
-        /**
3471
-         * Allow injecting actions before the query_args are modified for possible different
3472
-         * redirections on save and close actions
3473
-         *
3474
-         * @param array $query_args       The original query_args array coming into the
3475
-         *                                method.
3476
-         * @since 4.2.0
3477
-         */
3478
-        do_action(
3479
-            "AHEE__{$this->class_name}___redirect_after_action__before_redirect_modification_$this->_req_action",
3480
-            $query_args
3481
-        );
3482
-        // set redirect url.
3483
-        // Note if there is a "page" index in the $query_args then we go with vanilla admin.php route,
3484
-        // otherwise we go with whatever is set as the _admin_base_url
3485
-        $redirect_url = isset($query_args['page']) ? admin_url('admin.php') : $this->_admin_base_url;
3486
-        // calculate where we're going (if we have a "save and close" button pushed)
3487
-        if (
3488
-            $this->request->requestParamIsSet('save_and_close')
3489
-            && $this->request->requestParamIsSet('save_and_close_referrer')
3490
-        ) {
3491
-            // even though we have the save_and_close referrer, we need to parse the url for the action in order to generate a nonce
3492
-            $parsed_url = parse_url($this->request->getRequestParam('save_and_close_referrer', '', DataType::URL));
3493
-            // regenerate query args array from referrer URL
3494
-            parse_str($parsed_url['query'], $query_args);
3495
-            // correct page and action will be in the query args now
3496
-            $redirect_url = admin_url('admin.php');
3497
-        }
3498
-        // merge any default query_args set in _default_route_query_args property
3499
-        if (! empty($this->_default_route_query_args) && ! $this->_is_UI_request) {
3500
-            $args_to_merge = [];
3501
-            foreach ($this->_default_route_query_args as $query_param => $query_value) {
3502
-                // is there a wp_referer array in our _default_route_query_args property?
3503
-                if ($query_param === 'wp_referer') {
3504
-                    $query_value = (array) $query_value;
3505
-                    foreach ($query_value as $reference => $value) {
3506
-                        if (strpos($reference, 'nonce') !== false) {
3507
-                            continue;
3508
-                        }
3509
-                        // finally we will override any arguments in the referer with
3510
-                        // what might be set on the _default_route_query_args array.
3511
-                        if (isset($this->_default_route_query_args[ $reference ])) {
3512
-                            $args_to_merge[ $reference ] = urlencode($this->_default_route_query_args[ $reference ]);
3513
-                        } else {
3514
-                            $args_to_merge[ $reference ] = urlencode($value);
3515
-                        }
3516
-                    }
3517
-                    continue;
3518
-                }
3519
-                $args_to_merge[ $query_param ] = $query_value;
3520
-            }
3521
-            // now let's merge these arguments but override with what was specifically sent in to the
3522
-            // redirect.
3523
-            $query_args = array_merge($args_to_merge, $query_args);
3524
-        }
3525
-        $this->_process_notices($query_args);
3526
-        // generate redirect url
3527
-        // if redirecting to anything other than the main page, add a nonce
3528
-        if (isset($query_args['action'])) {
3529
-            // manually generate wp_nonce and merge that with the query vars
3530
-            // becuz the wp_nonce_url function wrecks havoc on some vars
3531
-            $query_args['_wpnonce'] = wp_create_nonce($query_args['action'] . '_nonce');
3532
-        }
3533
-        // we're adding some hooks and filters in here for processing any things just before redirects
3534
-        // (example: an admin page has done an insert or update and we want to run something after that).
3535
-        do_action('AHEE_redirect_' . $this->class_name . $this->_req_action, $query_args);
3536
-        $redirect_url = apply_filters(
3537
-            'FHEE_redirect_' . $this->class_name . $this->_req_action,
3538
-            EE_Admin_Page::add_query_args_and_nonce($query_args, $redirect_url),
3539
-            $query_args
3540
-        );
3541
-        // check if we're doing ajax.  If we are then lets just return the results and js can handle how it wants.
3542
-        if ($this->request->isAjax()) {
3543
-            $default_data                    = [
3544
-                'close'        => true,
3545
-                'redirect_url' => $redirect_url,
3546
-                'where'        => 'main',
3547
-                'what'         => 'append',
3548
-            ];
3549
-            $this->_template_args['success'] = $success;
3550
-            $this->_template_args['data']    = ! empty($this->_template_args['data']) ? array_merge(
3551
-                $default_data,
3552
-                $this->_template_args['data']
3553
-            ) : $default_data;
3554
-            $this->_return_json();
3555
-        }
3556
-        wp_safe_redirect($redirect_url);
3557
-        exit();
3558
-    }
3559
-
3560
-
3561
-    /**
3562
-     * process any notices before redirecting (or returning ajax request)
3563
-     * This method sets the $this->_template_args['notices'] attribute;
3564
-     *
3565
-     * @param array $query_args         any query args that need to be used for notice transient ('action')
3566
-     * @param bool  $skip_route_verify  This is typically used when we are processing notices REALLY early and
3567
-     *                                  page_routes haven't been defined yet.
3568
-     * @param bool  $sticky_notices     This is used to flag that regardless of whether this is doing_ajax or not, we
3569
-     *                                  still save a transient for the notice.
3570
-     * @return void
3571
-     * @throws EE_Error
3572
-     * @throws InvalidArgumentException
3573
-     * @throws InvalidDataTypeException
3574
-     * @throws InvalidInterfaceException
3575
-     */
3576
-    protected function _process_notices(
3577
-        array $query_args = [],
3578
-        bool $skip_route_verify = false,
3579
-        bool $sticky_notices = true
3580
-    ) {
3581
-        // first let's set individual error properties if doing_ajax and the properties aren't already set.
3582
-        if ($this->request->isAjax()) {
3583
-            $notices = EE_Error::get_notices(false);
3584
-            if (empty($this->_template_args['success'])) {
3585
-                $this->_template_args['success'] = $notices['success'] ?? false;
3586
-            }
3587
-            if (empty($this->_template_args['errors'])) {
3588
-                $this->_template_args['errors'] = $notices['errors'] ?? false;
3589
-            }
3590
-            if (empty($this->_template_args['attention'])) {
3591
-                $this->_template_args['attention'] = $notices['attention'] ?? false;
3592
-            }
3593
-        }
3594
-        $this->_template_args['notices'] = EE_Error::get_notices();
3595
-        // IF this isn't ajax we need to create a transient for the notices using the route (however, overridden if $sticky_notices == true)
3596
-        if (! $this->request->isAjax() || $sticky_notices) {
3597
-            $route = $query_args['action'] ?? 'default';
3598
-            $this->_add_transient(
3599
-                $route,
3600
-                (array) $this->_template_args['notices'],
3601
-                true,
3602
-                $skip_route_verify
3603
-            );
3604
-        }
3605
-    }
3606
-
3607
-
3608
-    /**
3609
-     * get_action_link_or_button
3610
-     * returns the button html for adding, editing, or deleting an item (depending on given type)
3611
-     *
3612
-     * @param string $action        use this to indicate which action the url is generated with.
3613
-     * @param string $type          accepted strings must be defined in the $_labels['button'] array(as the key)
3614
-     *                              property.
3615
-     * @param array  $extra_request if the button requires extra params you can include them in $key=>$value pairs.
3616
-     * @param string $class         Use this to give the class for the button. Defaults to 'button--primary'
3617
-     * @param string $base_url      If this is not provided
3618
-     *                              the _admin_base_url will be used as the default for the button base_url.
3619
-     *                              Otherwise this value will be used.
3620
-     * @param bool   $exclude_nonce If true then no nonce will be in the generated button link.
3621
-     * @return string
3622
-     * @throws InvalidArgumentException
3623
-     * @throws InvalidInterfaceException
3624
-     * @throws InvalidDataTypeException
3625
-     * @throws EE_Error
3626
-     */
3627
-    public function get_action_link_or_button(
3628
-        string $action,
3629
-        string $type = 'add',
3630
-        array $extra_request = [],
3631
-        string $class = 'button button--primary',
3632
-        string $base_url = '',
3633
-        bool $exclude_nonce = false
3634
-    ): string {
3635
-        // first let's validate the action (if $base_url is FALSE otherwise validation will happen further along)
3636
-        if (empty($base_url) && ! isset($this->_page_routes[ $action ])) {
3637
-            throw new EE_Error(
3638
-                sprintf(
3639
-                    esc_html__(
3640
-                        'There is no page route for given action for the button.  This action was given: %s',
3641
-                        'event_espresso'
3642
-                    ),
3643
-                    $action
3644
-                )
3645
-            );
3646
-        }
3647
-        if (! isset($this->_labels['buttons'][ $type ])) {
3648
-            throw new EE_Error(
3649
-                sprintf(
3650
-                    esc_html__(
3651
-                        'There is no label for the given button type (%s). Labels are set in the <code>_page_config</code> property.',
3652
-                        'event_espresso'
3653
-                    ),
3654
-                    $type
3655
-                )
3656
-            );
3657
-        }
3658
-        // finally check user access for this button.
3659
-        $has_access = $this->check_user_access($action, true);
3660
-        if (! $has_access) {
3661
-            return '';
3662
-        }
3663
-        $_base_url  = ! $base_url ? $this->_admin_base_url : $base_url;
3664
-        $query_args = [
3665
-            'action' => $action,
3666
-        ];
3667
-        // merge extra_request args but make sure our original action takes precedence and doesn't get overwritten.
3668
-        if (! empty($extra_request)) {
3669
-            $query_args = array_merge($extra_request, $query_args);
3670
-        }
3671
-        $url = EE_Admin_Page::add_query_args_and_nonce($query_args, $_base_url, false, $exclude_nonce);
3672
-        return EEH_Template::get_button_or_link($url, $this->_labels['buttons'][ $type ], $class);
3673
-    }
3674
-
3675
-
3676
-    /**
3677
-     * _per_page_screen_option
3678
-     * Utility function for adding in a per_page_option in the screen_options_dropdown.
3679
-     *
3680
-     * @return void
3681
-     * @throws InvalidArgumentException
3682
-     * @throws InvalidInterfaceException
3683
-     * @throws InvalidDataTypeException
3684
-     */
3685
-    protected function _per_page_screen_option()
3686
-    {
3687
-        $option = 'per_page';
3688
-        $args   = [
3689
-            'label'   => apply_filters(
3690
-                'FHEE__EE_Admin_Page___per_page_screen_options___label',
3691
-                $this->_admin_page_title,
3692
-                $this
3693
-            ),
3694
-            'default' => (int) apply_filters(
3695
-                'FHEE__EE_Admin_Page___per_page_screen_options__default',
3696
-                20
3697
-            ),
3698
-            'option'  => $this->_current_page . '_' . $this->_current_view . '_per_page',
3699
-        ];
3700
-        // ONLY add the screen option if the user has access to it.
3701
-        if ($this->check_user_access($this->_current_view, true)) {
3702
-            add_screen_option($option, $args);
3703
-        }
3704
-    }
3705
-
3706
-
3707
-    /**
3708
-     * set_per_page_screen_option
3709
-     * All this does is make sure that WordPress saves any per_page screen options (if set) for the current page.
3710
-     * we have to do this rather than running inside the 'set-screen-options' hook because it runs earlier than
3711
-     * admin_menu.
3712
-     *
3713
-     * @return void
3714
-     */
3715
-    private function _set_per_page_screen_options()
3716
-    {
3717
-        if ($this->request->requestParamIsSet('wp_screen_options')) {
3718
-            check_admin_referer('screen-options-nonce', 'screenoptionnonce');
3719
-            if (! $user = wp_get_current_user()) {
3720
-                return;
3721
-            }
3722
-            $option = $this->request->getRequestParam('wp_screen_options[option]', '', DataType::KEY);
3723
-            if (! $option) {
3724
-                return;
3725
-            }
3726
-            $value      = $this->request->getRequestParam('wp_screen_options[value]', 0, DataType::INT);
3727
-            $map_option = $option;
3728
-            $option     = str_replace('-', '_', $option);
3729
-            switch ($map_option) {
3730
-                case $this->_current_page . '_' . $this->_current_view . '_per_page':
3731
-                    $max_value = apply_filters(
3732
-                        'FHEE__EE_Admin_Page___set_per_page_screen_options__max_value',
3733
-                        999,
3734
-                        $this->_current_page,
3735
-                        $this->_current_view
3736
-                    );
3737
-                    if ($value < 1) {
3738
-                        return;
3739
-                    }
3740
-                    $value = min($value, $max_value);
3741
-                    break;
3742
-                default:
3743
-                    $value = apply_filters(
3744
-                        'FHEE__EE_Admin_Page___set_per_page_screen_options__value',
3745
-                        false,
3746
-                        $option,
3747
-                        $value
3748
-                    );
3749
-                    if (false === $value) {
3750
-                        return;
3751
-                    }
3752
-                    break;
3753
-            }
3754
-            update_user_meta($user->ID, $option, $value);
3755
-            wp_safe_redirect(remove_query_arg(['pagenum', 'apage', 'paged'], wp_get_referer()));
3756
-            exit;
3757
-        }
3758
-    }
3759
-
3760
-
3761
-    /**
3762
-     * This just allows for setting the $_template_args property if it needs to be set outside the object
3763
-     *
3764
-     * @param array $data array that will be assigned to template args.
3765
-     */
3766
-    public function set_template_args(array $data)
3767
-    {
3768
-        $this->_template_args = array_merge($this->_template_args, $data);
3769
-    }
3770
-
3771
-
3772
-    public function setAdminPageTitle(string $title)
3773
-    {
3774
-        $this->_admin_page_title = sanitize_text_field($title);
3775
-    }
3776
-
3777
-
3778
-    /**
3779
-     * This makes available the WP transient system for temporarily moving data between routes
3780
-     *
3781
-     * @param string $route             the route that should receive the transient
3782
-     * @param array  $data              the data that gets sent
3783
-     * @param bool   $notices           If this is for notices then we use this to indicate so, otherwise it's just a
3784
-     *                                  normal route transient.
3785
-     * @param bool   $skip_route_verify Used to indicate we want to skip route verification.  This is usually ONLY used
3786
-     *                                  when we are adding a transient before page_routes have been defined.
3787
-     * @return void
3788
-     * @throws EE_Error
3789
-     */
3790
-    protected function _add_transient(
3791
-        string $route,
3792
-        array $data,
3793
-        bool $notices = false,
3794
-        bool $skip_route_verify = false
3795
-    ) {
3796
-        $user_id = get_current_user_id();
3797
-        if (! $skip_route_verify) {
3798
-            $this->_verify_route($route);
3799
-        }
3800
-        // now let's set the string for what kind of transient we're setting
3801
-        $transient = $notices ? "ee_rte_n_tx_{$route}_$user_id" : "rte_tx_{$route}_$user_id";
3802
-        $data      = $notices ? ['notices' => $data] : $data;
3803
-        // is there already a transient for this route?  If there is then let's ADD to that transient
3804
-        $existing = is_multisite() && is_network_admin()
3805
-            ? get_site_transient($transient)
3806
-            : get_transient($transient);
3807
-        if ($existing) {
3808
-            $data = array_merge($data, (array) $existing);
3809
-        }
3810
-        if (is_multisite() && is_network_admin()) {
3811
-            set_site_transient($transient, $data, 8);
3812
-        } else {
3813
-            set_transient($transient, $data, 8);
3814
-        }
3815
-    }
3816
-
3817
-
3818
-    /**
3819
-     * this retrieves the temporary transient that has been set for moving data between routes.
3820
-     *
3821
-     * @param bool   $notices true we get notices transient. False we just return normal route transient
3822
-     * @param string $route
3823
-     * @return mixed data
3824
-     */
3825
-    protected function _get_transient(bool $notices = false, string $route = '')
3826
-    {
3827
-        $user_id   = get_current_user_id();
3828
-        $route     = ! $route ? $this->_req_action : $route;
3829
-        $transient = $notices
3830
-            ? 'ee_rte_n_tx_' . $route . '_' . $user_id
3831
-            : 'rte_tx_' . $route . '_' . $user_id;
3832
-        $data      = is_multisite() && is_network_admin()
3833
-            ? get_site_transient($transient)
3834
-            : get_transient($transient);
3835
-        // delete transient after retrieval (just in case it hasn't expired);
3836
-        if (is_multisite() && is_network_admin()) {
3837
-            delete_site_transient($transient);
3838
-        } else {
3839
-            delete_transient($transient);
3840
-        }
3841
-        return $notices && isset($data['notices']) ? $data['notices'] : $data;
3842
-    }
3843
-
3844
-
3845
-    /**
3846
-     * The purpose of this method is just to run garbage collection on any EE transients that might have expired but
3847
-     * would not be called later. This will be assigned to run on a specific EE Admin page. (place the method in the
3848
-     * default route callback on the EE_Admin page you want it run.)
3849
-     *
3850
-     * @return void
3851
-     */
3852
-    protected function _transient_garbage_collection()
3853
-    {
3854
-        global $wpdb;
3855
-        // retrieve all existing transients
3856
-        $query =
3857
-            "SELECT option_name FROM $wpdb->options WHERE option_name LIKE '%rte_tx_%' OR option_name LIKE '%rte_n_tx_%'";
3858
-        if ($results = $wpdb->get_results($query)) {
3859
-            foreach ($results as $result) {
3860
-                $transient = str_replace('_transient_', '', $result->option_name);
3861
-                get_transient($transient);
3862
-                if (is_multisite() && is_network_admin()) {
3863
-                    get_site_transient($transient);
3864
-                }
3865
-            }
3866
-        }
3867
-    }
3868
-
3869
-
3870
-    /**
3871
-     * get_view
3872
-     *
3873
-     * @return string content of _view property
3874
-     */
3875
-    public function get_view(): string
3876
-    {
3877
-        return $this->_view;
3878
-    }
3879
-
3880
-
3881
-    /**
3882
-     * getter for the protected $_views property
3883
-     *
3884
-     * @return array
3885
-     */
3886
-    public function get_views(): array
3887
-    {
3888
-        return $this->_views;
3889
-    }
3890
-
3891
-
3892
-    /**
3893
-     * @param array $views
3894
-     * @return void
3895
-     * @since 5.0.13.p
3896
-     */
3897
-    public function updateViews(array $views)
3898
-    {
3899
-        $this->_views = array_merge($this->_views, $views);
3900
-    }
3901
-
3902
-
3903
-    /**
3904
-    /**
3905
-     * get_current_page
3906
-     *
3907
-     * @return string _current_page property value
3908
-     */
3909
-    public function get_current_page(): string
3910
-    {
3911
-        return $this->_current_page;
3912
-    }
3913
-
3914
-
3915
-    /**
3916
-     * get_current_view
3917
-     *
3918
-     * @return string _current_view property value
3919
-     */
3920
-    public function get_current_view(): string
3921
-    {
3922
-        return $this->_current_view;
3923
-    }
3924
-
3925
-
3926
-    /**
3927
-     * get_current_screen
3928
-     *
3929
-     * @return object The current WP_Screen object
3930
-     */
3931
-    public function get_current_screen()
3932
-    {
3933
-        return $this->_current_screen;
3934
-    }
3935
-
3936
-
3937
-    /**
3938
-     * get_current_page_view_url
3939
-     *
3940
-     * @return string This returns the url for the current_page_view.
3941
-     */
3942
-    public function get_current_page_view_url(): string
3943
-    {
3944
-        return $this->_current_page_view_url;
3945
-    }
3946
-
3947
-
3948
-    /**
3949
-     * just returns the Request
3950
-     *
3951
-     * @return RequestInterface
3952
-     */
3953
-    public function get_request(): ?RequestInterface
3954
-    {
3955
-        return $this->request;
3956
-    }
3957
-
3958
-
3959
-    /**
3960
-     * just returns the _req_data property
3961
-     *
3962
-     * @return array
3963
-     */
3964
-    public function get_request_data(): array
3965
-    {
3966
-        return $this->request->requestParams();
3967
-    }
3968
-
3969
-
3970
-    /**
3971
-     * returns the _req_data protected property
3972
-     *
3973
-     * @return string
3974
-     */
3975
-    public function get_req_action(): string
3976
-    {
3977
-        return $this->_req_action;
3978
-    }
3979
-
3980
-
3981
-    /**
3982
-     * @return bool  value of $_is_caf property
3983
-     */
3984
-    public function is_caf(): bool
3985
-    {
3986
-        return $this->_is_caf;
3987
-    }
3988
-
3989
-
3990
-    /**
3991
-     * @return array
3992
-     */
3993
-    public function default_espresso_metaboxes(): array
3994
-    {
3995
-        return $this->_default_espresso_metaboxes;
3996
-    }
3997
-
3998
-
3999
-    /**
4000
-     * @return string
4001
-     */
4002
-    public function admin_base_url(): string
4003
-    {
4004
-        return $this->_admin_base_url;
4005
-    }
4006
-
4007
-
4008
-    /**
4009
-     * @return string
4010
-     */
4011
-    public function wp_page_slug(): string
4012
-    {
4013
-        return $this->_wp_page_slug;
4014
-    }
4015
-
4016
-
4017
-    /**
4018
-     * updates  espresso configuration settings
4019
-     *
4020
-     * @param string                   $tab
4021
-     * @param EE_Config_Base|EE_Config $config
4022
-     * @param string                   $file file where error occurred
4023
-     * @param string                   $func function  where error occurred
4024
-     * @param string                   $line line no where error occurred
4025
-     * @return bool
4026
-     * @throws EE_Error
4027
-     * @throws ReflectionException
4028
-     */
4029
-    protected function _update_espresso_configuration(
4030
-        string $tab,
4031
-        $config,
4032
-        string $file = '',
4033
-        string $func = '',
4034
-        string $line = ''
4035
-    ): bool {
4036
-        // remove any options that are NOT going to be saved with the config settings.
4037
-        if (isset($config->core->ee_ueip_optin)) {
4038
-            // TODO: remove the following two lines and make sure values are migrated from 3.1
4039
-            update_option('ee_ueip_optin', $config->core->ee_ueip_optin);
4040
-            update_option('ee_ueip_has_notified', true);
4041
-        }
4042
-        // and save it (note we're also doing the network save here)
4043
-        $net_saved    = ! is_main_site() || EE_Network_Config::instance()->update_config(false, false);
4044
-        $config_saved = EE_Config::instance()->update_espresso_config(false, false);
4045
-        if ($config_saved && $net_saved) {
4046
-            EE_Error::add_success(sprintf(esc_html__('"%s" have been successfully updated.', 'event_espresso'), $tab));
4047
-            return true;
4048
-        }
4049
-        EE_Error::add_error(
4050
-            sprintf(esc_html__('The "%s" were not updated.', 'event_espresso'), $tab),
4051
-            $file,
4052
-            $func,
4053
-            $line
4054
-        );
4055
-        return false;
4056
-    }
4057
-
4058
-
4059
-    /**
4060
-     * Returns an array to be used for EE_FOrm_Fields.helper.php's select_input as the $values argument.
4061
-     *
4062
-     * @return array
4063
-     */
4064
-    public function get_yes_no_values(): array
4065
-    {
4066
-        return $this->_yes_no_values;
4067
-    }
4068
-
4069
-
4070
-    /**
4071
-     * @return string
4072
-     * @throws ReflectionException
4073
-     * @since 5.0.0.p
4074
-     */
4075
-    protected function _get_dir(): string
4076
-    {
4077
-        $reflector = new ReflectionClass($this->class_name);
4078
-        return dirname($reflector->getFileName());
4079
-    }
4080
-
4081
-
4082
-    /**
4083
-     * A helper for getting a "next link".
4084
-     *
4085
-     * @param string $url   The url to link to
4086
-     * @param string $class The class to use.
4087
-     * @return string
4088
-     */
4089
-    protected function _next_link(string $url, string $class = 'dashicons dashicons-arrow-right'): string
4090
-    {
4091
-        return '<a class="' . $class . '" href="' . $url . '"></a>';
4092
-    }
4093
-
4094
-
4095
-    /**
4096
-     * A helper for getting a "previous link".
4097
-     *
4098
-     * @param string $url   The url to link to
4099
-     * @param string $class The class to use.
4100
-     * @return string
4101
-     */
4102
-    protected function _previous_link(string $url, string $class = 'dashicons dashicons-arrow-left'): string
4103
-    {
4104
-        return '<a class="' . $class . '" href="' . $url . '"></a>';
4105
-    }
4106
-
4107
-
4108
-
4109
-
4110
-
4111
-
4112
-
4113
-    // below are some messages related methods that should be available across the EE_Admin system.  Note, these methods are NOT page specific
4114
-
4115
-
4116
-    /**
4117
-     * This processes a request to resend a registration and assumes we have a _REG_ID for doing so. So if the caller
4118
-     * knows that the _REG_ID isn't in the req_data array but CAN obtain it, the caller should ADD the _REG_ID to the
4119
-     * _req_data array.
4120
-     *
4121
-     * @return bool success/fail
4122
-     * @throws EE_Error
4123
-     * @throws InvalidArgumentException
4124
-     * @throws ReflectionException
4125
-     * @throws InvalidDataTypeException
4126
-     * @throws InvalidInterfaceException
4127
-     */
4128
-    protected function _process_resend_registration(): bool
4129
-    {
4130
-        $this->_template_args['success'] = EED_Messages::process_resend($this->request->requestParams());
4131
-        do_action(
4132
-            'AHEE__EE_Admin_Page___process_resend_registration',
4133
-            $this->_template_args['success'],
4134
-            $this->request->requestParams()
4135
-        );
4136
-        return $this->_template_args['success'];
4137
-    }
4138
-
4139
-
4140
-    /**
4141
-     * This automatically processes any payment message notifications when manual payment has been applied.
4142
-     *
4143
-     * @param EE_Payment $payment
4144
-     * @return bool success/fail
4145
-     */
4146
-    protected function _process_payment_notification(EE_Payment $payment): bool
4147
-    {
4148
-        add_filter('FHEE__EE_Payment_Processor__process_registration_payments__display_notifications', '__return_true');
4149
-        do_action('AHEE__EE_Admin_Page___process_admin_payment_notification', $payment);
4150
-        $this->_template_args['success'] = apply_filters(
4151
-            'FHEE__EE_Admin_Page___process_admin_payment_notification__success',
4152
-            false,
4153
-            $payment
4154
-        );
4155
-        return $this->_template_args['success'];
4156
-    }
4157
-
4158
-
4159
-    /**
4160
-     * @param EEM_Base      $entity_model
4161
-     * @param string        $entity_PK_name name of the primary key field used as a request param, ie: id, ID, etc
4162
-     * @param string        $action         one of the EE_Admin_List_Table::ACTION_* constants: delete, restore, trash
4163
-     * @param string        $delete_column  name of the field that denotes whether entity is trashed
4164
-     * @param callable|null $callback       called after entity is trashed, restored, or deleted
4165
-     * @return int|float
4166
-     * @throws EE_Error
4167
-     */
4168
-    protected function trashRestoreDeleteEntities(
4169
-        EEM_Base $entity_model,
4170
-        string $entity_PK_name,
4171
-        string $action = EE_Admin_List_Table::ACTION_DELETE,
4172
-        string $delete_column = '',
4173
-        ?callable $callback = null
4174
-    ) {
4175
-        $entity_PK      = $entity_model->get_primary_key_field();
4176
-        $entity_PK_name = $entity_PK_name ?: $entity_PK->get_name();
4177
-        $entity_PK_type = $this->resolveEntityFieldDataType($entity_PK);
4178
-        // grab ID if deleting a single entity
4179
-        if ($this->request->requestParamIsSet($entity_PK_name)) {
4180
-            $ID = $this->request->getRequestParam($entity_PK_name, 0, $entity_PK_type);
4181
-            return $this->trashRestoreDeleteEntity($entity_model, $ID, $action, $delete_column, $callback) ? 1 : 0;
4182
-        }
4183
-        // or grab checkbox array if bulk deleting
4184
-        $checkboxes = $this->request->getRequestParam('checkbox', [], $entity_PK_type, true);
4185
-        if (empty($checkboxes)) {
4186
-            return 0;
4187
-        }
4188
-        $success = 0;
4189
-        $IDs     = array_keys($checkboxes);
4190
-        // cycle thru bulk action checkboxes
4191
-        foreach ($IDs as $ID) {
4192
-            // increment $success
4193
-            if ($this->trashRestoreDeleteEntity($entity_model, $ID, $action, $delete_column, $callback)) {
4194
-                $success++;
4195
-            }
4196
-        }
4197
-        $count = (int) count($checkboxes);
4198
-        // if multiple entities were deleted successfully, then $deleted will be full count of deletions,
4199
-        // otherwise it will be a fraction of ( actual deletions / total entities to be deleted )
4200
-        return $success === $count ? $count : $success / $count;
4201
-    }
4202
-
4203
-
4204
-    /**
4205
-     * @param EE_Primary_Key_Field_Base $entity_PK
4206
-     * @return string
4207
-     * @throws EE_Error
4208
-     * @since   4.10.30.p
4209
-     */
4210
-    private function resolveEntityFieldDataType(EE_Primary_Key_Field_Base $entity_PK): string
4211
-    {
4212
-        $entity_PK_type = $entity_PK->getSchemaType();
4213
-        switch ($entity_PK_type) {
4214
-            case 'boolean':
4215
-                return DataType::BOOL;
4216
-            case 'integer':
4217
-                return DataType::INT;
4218
-            case 'number':
4219
-                return DataType::FLOAT;
4220
-            case 'string':
4221
-                return DataType::STRING;
4222
-        }
4223
-        throw new RuntimeException(
4224
-            sprintf(
4225
-                esc_html__(
4226
-                    '"%1$s" is an invalid schema type for the %2$s primary key.',
4227
-                    'event_espresso'
4228
-                ),
4229
-                $entity_PK_type,
4230
-                $entity_PK->get_name()
4231
-            )
4232
-        );
4233
-    }
4234
-
4235
-
4236
-    /**
4237
-     * @param EEM_Base      $entity_model
4238
-     * @param int|string    $entity_ID
4239
-     * @param string        $action        one of the EE_Admin_List_Table::ACTION_* constants: delete, restore, trash
4240
-     * @param string        $delete_column name of the field that denotes whether entity is trashed
4241
-     * @param callable|null $callback      called after entity is trashed, restored, or deleted
4242
-     * @return bool
4243
-     */
4244
-    protected function trashRestoreDeleteEntity(
4245
-        EEM_Base $entity_model,
4246
-        $entity_ID,
4247
-        string $action,
4248
-        string $delete_column,
4249
-        ?callable $callback = null
4250
-    ): bool {
4251
-        $entity_ID = absint($entity_ID);
4252
-        if (! $entity_ID) {
4253
-            $this->trashRestoreDeleteError($action, $entity_model);
4254
-        }
4255
-        $result = 0;
4256
-        try {
4257
-            $entity = $entity_model->get_one_by_ID($entity_ID);
4258
-            if (! $entity instanceof EE_Base_Class) {
4259
-                throw new DomainException(
4260
-                    sprintf(
4261
-                        esc_html__(
4262
-                            'Missing or invalid %1$s entity with ID of "%2$s" returned from db.',
4263
-                            'event_espresso'
4264
-                        ),
4265
-                        str_replace('EEM_', '', $entity_model->get_this_model_name()),
4266
-                        $entity_ID
4267
-                    )
4268
-                );
4269
-            }
4270
-            switch ($action) {
4271
-                case EE_Admin_List_Table::ACTION_DELETE:
4272
-                    $result = (bool) $entity->delete_permanently();
4273
-                    break;
4274
-                case EE_Admin_List_Table::ACTION_RESTORE:
4275
-                    $result = $entity->delete_or_restore(false);
4276
-                    break;
4277
-                case EE_Admin_List_Table::ACTION_TRASH:
4278
-                    $result = $entity->delete_or_restore();
4279
-                    break;
4280
-            }
4281
-        } catch (Exception $exception) {
4282
-            $this->trashRestoreDeleteError($action, $entity_model, $exception);
4283
-        }
4284
-        if (is_callable($callback)) {
4285
-            call_user_func_array($callback, [$entity_model, $entity_ID, $action, $result, $delete_column]);
4286
-        }
4287
-        return $result;
4288
-    }
4289
-
4290
-
4291
-    /**
4292
-     * @param EEM_Base $entity_model
4293
-     * @param string   $delete_column
4294
-     * @since 4.10.30.p
4295
-     */
4296
-    private function validateDeleteColumn(EEM_Base $entity_model, string $delete_column)
4297
-    {
4298
-        if (empty($delete_column)) {
4299
-            throw new DomainException(
4300
-                sprintf(
4301
-                    esc_html__(
4302
-                        'You need to specify the name of the "delete column" on the %2$s model, in order to trash or restore an entity.',
4303
-                        'event_espresso'
4304
-                    ),
4305
-                    $entity_model->get_this_model_name()
4306
-                )
4307
-            );
4308
-        }
4309
-        if (! $entity_model->has_field($delete_column)) {
4310
-            throw new DomainException(
4311
-                sprintf(
4312
-                    esc_html__(
4313
-                        'The %1$s field does not exist on the %2$s model.',
4314
-                        'event_espresso'
4315
-                    ),
4316
-                    $delete_column,
4317
-                    $entity_model->get_this_model_name()
4318
-                )
4319
-            );
4320
-        }
4321
-    }
4322
-
4323
-
4324
-    /**
4325
-     * @param EEM_Base       $entity_model
4326
-     * @param Exception|null $exception
4327
-     * @param string         $action
4328
-     * @since 4.10.30.p
4329
-     */
4330
-    private function trashRestoreDeleteError(string $action, EEM_Base $entity_model, Exception $exception = null)
4331
-    {
4332
-        if ($exception instanceof Exception) {
4333
-            throw new RuntimeException(
4334
-                sprintf(
4335
-                    esc_html__(
4336
-                        'Could not %1$s the %2$s because the following error occurred: %3$s',
4337
-                        'event_espresso'
4338
-                    ),
4339
-                    $action,
4340
-                    $entity_model->get_this_model_name(),
4341
-                    $exception->getMessage()
4342
-                )
4343
-            );
4344
-        }
4345
-        throw new RuntimeException(
4346
-            sprintf(
4347
-                esc_html__(
4348
-                    'Could not %1$s the %2$s because an invalid ID was received.',
4349
-                    'event_espresso'
4350
-                ),
4351
-                $action,
4352
-                $entity_model->get_this_model_name()
4353
-            )
4354
-        );
4355
-    }
3346
+		// add nonce
3347
+		$nonce                                             =
3348
+			wp_nonce_field($route . '_nonce', $route . '_nonce', false, false);
3349
+		$this->_template_args['before_admin_page_content'] .= "\n\t" . $nonce;
3350
+		// add REQUIRED form action
3351
+		$hidden_fields = [
3352
+			'action' => ['type' => 'hidden', 'value' => $route],
3353
+		];
3354
+		// merge arrays
3355
+		$hidden_fields = is_array($additional_hidden_fields)
3356
+			? array_merge($hidden_fields, $additional_hidden_fields)
3357
+			: $hidden_fields;
3358
+		// generate form fields
3359
+		$form_fields = $this->_generate_admin_form_fields($hidden_fields, 'array');
3360
+		// add fields to form
3361
+		foreach ((array) $form_fields as $form_field) {
3362
+			$this->_template_args['before_admin_page_content'] .= "\n\t" . $form_field['field'];
3363
+		}
3364
+		// close form
3365
+		$this->_template_args['after_admin_page_content'] = '</form>';
3366
+	}
3367
+
3368
+
3369
+	/**
3370
+	 * Public Wrapper for _redirect_after_action() method since its
3371
+	 * discovered it would be useful for external code to have access.
3372
+	 *
3373
+	 * @param bool|int $success
3374
+	 * @param string   $what
3375
+	 * @param string   $action_desc
3376
+	 * @param array    $query_args
3377
+	 * @param bool     $override_overwrite
3378
+	 * @throws EE_Error
3379
+	 * @see   EE_Admin_Page::_redirect_after_action() for params.
3380
+	 * @since 4.5.0
3381
+	 */
3382
+	public function redirect_after_action(
3383
+		$success = false,
3384
+		string $what = 'item',
3385
+		string $action_desc = 'processed',
3386
+		array $query_args = [],
3387
+		bool $override_overwrite = false
3388
+	) {
3389
+		$this->_redirect_after_action(
3390
+			$success,
3391
+			$what,
3392
+			$action_desc,
3393
+			$query_args,
3394
+			$override_overwrite
3395
+		);
3396
+	}
3397
+
3398
+
3399
+	/**
3400
+	 * Helper method for merging existing request data with the returned redirect url.
3401
+	 * This is typically used for redirects after an action so that if the original view was a filtered view those
3402
+	 * filters are still applied.
3403
+	 *
3404
+	 * @param array $new_route_data
3405
+	 * @return array
3406
+	 */
3407
+	protected function mergeExistingRequestParamsWithRedirectArgs(array $new_route_data): array
3408
+	{
3409
+		foreach ($this->request->requestParams() as $ref => $value) {
3410
+			// unset nonces
3411
+			if (strpos($ref, 'nonce') !== false) {
3412
+				$this->request->unSetRequestParam($ref);
3413
+				continue;
3414
+			}
3415
+			// urlencode values.
3416
+			$value = is_array($value) ? array_map('urlencode', $value) : urlencode($value);
3417
+			$this->request->setRequestParam($ref, $value);
3418
+		}
3419
+		return array_merge($this->request->requestParams(), $new_route_data);
3420
+	}
3421
+
3422
+
3423
+	/**
3424
+	 * @param int|float|string $success            - whether success was for two or more records, or just one, or none
3425
+	 * @param string           $what               - what the action was performed on
3426
+	 * @param string           $action_desc        - what was done ie: updated, deleted, etc
3427
+	 * @param array            $query_args         - an array of query_args to be added to the URL to redirect to
3428
+	 * @param BOOL             $override_overwrite - by default all EE_Error::success messages are overwritten,
3429
+	 *                                             this allows you to override this so that they show.
3430
+	 * @return void
3431
+	 * @throws EE_Error
3432
+	 * @throws InvalidArgumentException
3433
+	 * @throws InvalidDataTypeException
3434
+	 * @throws InvalidInterfaceException
3435
+	 */
3436
+	protected function _redirect_after_action(
3437
+		$success = 0,
3438
+		string $what = 'item',
3439
+		string $action_desc = 'processed',
3440
+		array $query_args = [],
3441
+		bool $override_overwrite = false
3442
+	) {
3443
+		$notices = EE_Error::get_notices(false);
3444
+		// overwrite default success messages //BUT ONLY if overwrite not overridden
3445
+		if (! $override_overwrite || ! empty($notices['errors'])) {
3446
+			EE_Error::overwrite_success();
3447
+		}
3448
+		if (! $override_overwrite && ! empty($what) && ! empty($action_desc) && empty($notices['errors'])) {
3449
+			// how many records affected ? more than one record ? or just one ?
3450
+			EE_Error::add_success(
3451
+				sprintf(
3452
+					esc_html(
3453
+						_n(
3454
+							'The "%1$s" has been successfully %2$s.',
3455
+							'The "%1$s" have been successfully %2$s.',
3456
+							$success,
3457
+							'event_espresso'
3458
+						)
3459
+					),
3460
+					$what,
3461
+					$action_desc
3462
+				),
3463
+				__FILE__,
3464
+				__FUNCTION__,
3465
+				__LINE__
3466
+			);
3467
+		}
3468
+		// check that $query_args isn't something crazy
3469
+		$query_args = is_array($query_args) ? $query_args : [];
3470
+		/**
3471
+		 * Allow injecting actions before the query_args are modified for possible different
3472
+		 * redirections on save and close actions
3473
+		 *
3474
+		 * @param array $query_args       The original query_args array coming into the
3475
+		 *                                method.
3476
+		 * @since 4.2.0
3477
+		 */
3478
+		do_action(
3479
+			"AHEE__{$this->class_name}___redirect_after_action__before_redirect_modification_$this->_req_action",
3480
+			$query_args
3481
+		);
3482
+		// set redirect url.
3483
+		// Note if there is a "page" index in the $query_args then we go with vanilla admin.php route,
3484
+		// otherwise we go with whatever is set as the _admin_base_url
3485
+		$redirect_url = isset($query_args['page']) ? admin_url('admin.php') : $this->_admin_base_url;
3486
+		// calculate where we're going (if we have a "save and close" button pushed)
3487
+		if (
3488
+			$this->request->requestParamIsSet('save_and_close')
3489
+			&& $this->request->requestParamIsSet('save_and_close_referrer')
3490
+		) {
3491
+			// even though we have the save_and_close referrer, we need to parse the url for the action in order to generate a nonce
3492
+			$parsed_url = parse_url($this->request->getRequestParam('save_and_close_referrer', '', DataType::URL));
3493
+			// regenerate query args array from referrer URL
3494
+			parse_str($parsed_url['query'], $query_args);
3495
+			// correct page and action will be in the query args now
3496
+			$redirect_url = admin_url('admin.php');
3497
+		}
3498
+		// merge any default query_args set in _default_route_query_args property
3499
+		if (! empty($this->_default_route_query_args) && ! $this->_is_UI_request) {
3500
+			$args_to_merge = [];
3501
+			foreach ($this->_default_route_query_args as $query_param => $query_value) {
3502
+				// is there a wp_referer array in our _default_route_query_args property?
3503
+				if ($query_param === 'wp_referer') {
3504
+					$query_value = (array) $query_value;
3505
+					foreach ($query_value as $reference => $value) {
3506
+						if (strpos($reference, 'nonce') !== false) {
3507
+							continue;
3508
+						}
3509
+						// finally we will override any arguments in the referer with
3510
+						// what might be set on the _default_route_query_args array.
3511
+						if (isset($this->_default_route_query_args[ $reference ])) {
3512
+							$args_to_merge[ $reference ] = urlencode($this->_default_route_query_args[ $reference ]);
3513
+						} else {
3514
+							$args_to_merge[ $reference ] = urlencode($value);
3515
+						}
3516
+					}
3517
+					continue;
3518
+				}
3519
+				$args_to_merge[ $query_param ] = $query_value;
3520
+			}
3521
+			// now let's merge these arguments but override with what was specifically sent in to the
3522
+			// redirect.
3523
+			$query_args = array_merge($args_to_merge, $query_args);
3524
+		}
3525
+		$this->_process_notices($query_args);
3526
+		// generate redirect url
3527
+		// if redirecting to anything other than the main page, add a nonce
3528
+		if (isset($query_args['action'])) {
3529
+			// manually generate wp_nonce and merge that with the query vars
3530
+			// becuz the wp_nonce_url function wrecks havoc on some vars
3531
+			$query_args['_wpnonce'] = wp_create_nonce($query_args['action'] . '_nonce');
3532
+		}
3533
+		// we're adding some hooks and filters in here for processing any things just before redirects
3534
+		// (example: an admin page has done an insert or update and we want to run something after that).
3535
+		do_action('AHEE_redirect_' . $this->class_name . $this->_req_action, $query_args);
3536
+		$redirect_url = apply_filters(
3537
+			'FHEE_redirect_' . $this->class_name . $this->_req_action,
3538
+			EE_Admin_Page::add_query_args_and_nonce($query_args, $redirect_url),
3539
+			$query_args
3540
+		);
3541
+		// check if we're doing ajax.  If we are then lets just return the results and js can handle how it wants.
3542
+		if ($this->request->isAjax()) {
3543
+			$default_data                    = [
3544
+				'close'        => true,
3545
+				'redirect_url' => $redirect_url,
3546
+				'where'        => 'main',
3547
+				'what'         => 'append',
3548
+			];
3549
+			$this->_template_args['success'] = $success;
3550
+			$this->_template_args['data']    = ! empty($this->_template_args['data']) ? array_merge(
3551
+				$default_data,
3552
+				$this->_template_args['data']
3553
+			) : $default_data;
3554
+			$this->_return_json();
3555
+		}
3556
+		wp_safe_redirect($redirect_url);
3557
+		exit();
3558
+	}
3559
+
3560
+
3561
+	/**
3562
+	 * process any notices before redirecting (or returning ajax request)
3563
+	 * This method sets the $this->_template_args['notices'] attribute;
3564
+	 *
3565
+	 * @param array $query_args         any query args that need to be used for notice transient ('action')
3566
+	 * @param bool  $skip_route_verify  This is typically used when we are processing notices REALLY early and
3567
+	 *                                  page_routes haven't been defined yet.
3568
+	 * @param bool  $sticky_notices     This is used to flag that regardless of whether this is doing_ajax or not, we
3569
+	 *                                  still save a transient for the notice.
3570
+	 * @return void
3571
+	 * @throws EE_Error
3572
+	 * @throws InvalidArgumentException
3573
+	 * @throws InvalidDataTypeException
3574
+	 * @throws InvalidInterfaceException
3575
+	 */
3576
+	protected function _process_notices(
3577
+		array $query_args = [],
3578
+		bool $skip_route_verify = false,
3579
+		bool $sticky_notices = true
3580
+	) {
3581
+		// first let's set individual error properties if doing_ajax and the properties aren't already set.
3582
+		if ($this->request->isAjax()) {
3583
+			$notices = EE_Error::get_notices(false);
3584
+			if (empty($this->_template_args['success'])) {
3585
+				$this->_template_args['success'] = $notices['success'] ?? false;
3586
+			}
3587
+			if (empty($this->_template_args['errors'])) {
3588
+				$this->_template_args['errors'] = $notices['errors'] ?? false;
3589
+			}
3590
+			if (empty($this->_template_args['attention'])) {
3591
+				$this->_template_args['attention'] = $notices['attention'] ?? false;
3592
+			}
3593
+		}
3594
+		$this->_template_args['notices'] = EE_Error::get_notices();
3595
+		// IF this isn't ajax we need to create a transient for the notices using the route (however, overridden if $sticky_notices == true)
3596
+		if (! $this->request->isAjax() || $sticky_notices) {
3597
+			$route = $query_args['action'] ?? 'default';
3598
+			$this->_add_transient(
3599
+				$route,
3600
+				(array) $this->_template_args['notices'],
3601
+				true,
3602
+				$skip_route_verify
3603
+			);
3604
+		}
3605
+	}
3606
+
3607
+
3608
+	/**
3609
+	 * get_action_link_or_button
3610
+	 * returns the button html for adding, editing, or deleting an item (depending on given type)
3611
+	 *
3612
+	 * @param string $action        use this to indicate which action the url is generated with.
3613
+	 * @param string $type          accepted strings must be defined in the $_labels['button'] array(as the key)
3614
+	 *                              property.
3615
+	 * @param array  $extra_request if the button requires extra params you can include them in $key=>$value pairs.
3616
+	 * @param string $class         Use this to give the class for the button. Defaults to 'button--primary'
3617
+	 * @param string $base_url      If this is not provided
3618
+	 *                              the _admin_base_url will be used as the default for the button base_url.
3619
+	 *                              Otherwise this value will be used.
3620
+	 * @param bool   $exclude_nonce If true then no nonce will be in the generated button link.
3621
+	 * @return string
3622
+	 * @throws InvalidArgumentException
3623
+	 * @throws InvalidInterfaceException
3624
+	 * @throws InvalidDataTypeException
3625
+	 * @throws EE_Error
3626
+	 */
3627
+	public function get_action_link_or_button(
3628
+		string $action,
3629
+		string $type = 'add',
3630
+		array $extra_request = [],
3631
+		string $class = 'button button--primary',
3632
+		string $base_url = '',
3633
+		bool $exclude_nonce = false
3634
+	): string {
3635
+		// first let's validate the action (if $base_url is FALSE otherwise validation will happen further along)
3636
+		if (empty($base_url) && ! isset($this->_page_routes[ $action ])) {
3637
+			throw new EE_Error(
3638
+				sprintf(
3639
+					esc_html__(
3640
+						'There is no page route for given action for the button.  This action was given: %s',
3641
+						'event_espresso'
3642
+					),
3643
+					$action
3644
+				)
3645
+			);
3646
+		}
3647
+		if (! isset($this->_labels['buttons'][ $type ])) {
3648
+			throw new EE_Error(
3649
+				sprintf(
3650
+					esc_html__(
3651
+						'There is no label for the given button type (%s). Labels are set in the <code>_page_config</code> property.',
3652
+						'event_espresso'
3653
+					),
3654
+					$type
3655
+				)
3656
+			);
3657
+		}
3658
+		// finally check user access for this button.
3659
+		$has_access = $this->check_user_access($action, true);
3660
+		if (! $has_access) {
3661
+			return '';
3662
+		}
3663
+		$_base_url  = ! $base_url ? $this->_admin_base_url : $base_url;
3664
+		$query_args = [
3665
+			'action' => $action,
3666
+		];
3667
+		// merge extra_request args but make sure our original action takes precedence and doesn't get overwritten.
3668
+		if (! empty($extra_request)) {
3669
+			$query_args = array_merge($extra_request, $query_args);
3670
+		}
3671
+		$url = EE_Admin_Page::add_query_args_and_nonce($query_args, $_base_url, false, $exclude_nonce);
3672
+		return EEH_Template::get_button_or_link($url, $this->_labels['buttons'][ $type ], $class);
3673
+	}
3674
+
3675
+
3676
+	/**
3677
+	 * _per_page_screen_option
3678
+	 * Utility function for adding in a per_page_option in the screen_options_dropdown.
3679
+	 *
3680
+	 * @return void
3681
+	 * @throws InvalidArgumentException
3682
+	 * @throws InvalidInterfaceException
3683
+	 * @throws InvalidDataTypeException
3684
+	 */
3685
+	protected function _per_page_screen_option()
3686
+	{
3687
+		$option = 'per_page';
3688
+		$args   = [
3689
+			'label'   => apply_filters(
3690
+				'FHEE__EE_Admin_Page___per_page_screen_options___label',
3691
+				$this->_admin_page_title,
3692
+				$this
3693
+			),
3694
+			'default' => (int) apply_filters(
3695
+				'FHEE__EE_Admin_Page___per_page_screen_options__default',
3696
+				20
3697
+			),
3698
+			'option'  => $this->_current_page . '_' . $this->_current_view . '_per_page',
3699
+		];
3700
+		// ONLY add the screen option if the user has access to it.
3701
+		if ($this->check_user_access($this->_current_view, true)) {
3702
+			add_screen_option($option, $args);
3703
+		}
3704
+	}
3705
+
3706
+
3707
+	/**
3708
+	 * set_per_page_screen_option
3709
+	 * All this does is make sure that WordPress saves any per_page screen options (if set) for the current page.
3710
+	 * we have to do this rather than running inside the 'set-screen-options' hook because it runs earlier than
3711
+	 * admin_menu.
3712
+	 *
3713
+	 * @return void
3714
+	 */
3715
+	private function _set_per_page_screen_options()
3716
+	{
3717
+		if ($this->request->requestParamIsSet('wp_screen_options')) {
3718
+			check_admin_referer('screen-options-nonce', 'screenoptionnonce');
3719
+			if (! $user = wp_get_current_user()) {
3720
+				return;
3721
+			}
3722
+			$option = $this->request->getRequestParam('wp_screen_options[option]', '', DataType::KEY);
3723
+			if (! $option) {
3724
+				return;
3725
+			}
3726
+			$value      = $this->request->getRequestParam('wp_screen_options[value]', 0, DataType::INT);
3727
+			$map_option = $option;
3728
+			$option     = str_replace('-', '_', $option);
3729
+			switch ($map_option) {
3730
+				case $this->_current_page . '_' . $this->_current_view . '_per_page':
3731
+					$max_value = apply_filters(
3732
+						'FHEE__EE_Admin_Page___set_per_page_screen_options__max_value',
3733
+						999,
3734
+						$this->_current_page,
3735
+						$this->_current_view
3736
+					);
3737
+					if ($value < 1) {
3738
+						return;
3739
+					}
3740
+					$value = min($value, $max_value);
3741
+					break;
3742
+				default:
3743
+					$value = apply_filters(
3744
+						'FHEE__EE_Admin_Page___set_per_page_screen_options__value',
3745
+						false,
3746
+						$option,
3747
+						$value
3748
+					);
3749
+					if (false === $value) {
3750
+						return;
3751
+					}
3752
+					break;
3753
+			}
3754
+			update_user_meta($user->ID, $option, $value);
3755
+			wp_safe_redirect(remove_query_arg(['pagenum', 'apage', 'paged'], wp_get_referer()));
3756
+			exit;
3757
+		}
3758
+	}
3759
+
3760
+
3761
+	/**
3762
+	 * This just allows for setting the $_template_args property if it needs to be set outside the object
3763
+	 *
3764
+	 * @param array $data array that will be assigned to template args.
3765
+	 */
3766
+	public function set_template_args(array $data)
3767
+	{
3768
+		$this->_template_args = array_merge($this->_template_args, $data);
3769
+	}
3770
+
3771
+
3772
+	public function setAdminPageTitle(string $title)
3773
+	{
3774
+		$this->_admin_page_title = sanitize_text_field($title);
3775
+	}
3776
+
3777
+
3778
+	/**
3779
+	 * This makes available the WP transient system for temporarily moving data between routes
3780
+	 *
3781
+	 * @param string $route             the route that should receive the transient
3782
+	 * @param array  $data              the data that gets sent
3783
+	 * @param bool   $notices           If this is for notices then we use this to indicate so, otherwise it's just a
3784
+	 *                                  normal route transient.
3785
+	 * @param bool   $skip_route_verify Used to indicate we want to skip route verification.  This is usually ONLY used
3786
+	 *                                  when we are adding a transient before page_routes have been defined.
3787
+	 * @return void
3788
+	 * @throws EE_Error
3789
+	 */
3790
+	protected function _add_transient(
3791
+		string $route,
3792
+		array $data,
3793
+		bool $notices = false,
3794
+		bool $skip_route_verify = false
3795
+	) {
3796
+		$user_id = get_current_user_id();
3797
+		if (! $skip_route_verify) {
3798
+			$this->_verify_route($route);
3799
+		}
3800
+		// now let's set the string for what kind of transient we're setting
3801
+		$transient = $notices ? "ee_rte_n_tx_{$route}_$user_id" : "rte_tx_{$route}_$user_id";
3802
+		$data      = $notices ? ['notices' => $data] : $data;
3803
+		// is there already a transient for this route?  If there is then let's ADD to that transient
3804
+		$existing = is_multisite() && is_network_admin()
3805
+			? get_site_transient($transient)
3806
+			: get_transient($transient);
3807
+		if ($existing) {
3808
+			$data = array_merge($data, (array) $existing);
3809
+		}
3810
+		if (is_multisite() && is_network_admin()) {
3811
+			set_site_transient($transient, $data, 8);
3812
+		} else {
3813
+			set_transient($transient, $data, 8);
3814
+		}
3815
+	}
3816
+
3817
+
3818
+	/**
3819
+	 * this retrieves the temporary transient that has been set for moving data between routes.
3820
+	 *
3821
+	 * @param bool   $notices true we get notices transient. False we just return normal route transient
3822
+	 * @param string $route
3823
+	 * @return mixed data
3824
+	 */
3825
+	protected function _get_transient(bool $notices = false, string $route = '')
3826
+	{
3827
+		$user_id   = get_current_user_id();
3828
+		$route     = ! $route ? $this->_req_action : $route;
3829
+		$transient = $notices
3830
+			? 'ee_rte_n_tx_' . $route . '_' . $user_id
3831
+			: 'rte_tx_' . $route . '_' . $user_id;
3832
+		$data      = is_multisite() && is_network_admin()
3833
+			? get_site_transient($transient)
3834
+			: get_transient($transient);
3835
+		// delete transient after retrieval (just in case it hasn't expired);
3836
+		if (is_multisite() && is_network_admin()) {
3837
+			delete_site_transient($transient);
3838
+		} else {
3839
+			delete_transient($transient);
3840
+		}
3841
+		return $notices && isset($data['notices']) ? $data['notices'] : $data;
3842
+	}
3843
+
3844
+
3845
+	/**
3846
+	 * The purpose of this method is just to run garbage collection on any EE transients that might have expired but
3847
+	 * would not be called later. This will be assigned to run on a specific EE Admin page. (place the method in the
3848
+	 * default route callback on the EE_Admin page you want it run.)
3849
+	 *
3850
+	 * @return void
3851
+	 */
3852
+	protected function _transient_garbage_collection()
3853
+	{
3854
+		global $wpdb;
3855
+		// retrieve all existing transients
3856
+		$query =
3857
+			"SELECT option_name FROM $wpdb->options WHERE option_name LIKE '%rte_tx_%' OR option_name LIKE '%rte_n_tx_%'";
3858
+		if ($results = $wpdb->get_results($query)) {
3859
+			foreach ($results as $result) {
3860
+				$transient = str_replace('_transient_', '', $result->option_name);
3861
+				get_transient($transient);
3862
+				if (is_multisite() && is_network_admin()) {
3863
+					get_site_transient($transient);
3864
+				}
3865
+			}
3866
+		}
3867
+	}
3868
+
3869
+
3870
+	/**
3871
+	 * get_view
3872
+	 *
3873
+	 * @return string content of _view property
3874
+	 */
3875
+	public function get_view(): string
3876
+	{
3877
+		return $this->_view;
3878
+	}
3879
+
3880
+
3881
+	/**
3882
+	 * getter for the protected $_views property
3883
+	 *
3884
+	 * @return array
3885
+	 */
3886
+	public function get_views(): array
3887
+	{
3888
+		return $this->_views;
3889
+	}
3890
+
3891
+
3892
+	/**
3893
+	 * @param array $views
3894
+	 * @return void
3895
+	 * @since 5.0.13.p
3896
+	 */
3897
+	public function updateViews(array $views)
3898
+	{
3899
+		$this->_views = array_merge($this->_views, $views);
3900
+	}
3901
+
3902
+
3903
+	/**
3904
+    /**
3905
+	 * get_current_page
3906
+	 *
3907
+	 * @return string _current_page property value
3908
+	 */
3909
+	public function get_current_page(): string
3910
+	{
3911
+		return $this->_current_page;
3912
+	}
3913
+
3914
+
3915
+	/**
3916
+	 * get_current_view
3917
+	 *
3918
+	 * @return string _current_view property value
3919
+	 */
3920
+	public function get_current_view(): string
3921
+	{
3922
+		return $this->_current_view;
3923
+	}
3924
+
3925
+
3926
+	/**
3927
+	 * get_current_screen
3928
+	 *
3929
+	 * @return object The current WP_Screen object
3930
+	 */
3931
+	public function get_current_screen()
3932
+	{
3933
+		return $this->_current_screen;
3934
+	}
3935
+
3936
+
3937
+	/**
3938
+	 * get_current_page_view_url
3939
+	 *
3940
+	 * @return string This returns the url for the current_page_view.
3941
+	 */
3942
+	public function get_current_page_view_url(): string
3943
+	{
3944
+		return $this->_current_page_view_url;
3945
+	}
3946
+
3947
+
3948
+	/**
3949
+	 * just returns the Request
3950
+	 *
3951
+	 * @return RequestInterface
3952
+	 */
3953
+	public function get_request(): ?RequestInterface
3954
+	{
3955
+		return $this->request;
3956
+	}
3957
+
3958
+
3959
+	/**
3960
+	 * just returns the _req_data property
3961
+	 *
3962
+	 * @return array
3963
+	 */
3964
+	public function get_request_data(): array
3965
+	{
3966
+		return $this->request->requestParams();
3967
+	}
3968
+
3969
+
3970
+	/**
3971
+	 * returns the _req_data protected property
3972
+	 *
3973
+	 * @return string
3974
+	 */
3975
+	public function get_req_action(): string
3976
+	{
3977
+		return $this->_req_action;
3978
+	}
3979
+
3980
+
3981
+	/**
3982
+	 * @return bool  value of $_is_caf property
3983
+	 */
3984
+	public function is_caf(): bool
3985
+	{
3986
+		return $this->_is_caf;
3987
+	}
3988
+
3989
+
3990
+	/**
3991
+	 * @return array
3992
+	 */
3993
+	public function default_espresso_metaboxes(): array
3994
+	{
3995
+		return $this->_default_espresso_metaboxes;
3996
+	}
3997
+
3998
+
3999
+	/**
4000
+	 * @return string
4001
+	 */
4002
+	public function admin_base_url(): string
4003
+	{
4004
+		return $this->_admin_base_url;
4005
+	}
4006
+
4007
+
4008
+	/**
4009
+	 * @return string
4010
+	 */
4011
+	public function wp_page_slug(): string
4012
+	{
4013
+		return $this->_wp_page_slug;
4014
+	}
4015
+
4016
+
4017
+	/**
4018
+	 * updates  espresso configuration settings
4019
+	 *
4020
+	 * @param string                   $tab
4021
+	 * @param EE_Config_Base|EE_Config $config
4022
+	 * @param string                   $file file where error occurred
4023
+	 * @param string                   $func function  where error occurred
4024
+	 * @param string                   $line line no where error occurred
4025
+	 * @return bool
4026
+	 * @throws EE_Error
4027
+	 * @throws ReflectionException
4028
+	 */
4029
+	protected function _update_espresso_configuration(
4030
+		string $tab,
4031
+		$config,
4032
+		string $file = '',
4033
+		string $func = '',
4034
+		string $line = ''
4035
+	): bool {
4036
+		// remove any options that are NOT going to be saved with the config settings.
4037
+		if (isset($config->core->ee_ueip_optin)) {
4038
+			// TODO: remove the following two lines and make sure values are migrated from 3.1
4039
+			update_option('ee_ueip_optin', $config->core->ee_ueip_optin);
4040
+			update_option('ee_ueip_has_notified', true);
4041
+		}
4042
+		// and save it (note we're also doing the network save here)
4043
+		$net_saved    = ! is_main_site() || EE_Network_Config::instance()->update_config(false, false);
4044
+		$config_saved = EE_Config::instance()->update_espresso_config(false, false);
4045
+		if ($config_saved && $net_saved) {
4046
+			EE_Error::add_success(sprintf(esc_html__('"%s" have been successfully updated.', 'event_espresso'), $tab));
4047
+			return true;
4048
+		}
4049
+		EE_Error::add_error(
4050
+			sprintf(esc_html__('The "%s" were not updated.', 'event_espresso'), $tab),
4051
+			$file,
4052
+			$func,
4053
+			$line
4054
+		);
4055
+		return false;
4056
+	}
4057
+
4058
+
4059
+	/**
4060
+	 * Returns an array to be used for EE_FOrm_Fields.helper.php's select_input as the $values argument.
4061
+	 *
4062
+	 * @return array
4063
+	 */
4064
+	public function get_yes_no_values(): array
4065
+	{
4066
+		return $this->_yes_no_values;
4067
+	}
4068
+
4069
+
4070
+	/**
4071
+	 * @return string
4072
+	 * @throws ReflectionException
4073
+	 * @since 5.0.0.p
4074
+	 */
4075
+	protected function _get_dir(): string
4076
+	{
4077
+		$reflector = new ReflectionClass($this->class_name);
4078
+		return dirname($reflector->getFileName());
4079
+	}
4080
+
4081
+
4082
+	/**
4083
+	 * A helper for getting a "next link".
4084
+	 *
4085
+	 * @param string $url   The url to link to
4086
+	 * @param string $class The class to use.
4087
+	 * @return string
4088
+	 */
4089
+	protected function _next_link(string $url, string $class = 'dashicons dashicons-arrow-right'): string
4090
+	{
4091
+		return '<a class="' . $class . '" href="' . $url . '"></a>';
4092
+	}
4093
+
4094
+
4095
+	/**
4096
+	 * A helper for getting a "previous link".
4097
+	 *
4098
+	 * @param string $url   The url to link to
4099
+	 * @param string $class The class to use.
4100
+	 * @return string
4101
+	 */
4102
+	protected function _previous_link(string $url, string $class = 'dashicons dashicons-arrow-left'): string
4103
+	{
4104
+		return '<a class="' . $class . '" href="' . $url . '"></a>';
4105
+	}
4106
+
4107
+
4108
+
4109
+
4110
+
4111
+
4112
+
4113
+	// below are some messages related methods that should be available across the EE_Admin system.  Note, these methods are NOT page specific
4114
+
4115
+
4116
+	/**
4117
+	 * This processes a request to resend a registration and assumes we have a _REG_ID for doing so. So if the caller
4118
+	 * knows that the _REG_ID isn't in the req_data array but CAN obtain it, the caller should ADD the _REG_ID to the
4119
+	 * _req_data array.
4120
+	 *
4121
+	 * @return bool success/fail
4122
+	 * @throws EE_Error
4123
+	 * @throws InvalidArgumentException
4124
+	 * @throws ReflectionException
4125
+	 * @throws InvalidDataTypeException
4126
+	 * @throws InvalidInterfaceException
4127
+	 */
4128
+	protected function _process_resend_registration(): bool
4129
+	{
4130
+		$this->_template_args['success'] = EED_Messages::process_resend($this->request->requestParams());
4131
+		do_action(
4132
+			'AHEE__EE_Admin_Page___process_resend_registration',
4133
+			$this->_template_args['success'],
4134
+			$this->request->requestParams()
4135
+		);
4136
+		return $this->_template_args['success'];
4137
+	}
4138
+
4139
+
4140
+	/**
4141
+	 * This automatically processes any payment message notifications when manual payment has been applied.
4142
+	 *
4143
+	 * @param EE_Payment $payment
4144
+	 * @return bool success/fail
4145
+	 */
4146
+	protected function _process_payment_notification(EE_Payment $payment): bool
4147
+	{
4148
+		add_filter('FHEE__EE_Payment_Processor__process_registration_payments__display_notifications', '__return_true');
4149
+		do_action('AHEE__EE_Admin_Page___process_admin_payment_notification', $payment);
4150
+		$this->_template_args['success'] = apply_filters(
4151
+			'FHEE__EE_Admin_Page___process_admin_payment_notification__success',
4152
+			false,
4153
+			$payment
4154
+		);
4155
+		return $this->_template_args['success'];
4156
+	}
4157
+
4158
+
4159
+	/**
4160
+	 * @param EEM_Base      $entity_model
4161
+	 * @param string        $entity_PK_name name of the primary key field used as a request param, ie: id, ID, etc
4162
+	 * @param string        $action         one of the EE_Admin_List_Table::ACTION_* constants: delete, restore, trash
4163
+	 * @param string        $delete_column  name of the field that denotes whether entity is trashed
4164
+	 * @param callable|null $callback       called after entity is trashed, restored, or deleted
4165
+	 * @return int|float
4166
+	 * @throws EE_Error
4167
+	 */
4168
+	protected function trashRestoreDeleteEntities(
4169
+		EEM_Base $entity_model,
4170
+		string $entity_PK_name,
4171
+		string $action = EE_Admin_List_Table::ACTION_DELETE,
4172
+		string $delete_column = '',
4173
+		?callable $callback = null
4174
+	) {
4175
+		$entity_PK      = $entity_model->get_primary_key_field();
4176
+		$entity_PK_name = $entity_PK_name ?: $entity_PK->get_name();
4177
+		$entity_PK_type = $this->resolveEntityFieldDataType($entity_PK);
4178
+		// grab ID if deleting a single entity
4179
+		if ($this->request->requestParamIsSet($entity_PK_name)) {
4180
+			$ID = $this->request->getRequestParam($entity_PK_name, 0, $entity_PK_type);
4181
+			return $this->trashRestoreDeleteEntity($entity_model, $ID, $action, $delete_column, $callback) ? 1 : 0;
4182
+		}
4183
+		// or grab checkbox array if bulk deleting
4184
+		$checkboxes = $this->request->getRequestParam('checkbox', [], $entity_PK_type, true);
4185
+		if (empty($checkboxes)) {
4186
+			return 0;
4187
+		}
4188
+		$success = 0;
4189
+		$IDs     = array_keys($checkboxes);
4190
+		// cycle thru bulk action checkboxes
4191
+		foreach ($IDs as $ID) {
4192
+			// increment $success
4193
+			if ($this->trashRestoreDeleteEntity($entity_model, $ID, $action, $delete_column, $callback)) {
4194
+				$success++;
4195
+			}
4196
+		}
4197
+		$count = (int) count($checkboxes);
4198
+		// if multiple entities were deleted successfully, then $deleted will be full count of deletions,
4199
+		// otherwise it will be a fraction of ( actual deletions / total entities to be deleted )
4200
+		return $success === $count ? $count : $success / $count;
4201
+	}
4202
+
4203
+
4204
+	/**
4205
+	 * @param EE_Primary_Key_Field_Base $entity_PK
4206
+	 * @return string
4207
+	 * @throws EE_Error
4208
+	 * @since   4.10.30.p
4209
+	 */
4210
+	private function resolveEntityFieldDataType(EE_Primary_Key_Field_Base $entity_PK): string
4211
+	{
4212
+		$entity_PK_type = $entity_PK->getSchemaType();
4213
+		switch ($entity_PK_type) {
4214
+			case 'boolean':
4215
+				return DataType::BOOL;
4216
+			case 'integer':
4217
+				return DataType::INT;
4218
+			case 'number':
4219
+				return DataType::FLOAT;
4220
+			case 'string':
4221
+				return DataType::STRING;
4222
+		}
4223
+		throw new RuntimeException(
4224
+			sprintf(
4225
+				esc_html__(
4226
+					'"%1$s" is an invalid schema type for the %2$s primary key.',
4227
+					'event_espresso'
4228
+				),
4229
+				$entity_PK_type,
4230
+				$entity_PK->get_name()
4231
+			)
4232
+		);
4233
+	}
4234
+
4235
+
4236
+	/**
4237
+	 * @param EEM_Base      $entity_model
4238
+	 * @param int|string    $entity_ID
4239
+	 * @param string        $action        one of the EE_Admin_List_Table::ACTION_* constants: delete, restore, trash
4240
+	 * @param string        $delete_column name of the field that denotes whether entity is trashed
4241
+	 * @param callable|null $callback      called after entity is trashed, restored, or deleted
4242
+	 * @return bool
4243
+	 */
4244
+	protected function trashRestoreDeleteEntity(
4245
+		EEM_Base $entity_model,
4246
+		$entity_ID,
4247
+		string $action,
4248
+		string $delete_column,
4249
+		?callable $callback = null
4250
+	): bool {
4251
+		$entity_ID = absint($entity_ID);
4252
+		if (! $entity_ID) {
4253
+			$this->trashRestoreDeleteError($action, $entity_model);
4254
+		}
4255
+		$result = 0;
4256
+		try {
4257
+			$entity = $entity_model->get_one_by_ID($entity_ID);
4258
+			if (! $entity instanceof EE_Base_Class) {
4259
+				throw new DomainException(
4260
+					sprintf(
4261
+						esc_html__(
4262
+							'Missing or invalid %1$s entity with ID of "%2$s" returned from db.',
4263
+							'event_espresso'
4264
+						),
4265
+						str_replace('EEM_', '', $entity_model->get_this_model_name()),
4266
+						$entity_ID
4267
+					)
4268
+				);
4269
+			}
4270
+			switch ($action) {
4271
+				case EE_Admin_List_Table::ACTION_DELETE:
4272
+					$result = (bool) $entity->delete_permanently();
4273
+					break;
4274
+				case EE_Admin_List_Table::ACTION_RESTORE:
4275
+					$result = $entity->delete_or_restore(false);
4276
+					break;
4277
+				case EE_Admin_List_Table::ACTION_TRASH:
4278
+					$result = $entity->delete_or_restore();
4279
+					break;
4280
+			}
4281
+		} catch (Exception $exception) {
4282
+			$this->trashRestoreDeleteError($action, $entity_model, $exception);
4283
+		}
4284
+		if (is_callable($callback)) {
4285
+			call_user_func_array($callback, [$entity_model, $entity_ID, $action, $result, $delete_column]);
4286
+		}
4287
+		return $result;
4288
+	}
4289
+
4290
+
4291
+	/**
4292
+	 * @param EEM_Base $entity_model
4293
+	 * @param string   $delete_column
4294
+	 * @since 4.10.30.p
4295
+	 */
4296
+	private function validateDeleteColumn(EEM_Base $entity_model, string $delete_column)
4297
+	{
4298
+		if (empty($delete_column)) {
4299
+			throw new DomainException(
4300
+				sprintf(
4301
+					esc_html__(
4302
+						'You need to specify the name of the "delete column" on the %2$s model, in order to trash or restore an entity.',
4303
+						'event_espresso'
4304
+					),
4305
+					$entity_model->get_this_model_name()
4306
+				)
4307
+			);
4308
+		}
4309
+		if (! $entity_model->has_field($delete_column)) {
4310
+			throw new DomainException(
4311
+				sprintf(
4312
+					esc_html__(
4313
+						'The %1$s field does not exist on the %2$s model.',
4314
+						'event_espresso'
4315
+					),
4316
+					$delete_column,
4317
+					$entity_model->get_this_model_name()
4318
+				)
4319
+			);
4320
+		}
4321
+	}
4322
+
4323
+
4324
+	/**
4325
+	 * @param EEM_Base       $entity_model
4326
+	 * @param Exception|null $exception
4327
+	 * @param string         $action
4328
+	 * @since 4.10.30.p
4329
+	 */
4330
+	private function trashRestoreDeleteError(string $action, EEM_Base $entity_model, Exception $exception = null)
4331
+	{
4332
+		if ($exception instanceof Exception) {
4333
+			throw new RuntimeException(
4334
+				sprintf(
4335
+					esc_html__(
4336
+						'Could not %1$s the %2$s because the following error occurred: %3$s',
4337
+						'event_espresso'
4338
+					),
4339
+					$action,
4340
+					$entity_model->get_this_model_name(),
4341
+					$exception->getMessage()
4342
+				)
4343
+			);
4344
+		}
4345
+		throw new RuntimeException(
4346
+			sprintf(
4347
+				esc_html__(
4348
+					'Could not %1$s the %2$s because an invalid ID was received.',
4349
+					'event_espresso'
4350
+				),
4351
+				$action,
4352
+				$entity_model->get_this_model_name()
4353
+			)
4354
+		);
4355
+	}
4356 4356
 }
Please login to merge, or discard this patch.
Spacing   +185 added lines, -185 removed lines patch added patch discarded remove patch
@@ -24,23 +24,23 @@  discard block
 block discarded – undo
24 24
  */
25 25
 abstract class EE_Admin_Page extends EE_Base implements InterminableInterface
26 26
 {
27
-    protected ?EE_Admin_Config $admin_config       = null;
27
+    protected ?EE_Admin_Config $admin_config = null;
28 28
 
29
-    protected ?EE_Admin_Hooks $_hook_obj          = null;
29
+    protected ?EE_Admin_Hooks $_hook_obj = null;
30 30
 
31 31
     protected ?EE_Admin_List_Table $_list_table_object = null;
32 32
 
33
-    protected ?EE_Capabilities $capabilities       = null;
33
+    protected ?EE_Capabilities $capabilities = null;
34 34
 
35
-    protected ?EE_Registry $EE                 = null;
35
+    protected ?EE_Registry $EE = null;
36 36
 
37
-    protected ?FeatureFlags $feature            = null;
37
+    protected ?FeatureFlags $feature = null;
38 38
 
39
-    protected ?LoaderInterface $loader             = null;
39
+    protected ?LoaderInterface $loader = null;
40 40
 
41
-    protected ?RequestInterface $request            = null;
41
+    protected ?RequestInterface $request = null;
42 42
 
43
-    protected ?WP_Screen $_current_screen    = null;
43
+    protected ?WP_Screen $_current_screen = null;
44 44
 
45 45
     /**
46 46
      * @var array
@@ -124,7 +124,7 @@  discard block
 block discarded – undo
124 124
 
125 125
     protected string $_column_template_path = '';
126 126
 
127
-    protected bool $_cpt_route            = false;
127
+    protected bool $_cpt_route = false;
128 128
 
129 129
     /**
130 130
      * set via request page and action args.
@@ -245,7 +245,7 @@  discard block
 block discarded – undo
245 245
 
246 246
     public function capabilities(): EE_Capabilities
247 247
     {
248
-        if (! $this->capabilities instanceof EE_Capabilities) {
248
+        if ( ! $this->capabilities instanceof EE_Capabilities) {
249 249
             $this->capabilities = $this->loader->getShared(EE_Capabilities::class);
250 250
         }
251 251
         return $this->capabilities;
@@ -609,7 +609,7 @@  discard block
 block discarded – undo
609 609
         $ee_menu_slugs = (array) $ee_menu_slugs;
610 610
         if (
611 611
             ! $this->request->isAjax()
612
-            && (! $this->_current_page || ! isset($ee_menu_slugs[ $this->_current_page ]))
612
+            && ( ! $this->_current_page || ! isset($ee_menu_slugs[$this->_current_page]))
613 613
         ) {
614 614
             return;
615 615
         }
@@ -629,7 +629,7 @@  discard block
 block discarded – undo
629 629
             ? $route
630 630
             : $req_action;
631 631
         $this->_current_view = $this->_req_action;
632
-        $this->_req_nonce    = $this->_req_action . '_nonce';
632
+        $this->_req_nonce    = $this->_req_action.'_nonce';
633 633
         $this->_define_page_props();
634 634
         $this->_current_page_view_url = add_query_arg(
635 635
             ['page' => $this->_current_page, 'action' => $this->_current_view],
@@ -653,33 +653,33 @@  discard block
 block discarded – undo
653 653
         }
654 654
         // filter routes and page_config so addons can add their stuff. Filtering done per class
655 655
         $this->_page_routes = apply_filters(
656
-            'FHEE__' . $this->class_name . '__page_setup__page_routes',
656
+            'FHEE__'.$this->class_name.'__page_setup__page_routes',
657 657
             $this->_page_routes,
658 658
             $this
659 659
         );
660 660
         $this->_page_config = apply_filters(
661
-            'FHEE__' . $this->class_name . '__page_setup__page_config',
661
+            'FHEE__'.$this->class_name.'__page_setup__page_config',
662 662
             $this->_page_config,
663 663
             $this
664 664
         );
665 665
         if ($this->base_class_name !== '') {
666 666
             $this->_page_routes = apply_filters(
667
-                'FHEE__' . $this->base_class_name . '__page_setup__page_routes',
667
+                'FHEE__'.$this->base_class_name.'__page_setup__page_routes',
668 668
                 $this->_page_routes,
669 669
                 $this
670 670
             );
671 671
             $this->_page_config = apply_filters(
672
-                'FHEE__' . $this->base_class_name . '__page_setup__page_config',
672
+                'FHEE__'.$this->base_class_name.'__page_setup__page_config',
673 673
                 $this->_page_config,
674 674
                 $this
675 675
             );
676 676
         }
677 677
         // if AHEE__EE_Admin_Page__route_admin_request_$this->_current_view method is present
678 678
         // then we call it hooked into the AHEE__EE_Admin_Page__route_admin_request action
679
-        if (method_exists($this, 'AHEE__EE_Admin_Page__route_admin_request_' . $this->_current_view)) {
679
+        if (method_exists($this, 'AHEE__EE_Admin_Page__route_admin_request_'.$this->_current_view)) {
680 680
             add_action(
681 681
                 'AHEE__EE_Admin_Page__route_admin_request',
682
-                [$this, 'AHEE__EE_Admin_Page__route_admin_request_' . $this->_current_view],
682
+                [$this, 'AHEE__EE_Admin_Page__route_admin_request_'.$this->_current_view],
683 683
                 10,
684 684
                 2
685 685
             );
@@ -692,8 +692,8 @@  discard block
 block discarded – undo
692 692
             if ($this->_is_UI_request) {
693 693
                 // admin_init stuff - global, all views for this page class, specific view
694 694
                 add_action('admin_init', [$this, 'admin_init']);
695
-                if (method_exists($this, 'admin_init_' . $this->_current_view)) {
696
-                    add_action('admin_init', [$this, 'admin_init_' . $this->_current_view], 15);
695
+                if (method_exists($this, 'admin_init_'.$this->_current_view)) {
696
+                    add_action('admin_init', [$this, 'admin_init_'.$this->_current_view], 15);
697 697
                 }
698 698
             } else {
699 699
                 // hijack regular WP loading and route admin request immediately
@@ -712,12 +712,12 @@  discard block
 block discarded – undo
712 712
      */
713 713
     private function _do_other_page_hooks()
714 714
     {
715
-        $registered_pages = apply_filters('FHEE_do_other_page_hooks_' . $this->page_slug, []);
715
+        $registered_pages = apply_filters('FHEE_do_other_page_hooks_'.$this->page_slug, []);
716 716
         foreach ($registered_pages as $page) {
717 717
             // now let's set up the file name and class that should be present
718 718
             $classname = str_replace('.class.php', '', $page);
719 719
             // autoloaders should take care of loading file
720
-            if (! class_exists($classname)) {
720
+            if ( ! class_exists($classname)) {
721 721
                 $error_msg[] = sprintf(
722 722
                     esc_html__(
723 723
                         'Something went wrong with loading the %s admin hooks page.',
@@ -734,7 +734,7 @@  discard block
 block discarded – undo
734 734
                                    ),
735 735
                                    $page,
736 736
                                    '<br />',
737
-                                   '<strong>' . $classname . '</strong>'
737
+                                   '<strong>'.$classname.'</strong>'
738 738
                                );
739 739
                 throw new EE_Error(implode('||', $error_msg));
740 740
             }
@@ -783,13 +783,13 @@  discard block
 block discarded – undo
783 783
         // load admin_notices - global, page class, and view specific
784 784
         add_action('admin_notices', [$this, 'admin_notices_global'], 5);
785 785
         add_action('admin_notices', [$this, 'admin_notices']);
786
-        if (method_exists($this, 'admin_notices_' . $this->_current_view)) {
787
-            add_action('admin_notices', [$this, 'admin_notices_' . $this->_current_view], 15);
786
+        if (method_exists($this, 'admin_notices_'.$this->_current_view)) {
787
+            add_action('admin_notices', [$this, 'admin_notices_'.$this->_current_view], 15);
788 788
         }
789 789
         // load network admin_notices - global, page class, and view specific
790 790
         add_action('network_admin_notices', [$this, 'network_admin_notices_global'], 5);
791
-        if (method_exists($this, 'network_admin_notices_' . $this->_current_view)) {
792
-            add_action('network_admin_notices', [$this, 'network_admin_notices_' . $this->_current_view]);
791
+        if (method_exists($this, 'network_admin_notices_'.$this->_current_view)) {
792
+            add_action('network_admin_notices', [$this, 'network_admin_notices_'.$this->_current_view]);
793 793
         }
794 794
         // this will save any per_page screen options if they are present
795 795
         $this->_set_per_page_screen_options();
@@ -915,7 +915,7 @@  discard block
 block discarded – undo
915 915
      */
916 916
     protected function _verify_routes(): bool
917 917
     {
918
-        if (! $this->_current_page && ! $this->request->isAjax()) {
918
+        if ( ! $this->_current_page && ! $this->request->isAjax()) {
919 919
             return false;
920 920
         }
921 921
         // check that the page_routes array is not empty
@@ -926,7 +926,7 @@  discard block
 block discarded – undo
926 926
                 $this->_admin_page_title
927 927
             );
928 928
             // developer error msg
929
-            $error_msg .= '||' . $error_msg
929
+            $error_msg .= '||'.$error_msg
930 930
                           . esc_html__(
931 931
                               ' Make sure the "set_page_routes()" method exists, and is setting the "_page_routes" array properly.',
932 932
                               'event_espresso'
@@ -938,14 +938,14 @@  discard block
 block discarded – undo
938 938
         if (
939 939
             $this->_req_action === 'editpost'
940 940
             && ! isset($this->_page_routes['editpost'])
941
-            && isset($this->_page_routes[ $alt_edit_route ])
941
+            && isset($this->_page_routes[$alt_edit_route])
942 942
         ) {
943 943
             $this->_req_action = $alt_edit_route;
944 944
         }
945 945
         // and that the requested page route exists
946 946
         if (array_key_exists($this->_req_action, $this->_page_routes)) {
947
-            $this->_route        = $this->_page_routes[ $this->_req_action ];
948
-            $this->_route_config = $this->_page_config[ $this->_req_action ] ?? [];
947
+            $this->_route        = $this->_page_routes[$this->_req_action];
948
+            $this->_route_config = $this->_page_config[$this->_req_action] ?? [];
949 949
         } else {
950 950
             // user error msg
951 951
             $error_msg = sprintf(
@@ -956,7 +956,7 @@  discard block
 block discarded – undo
956 956
                 $this->_admin_page_title
957 957
             );
958 958
             // developer error msg
959
-            $error_msg .= '||' . $error_msg
959
+            $error_msg .= '||'.$error_msg
960 960
                           . sprintf(
961 961
                               esc_html__(
962 962
                                   ' Create a key in the "_page_routes" array named "%s" and set its value to the appropriate method.',
@@ -967,7 +967,7 @@  discard block
 block discarded – undo
967 967
             throw new EE_Error($error_msg);
968 968
         }
969 969
         // and that a default route exists
970
-        if (! array_key_exists('default', $this->_page_routes)) {
970
+        if ( ! array_key_exists('default', $this->_page_routes)) {
971 971
             // user error msg
972 972
             $error_msg = sprintf(
973 973
                 esc_html__(
@@ -977,7 +977,7 @@  discard block
 block discarded – undo
977 977
                 $this->_admin_page_title
978 978
             );
979 979
             // developer error msg
980
-            $error_msg .= '||' . $error_msg
980
+            $error_msg .= '||'.$error_msg
981 981
                           . esc_html__(
982 982
                               ' Create a key in the "_page_routes" array named "default" and set its value to your default page method.',
983 983
                               'event_espresso'
@@ -1017,7 +1017,7 @@  discard block
 block discarded – undo
1017 1017
             $this->_admin_page_title
1018 1018
         );
1019 1019
         // developer error msg
1020
-        $error_msg .= '||' . $error_msg
1020
+        $error_msg .= '||'.$error_msg
1021 1021
                       . sprintf(
1022 1022
                           esc_html__(
1023 1023
                               ' Check the route you are using in your method (%s) and make sure it matches a route set in your "_page_routes" array property',
@@ -1047,7 +1047,7 @@  discard block
 block discarded – undo
1047 1047
         $nonce = $nonce ?: $this->request->getRequestParam($this->_req_nonce, '');
1048 1048
         $nonce_ref = $nonce_ref ?: $this->_req_action;
1049 1049
         // verify nonce against expected value
1050
-        if (! wp_verify_nonce($nonce, $nonce_ref)) {
1050
+        if ( ! wp_verify_nonce($nonce, $nonce_ref)) {
1051 1051
             // these are not the droids you are looking for !!!
1052 1052
             $msg = sprintf(
1053 1053
                 esc_html__('%sNonce Fail.%s', 'event_espresso'),
@@ -1064,7 +1064,7 @@  discard block
 block discarded – undo
1064 1064
                     __CLASS__
1065 1065
                 );
1066 1066
             }
1067
-            if (! $this->request->isAjax()) {
1067
+            if ( ! $this->request->isAjax()) {
1068 1068
                 wp_die($msg);
1069 1069
             }
1070 1070
             EE_Error::add_error($msg, __FILE__, __FUNCTION__, __LINE__);
@@ -1089,7 +1089,7 @@  discard block
 block discarded – undo
1089 1089
      */
1090 1090
     protected function _route_admin_request()
1091 1091
     {
1092
-        if (! $this->_is_UI_request) {
1092
+        if ( ! $this->_is_UI_request) {
1093 1093
             $this->_verify_routes();
1094 1094
         }
1095 1095
         $nonce_check = ! isset($this->_route_config['require_nonce']) || $this->_route_config['require_nonce'];
@@ -1109,7 +1109,7 @@  discard block
 block discarded – undo
1109 1109
 
1110 1110
         // action right before calling route
1111 1111
         // (hook is something like 'AHEE__Registrations_Admin_Page__route_admin_request')
1112
-        if (! did_action('AHEE__EE_Admin_Page__route_admin_request')) {
1112
+        if ( ! did_action('AHEE__EE_Admin_Page__route_admin_request')) {
1113 1113
             do_action('AHEE__EE_Admin_Page__route_admin_request', $this->_current_view, $this);
1114 1114
         }
1115 1115
         // strip _wp_http_referer from the server REQUEST_URI
@@ -1124,7 +1124,7 @@  discard block
 block discarded – undo
1124 1124
         $this->request->setRequestParam('_wp_http_referer', $cleaner_request_uri, true);
1125 1125
         $this->request->setServerParam('REQUEST_URI', $cleaner_request_uri, true);
1126 1126
         $route_callback = [];
1127
-        if (! empty($func)) {
1127
+        if ( ! empty($func)) {
1128 1128
             if (is_array($func) && is_callable($func)) {
1129 1129
                 $route_callback = $func;
1130 1130
             } elseif (is_string($func)) {
@@ -1138,7 +1138,7 @@  discard block
 block discarded – undo
1138 1138
             }
1139 1139
             [$class, $method] = $route_callback;
1140 1140
             // is it neither a class method NOR a standalone function?
1141
-            if (! is_callable($route_callback)) {
1141
+            if ( ! is_callable($route_callback)) {
1142 1142
                 // user error msg
1143 1143
                 $error_msg = esc_html__(
1144 1144
                     'An error occurred. The  requested page route could not be found.',
@@ -1247,7 +1247,7 @@  discard block
 block discarded – undo
1247 1247
                 if (strpos($key, 'nonce') !== false) {
1248 1248
                     continue;
1249 1249
                 }
1250
-                $args[ 'wp_referer[' . $key . ']' ] = is_string($value) ? htmlspecialchars($value) : $value;
1250
+                $args['wp_referer['.$key.']'] = is_string($value) ? htmlspecialchars($value) : $value;
1251 1251
             }
1252 1252
         }
1253 1253
         return EEH_URL::add_query_args_and_nonce($args, $url, $exclude_nonce, $context);
@@ -1287,12 +1287,12 @@  discard block
 block discarded – undo
1287 1287
      */
1288 1288
     protected function _add_help_tabs()
1289 1289
     {
1290
-        if (isset($this->_page_config[ $this->_req_action ])) {
1291
-            $config = $this->_page_config[ $this->_req_action ];
1290
+        if (isset($this->_page_config[$this->_req_action])) {
1291
+            $config = $this->_page_config[$this->_req_action];
1292 1292
             // let's see if there is a help_sidebar set for the current route and we'll set that up for usage as well.
1293 1293
             if (is_array($config) && isset($config['help_sidebar'])) {
1294 1294
                 // check that the callback given is valid
1295
-                if (! method_exists($this, $config['help_sidebar'])) {
1295
+                if ( ! method_exists($this, $config['help_sidebar'])) {
1296 1296
                     throw new EE_Error(
1297 1297
                         sprintf(
1298 1298
                             esc_html__(
@@ -1305,18 +1305,18 @@  discard block
 block discarded – undo
1305 1305
                     );
1306 1306
                 }
1307 1307
                 $content = apply_filters(
1308
-                    'FHEE__' . $this->class_name . '__add_help_tabs__help_sidebar',
1308
+                    'FHEE__'.$this->class_name.'__add_help_tabs__help_sidebar',
1309 1309
                     $this->{$config['help_sidebar']}()
1310 1310
                 );
1311 1311
                 $this->_current_screen->set_help_sidebar($content);
1312 1312
             }
1313
-            if (! isset($config['help_tabs'])) {
1313
+            if ( ! isset($config['help_tabs'])) {
1314 1314
                 return;
1315 1315
             } //no help tabs for this route
1316 1316
             foreach ((array) $config['help_tabs'] as $tab_id => $cfg) {
1317 1317
                 // we're here so there ARE help tabs!
1318 1318
                 // make sure we've got what we need
1319
-                if (! isset($cfg['title'])) {
1319
+                if ( ! isset($cfg['title'])) {
1320 1320
                     throw new EE_Error(
1321 1321
                         esc_html__(
1322 1322
                             'The _page_config array is not set up properly for help tabs.  It is missing a title',
@@ -1324,7 +1324,7 @@  discard block
 block discarded – undo
1324 1324
                         )
1325 1325
                     );
1326 1326
                 }
1327
-                if (! isset($cfg['filename']) && ! isset($cfg['callback']) && ! isset($cfg['content'])) {
1327
+                if ( ! isset($cfg['filename']) && ! isset($cfg['callback']) && ! isset($cfg['content'])) {
1328 1328
                     throw new EE_Error(
1329 1329
                         esc_html__(
1330 1330
                             'The _page_config array is not setup properly for help tabs. It is missing a either a filename reference, or a callback reference or a content reference so there is no way to know the content for the help tab',
@@ -1333,11 +1333,11 @@  discard block
 block discarded – undo
1333 1333
                     );
1334 1334
                 }
1335 1335
                 // first priority goes to content.
1336
-                if (! empty($cfg['content'])) {
1336
+                if ( ! empty($cfg['content'])) {
1337 1337
                     $content = $cfg['content'];
1338 1338
                     // second priority goes to filename
1339
-                } elseif (! empty($cfg['filename'])) {
1340
-                    $file_path = $this->_get_dir() . '/help_tabs/' . $cfg['filename'] . '.help_tab.php';
1339
+                } elseif ( ! empty($cfg['filename'])) {
1340
+                    $file_path = $this->_get_dir().'/help_tabs/'.$cfg['filename'].'.help_tab.php';
1341 1341
                     // it's possible that the file is located on decaf route (and above sets up for caf route, if this is the case then lets check decaf route too)
1342 1342
                     $file_path = ! is_readable($file_path) ? EE_ADMIN_PAGES
1343 1343
                                                              . basename($this->_get_dir())
@@ -1345,7 +1345,7 @@  discard block
 block discarded – undo
1345 1345
                                                              . $cfg['filename']
1346 1346
                                                              . '.help_tab.php' : $file_path;
1347 1347
                     // if file is STILL not readable then let's do an EE_Error so its more graceful than a fatal error.
1348
-                    if (! isset($cfg['callback']) && ! is_readable($file_path)) {
1348
+                    if ( ! isset($cfg['callback']) && ! is_readable($file_path)) {
1349 1349
                         EE_Error::add_error(
1350 1350
                             sprintf(
1351 1351
                                 esc_html__(
@@ -1393,7 +1393,7 @@  discard block
 block discarded – undo
1393 1393
                     return;
1394 1394
                 }
1395 1395
                 // setup config array for help tab method
1396
-                $id  = $this->page_slug . '-' . $this->_req_action . '-' . $tab_id;
1396
+                $id  = $this->page_slug.'-'.$this->_req_action.'-'.$tab_id;
1397 1397
                 $_ht = [
1398 1398
                     'id'       => $id,
1399 1399
                     'title'    => $cfg['title'],
@@ -1419,8 +1419,8 @@  discard block
 block discarded – undo
1419 1419
             $qtips = (array) $this->_route_config['qtips'];
1420 1420
             // load qtip loader
1421 1421
             $path = [
1422
-                $this->_get_dir() . '/qtips/',
1423
-                EE_ADMIN_PAGES . basename($this->_get_dir()) . '/qtips/',
1422
+                $this->_get_dir().'/qtips/',
1423
+                EE_ADMIN_PAGES.basename($this->_get_dir()).'/qtips/',
1424 1424
             ];
1425 1425
             EEH_Qtip_Loader::instance()->register($qtips, $path);
1426 1426
         }
@@ -1442,7 +1442,7 @@  discard block
 block discarded – undo
1442 1442
         $i        = 0;
1443 1443
         $only_tab = count($this->_page_config) < 2;
1444 1444
         foreach ($this->_page_config as $slug => $config) {
1445
-            if (! is_array($config) || empty($config['nav'])) {
1445
+            if ( ! is_array($config) || empty($config['nav'])) {
1446 1446
                 continue;
1447 1447
             }
1448 1448
             // no nav tab for this config
@@ -1451,7 +1451,7 @@  discard block
 block discarded – undo
1451 1451
                 // nav tab is only to appear when route requested.
1452 1452
                 continue;
1453 1453
             }
1454
-            if (! $this->check_user_access($slug, true)) {
1454
+            if ( ! $this->check_user_access($slug, true)) {
1455 1455
                 // no nav tab because current user does not have access.
1456 1456
                 continue;
1457 1457
             }
@@ -1459,20 +1459,20 @@  discard block
 block discarded – undo
1459 1459
             $css_class .= $only_tab ? ' ee-only-tab' : '';
1460 1460
             $css_class .= " ee-nav-tab__$slug";
1461 1461
 
1462
-            $this->_nav_tabs[ $slug ] = [
1462
+            $this->_nav_tabs[$slug] = [
1463 1463
                 'url'       => $config['nav']['url'] ?? EE_Admin_Page::add_query_args_and_nonce(
1464 1464
                     ['action' => $slug],
1465 1465
                     $this->_admin_base_url
1466 1466
                 ),
1467 1467
                 'link_text' => $this->navTabLabel($config['nav'], $slug),
1468
-                'css_class' => $this->_req_action === $slug ? $css_class . ' nav-tab-active' : $css_class,
1468
+                'css_class' => $this->_req_action === $slug ? $css_class.' nav-tab-active' : $css_class,
1469 1469
                 'order'     => $config['nav']['order'] ?? $i,
1470 1470
             ];
1471 1471
             $i++;
1472 1472
         }
1473 1473
         // if $this->_nav_tabs is empty then lets set the default
1474 1474
         if (empty($this->_nav_tabs)) {
1475
-            $this->_nav_tabs[ $this->_default_nav_tab_name ] = [
1475
+            $this->_nav_tabs[$this->_default_nav_tab_name] = [
1476 1476
                 'url'       => $this->_admin_base_url,
1477 1477
                 'link_text' => ucwords(str_replace('_', ' ', $this->_default_nav_tab_name)),
1478 1478
                 'css_class' => 'nav-tab-active',
@@ -1488,11 +1488,11 @@  discard block
 block discarded – undo
1488 1488
     {
1489 1489
         $label = $nav_tab['label'] ?? ucwords(str_replace('_', ' ', $slug));
1490 1490
         $icon  = $nav_tab['icon'] ?? null;
1491
-        $icon  = $icon ? '<span class="dashicons ' . $icon . '"></span>' : '';
1491
+        $icon  = $icon ? '<span class="dashicons '.$icon.'"></span>' : '';
1492 1492
         return '
1493 1493
             <span class="ee-admin-screen-tab__label">
1494
-                ' . $icon . '
1495
-                <span class="ee-nav-label__text">' . $label . '</span>
1494
+                ' . $icon.'
1495
+                <span class="ee-nav-label__text">' . $label.'</span>
1496 1496
             </span>';
1497 1497
     }
1498 1498
 
@@ -1510,10 +1510,10 @@  discard block
 block discarded – undo
1510 1510
             foreach ($this->_route_config['labels'] as $label => $text) {
1511 1511
                 if (is_array($text)) {
1512 1512
                     foreach ($text as $sublabel => $subtext) {
1513
-                        $this->_labels[ $label ][ $sublabel ] = $subtext;
1513
+                        $this->_labels[$label][$sublabel] = $subtext;
1514 1514
                     }
1515 1515
                 } else {
1516
-                    $this->_labels[ $label ] = $text;
1516
+                    $this->_labels[$label] = $text;
1517 1517
                 }
1518 1518
             }
1519 1519
         }
@@ -1535,8 +1535,8 @@  discard block
 block discarded – undo
1535 1535
     {
1536 1536
         // if no route_to_check is passed in then use the current route set via _req_action
1537 1537
         $action = $route_to_check ?: $this->_req_action;
1538
-        $capability = ! empty($this->_page_routes[ $action ]['capability'])
1539
-            ? $this->_page_routes[ $action ]['capability']
1538
+        $capability = ! empty($this->_page_routes[$action]['capability'])
1539
+            ? $this->_page_routes[$action]['capability']
1540 1540
             : null;
1541 1541
 
1542 1542
         if (empty($capability)) {
@@ -1586,14 +1586,14 @@  discard block
 block discarded – undo
1586 1586
         string $priority = 'default',
1587 1587
         ?array $callback_args = null
1588 1588
     ) {
1589
-        if (! (is_callable($callback) || ! function_exists($callback))) {
1589
+        if ( ! (is_callable($callback) || ! function_exists($callback))) {
1590 1590
             return;
1591 1591
         }
1592 1592
 
1593 1593
         add_meta_box($box_id, $title, $callback, $screen, $context, $priority, $callback_args);
1594 1594
         add_filter(
1595 1595
             "postbox_classes_{$this->_wp_page_slug}_$box_id",
1596
-            function ($classes) {
1596
+            function($classes) {
1597 1597
                 $classes[] = 'ee-admin-container';
1598 1598
                 return $classes;
1599 1599
             }
@@ -1684,8 +1684,8 @@  discard block
 block discarded – undo
1684 1684
             <div class="ee-notices"></div>
1685 1685
             <div class="ee-admin-dialog-container-inner-content"></div>
1686 1686
         </div>
1687
-        <span id="current_timezone" class="hidden">' . esc_html(EEH_DTT_Helper::get_timezone()) . '</span>
1688
-        <input type="hidden" id="espresso_admin_current_page" value="' . esc_attr($this->_current_page) . '"/>';
1687
+        <span id="current_timezone" class="hidden">' . esc_html(EEH_DTT_Helper::get_timezone()).'</span>
1688
+        <input type="hidden" id="espresso_admin_current_page" value="' . esc_attr($this->_current_page).'"/>';
1689 1689
     }
1690 1690
 
1691 1691
 
@@ -1719,7 +1719,7 @@  discard block
 block discarded – undo
1719 1719
         // loop through the array and setup content
1720 1720
         foreach ($help_array as $trigger => $help) {
1721 1721
             // make sure the array is set up properly
1722
-            if (! isset($help['title'], $help['content'])) {
1722
+            if ( ! isset($help['title'], $help['content'])) {
1723 1723
                 throw new EE_Error(
1724 1724
                     esc_html__(
1725 1725
                         'Does not look like the popup content array has been setup correctly.  Might want to double check that.  Read the comments for the _get_help_popup_content method found in "EE_Admin_Page" class',
@@ -1733,8 +1733,8 @@  discard block
 block discarded – undo
1733 1733
                 'help_popup_title'   => $help['title'],
1734 1734
                 'help_popup_content' => $help['content'],
1735 1735
             ];
1736
-            $content       .= EEH_Template::display_template(
1737
-                EE_ADMIN_TEMPLATE . 'admin_help_popup.template.php',
1736
+            $content .= EEH_Template::display_template(
1737
+                EE_ADMIN_TEMPLATE.'admin_help_popup.template.php',
1738 1738
                 $template_args,
1739 1739
                 true
1740 1740
             );
@@ -1756,15 +1756,15 @@  discard block
 block discarded – undo
1756 1756
     private function _get_help_content(): array
1757 1757
     {
1758 1758
         // what is the method we're looking for?
1759
-        $method_name = '_help_popup_content_' . $this->_req_action;
1759
+        $method_name = '_help_popup_content_'.$this->_req_action;
1760 1760
         // if method doesn't exist let's get out.
1761
-        if (! method_exists($this, $method_name)) {
1761
+        if ( ! method_exists($this, $method_name)) {
1762 1762
             return [];
1763 1763
         }
1764 1764
         // k we're good to go let's retrieve the help array
1765 1765
         $help_array = $this->{$method_name}();
1766 1766
         // make sure we've got an array!
1767
-        if (! is_array($help_array)) {
1767
+        if ( ! is_array($help_array)) {
1768 1768
             throw new EE_Error(
1769 1769
                 esc_html__(
1770 1770
                     'Something went wrong with help popup content generation. Expecting an array and well, this ain\'t no array bub.',
@@ -1796,15 +1796,15 @@  discard block
 block discarded – undo
1796 1796
         // let's check and see if there is any content set for this popup.  If there isn't then we'll include a default title and content so that developers know something needs to be corrected
1797 1797
         $help_array   = $this->_get_help_content();
1798 1798
         $help_content = '';
1799
-        if (empty($help_array) || ! isset($help_array[ $trigger_id ])) {
1800
-            $help_array[ $trigger_id ] = [
1799
+        if (empty($help_array) || ! isset($help_array[$trigger_id])) {
1800
+            $help_array[$trigger_id] = [
1801 1801
                 'title'   => esc_html__('Missing Content', 'event_espresso'),
1802 1802
                 'content' => esc_html__(
1803 1803
                     'A trigger has been set that doesn\'t have any corresponding content. Make sure you have set the help content. (see the "_set_help_popup_content" method in the EE_Admin_Page for instructions.)',
1804 1804
                     'event_espresso'
1805 1805
                 ),
1806 1806
             ];
1807
-            $help_content              = $this->_set_help_popup_content($help_array);
1807
+            $help_content = $this->_set_help_popup_content($help_array);
1808 1808
         }
1809 1809
         $height   = esc_attr($dimensions[0]) ?? 400;
1810 1810
         $width    = esc_attr($dimensions[1]) ?? 640;
@@ -1892,7 +1892,7 @@  discard block
 block discarded – undo
1892 1892
 
1893 1893
         add_filter(
1894 1894
             'admin_body_class',
1895
-            function ($classes) {
1895
+            function($classes) {
1896 1896
                 if (strpos($classes, 'espresso-admin') === false) {
1897 1897
                     $classes .= ' espresso-admin';
1898 1898
                 }
@@ -1983,12 +1983,12 @@  discard block
 block discarded – undo
1983 1983
     protected function _set_list_table()
1984 1984
     {
1985 1985
         // first is this a list_table view?
1986
-        if (! isset($this->_route_config['list_table'])) {
1986
+        if ( ! isset($this->_route_config['list_table'])) {
1987 1987
             return;
1988 1988
         } //not a list_table view so get out.
1989 1989
         // list table functions are per view specific (because some admin pages might have more than one list table!)
1990
-        $list_table_view = '_set_list_table_views_' . $this->_req_action;
1991
-        if (! method_exists($this, $list_table_view)) {
1990
+        $list_table_view = '_set_list_table_views_'.$this->_req_action;
1991
+        if ( ! method_exists($this, $list_table_view)) {
1992 1992
             // user error msg
1993 1993
             $error_msg = esc_html__(
1994 1994
                 'An error occurred. The requested list table views could not be found.',
@@ -2009,10 +2009,10 @@  discard block
 block discarded – undo
2009 2009
         $this->{$list_table_view}();
2010 2010
         // let's provide the ability to filter the views per PAGE AND ROUTE, per PAGE, and globally
2011 2011
         $this->_views = apply_filters(
2012
-            'FHEE_list_table_views_' . $this->page_slug . '_' . $this->_req_action,
2012
+            'FHEE_list_table_views_'.$this->page_slug.'_'.$this->_req_action,
2013 2013
             $this->_views
2014 2014
         );
2015
-        $this->_views = apply_filters('FHEE_list_table_views_' . $this->page_slug, $this->_views);
2015
+        $this->_views = apply_filters('FHEE_list_table_views_'.$this->page_slug, $this->_views);
2016 2016
         $this->_views = apply_filters('FHEE_list_table_views', $this->_views);
2017 2017
         $this->_set_list_table_view();
2018 2018
         $this->_set_list_table_object();
@@ -2047,7 +2047,7 @@  discard block
 block discarded – undo
2047 2047
     protected function _set_list_table_object()
2048 2048
     {
2049 2049
         if (isset($this->_route_config['list_table'])) {
2050
-            if (! class_exists($this->_route_config['list_table'])) {
2050
+            if ( ! class_exists($this->_route_config['list_table'])) {
2051 2051
                 throw new EE_Error(
2052 2052
                     sprintf(
2053 2053
                         esc_html__(
@@ -2090,19 +2090,19 @@  discard block
 block discarded – undo
2090 2090
         // cycle thru views
2091 2091
         foreach ($this->_views as $key => $view) {
2092 2092
             $query_args = [];
2093
-            if ( ! isset($this->_views[ $key ]['class'])) {
2094
-                $this->_views[ $key ]['class'] = '';
2093
+            if ( ! isset($this->_views[$key]['class'])) {
2094
+                $this->_views[$key]['class'] = '';
2095 2095
             }
2096 2096
             // check for current view
2097
-            $this->_views[ $key ]['class'] .= $this->_view === $view['slug'] ? ' current' : '';
2097
+            $this->_views[$key]['class'] .= $this->_view === $view['slug'] ? ' current' : '';
2098 2098
             $query_args['action']          = $this->_req_action;
2099
-            $query_args[ $action_nonce ]   = $nonce;
2099
+            $query_args[$action_nonce]   = $nonce;
2100 2100
             $query_args['status']          = $view['slug'];
2101 2101
             // merge any other arguments sent in.
2102
-            if (isset($extra_query_args[ $view['slug'] ])) {
2103
-                $query_args = array_merge($query_args, $extra_query_args[ $view['slug'] ]);
2102
+            if (isset($extra_query_args[$view['slug']])) {
2103
+                $query_args = array_merge($query_args, $extra_query_args[$view['slug']]);
2104 2104
             }
2105
-            $this->_views[ $key ]['url'] = EE_Admin_Page::add_query_args_and_nonce($query_args, $this->_admin_base_url);
2105
+            $this->_views[$key]['url'] = EE_Admin_Page::add_query_args_and_nonce($query_args, $this->_admin_base_url);
2106 2106
         }
2107 2107
         return $this->_views;
2108 2108
     }
@@ -2131,14 +2131,14 @@  discard block
 block discarded – undo
2131 2131
 					<select id="entries-per-page-slct" name="entries-per-page-slct">';
2132 2132
         foreach ($values as $value) {
2133 2133
             if ($value < $max_entries) {
2134
-                $selected                  = $value === $per_page ? ' selected="' . $per_page . '"' : '';
2134
+                $selected = $value === $per_page ? ' selected="'.$per_page.'"' : '';
2135 2135
                 $entries_per_page_dropdown .= '
2136
-						<option value="' . $value . '"' . $selected . '>' . $value . '&nbsp;&nbsp;</option>';
2136
+						<option value="' . $value.'"'.$selected.'>'.$value.'&nbsp;&nbsp;</option>';
2137 2137
             }
2138 2138
         }
2139
-        $selected                  = $max_entries === $per_page ? ' selected="' . $per_page . '"' : '';
2139
+        $selected = $max_entries === $per_page ? ' selected="'.$per_page.'"' : '';
2140 2140
         $entries_per_page_dropdown .= '
2141
-						<option value="' . $max_entries . '"' . $selected . '>All&nbsp;&nbsp;</option>';
2141
+						<option value="' . $max_entries.'"'.$selected.'>All&nbsp;&nbsp;</option>';
2142 2142
         $entries_per_page_dropdown .= '
2143 2143
 					</select>
2144 2144
 					entries
@@ -2162,7 +2162,7 @@  discard block
 block discarded – undo
2162 2162
             empty($this->_search_btn_label) ? $this->page_label
2163 2163
                 : $this->_search_btn_label
2164 2164
         );
2165
-        $this->_template_args['search']['callback']  = 'search_' . $this->page_slug;
2165
+        $this->_template_args['search']['callback'] = 'search_'.$this->page_slug;
2166 2166
     }
2167 2167
 
2168 2168
 
@@ -2223,7 +2223,7 @@  discard block
 block discarded – undo
2223 2223
                                   );
2224 2224
                     throw new EE_Error($error_msg);
2225 2225
                 }
2226
-                unset($this->_route_config['metaboxes'][ $key ]);
2226
+                unset($this->_route_config['metaboxes'][$key]);
2227 2227
             }
2228 2228
         }
2229 2229
     }
@@ -2256,7 +2256,7 @@  discard block
 block discarded – undo
2256 2256
             $total_columns                                       = ! empty($screen_columns)
2257 2257
                 ? $screen_columns
2258 2258
                 : $this->_route_config['columns'][1];
2259
-            $this->_template_args['current_screen_widget_class'] = 'columns-' . $total_columns;
2259
+            $this->_template_args['current_screen_widget_class'] = 'columns-'.$total_columns;
2260 2260
             $this->_template_args['current_page']                = $this->_wp_page_slug;
2261 2261
             $this->_template_args['screen']                      = $this->_current_screen;
2262 2262
             $this->_column_template_path                         = EE_ADMIN_TEMPLATE
@@ -2302,7 +2302,7 @@  discard block
 block discarded – undo
2302 2302
      */
2303 2303
     protected function _espresso_ratings_request()
2304 2304
     {
2305
-        if (! apply_filters('FHEE_show_ratings_request_meta_box', true)) {
2305
+        if ( ! apply_filters('FHEE_show_ratings_request_meta_box', true)) {
2306 2306
             return;
2307 2307
         }
2308 2308
         $ratings_box_title = apply_filters(
@@ -2329,28 +2329,28 @@  discard block
 block discarded – undo
2329 2329
      */
2330 2330
     public function espresso_ratings_request()
2331 2331
     {
2332
-        EEH_Template::display_template(EE_ADMIN_TEMPLATE . 'espresso_ratings_request_content.template.php');
2332
+        EEH_Template::display_template(EE_ADMIN_TEMPLATE.'espresso_ratings_request_content.template.php');
2333 2333
     }
2334 2334
 
2335 2335
 
2336 2336
     public static function cached_rss_display(string $rss_id, string $url): bool
2337 2337
     {
2338
-        $loading   = '<p class="widget-loading hide-if-no-js">'
2338
+        $loading = '<p class="widget-loading hide-if-no-js">'
2339 2339
                      . esc_html__('Loading&#8230;', 'event_espresso')
2340 2340
                      . '</p><p class="hide-if-js">'
2341 2341
                      . esc_html__('This widget requires JavaScript.', 'event_espresso')
2342 2342
                      . '</p>';
2343
-        $pre       = '<div class="espresso-rss-display">' . "\n\t";
2344
-        $pre       .= '<span id="' . esc_attr($rss_id) . '_url" class="hidden">' . esc_url_raw($url) . '</span>';
2345
-        $post      = '</div>' . "\n";
2346
-        $cache_key = 'ee_rss_' . md5($rss_id);
2343
+        $pre       = '<div class="espresso-rss-display">'."\n\t";
2344
+        $pre .= '<span id="'.esc_attr($rss_id).'_url" class="hidden">'.esc_url_raw($url).'</span>';
2345
+        $post      = '</div>'."\n";
2346
+        $cache_key = 'ee_rss_'.md5($rss_id);
2347 2347
         $output    = get_transient($cache_key);
2348 2348
         if ($output !== false) {
2349
-            echo wp_kses($pre . $output . $post, AllowedTags::getWithFormTags());
2349
+            echo wp_kses($pre.$output.$post, AllowedTags::getWithFormTags());
2350 2350
             return true;
2351 2351
         }
2352
-        if (! (defined('DOING_AJAX') && DOING_AJAX)) {
2353
-            echo wp_kses($pre . $loading . $post, AllowedTags::getWithFormTags());
2352
+        if ( ! (defined('DOING_AJAX') && DOING_AJAX)) {
2353
+            echo wp_kses($pre.$loading.$post, AllowedTags::getWithFormTags());
2354 2354
             return false;
2355 2355
         }
2356 2356
         ob_start();
@@ -2417,7 +2417,7 @@  discard block
 block discarded – undo
2417 2417
     public function espresso_sponsors_post_box()
2418 2418
     {
2419 2419
         EEH_Template::display_template(
2420
-            EE_ADMIN_TEMPLATE . 'admin_general_metabox_contents_espresso_sponsors.template.php'
2420
+            EE_ADMIN_TEMPLATE.'admin_general_metabox_contents_espresso_sponsors.template.php'
2421 2421
         );
2422 2422
     }
2423 2423
 
@@ -2434,9 +2434,9 @@  discard block
 block discarded – undo
2434 2434
     protected function getPublishBoxTitle(): string
2435 2435
     {
2436 2436
         $publish_box_title = esc_html__('Publish', 'event_espresso');
2437
-        if (! empty($this->_labels['publishbox'])) {
2437
+        if ( ! empty($this->_labels['publishbox'])) {
2438 2438
             if (is_array($this->_labels['publishbox'])) {
2439
-                $publish_box_title = $this->_labels['publishbox'][ $this->_req_action ] ?? $publish_box_title;
2439
+                $publish_box_title = $this->_labels['publishbox'][$this->_req_action] ?? $publish_box_title;
2440 2440
             } else {
2441 2441
                 $publish_box_title = $this->_labels['publishbox'];
2442 2442
             }
@@ -2486,7 +2486,7 @@  discard block
 block discarded – undo
2486 2486
         // if we have extra content set let's add it in if not make sure its empty
2487 2487
         $this->_template_args['publish_box_extra_content'] = $this->_template_args['publish_box_extra_content'] ?? '';
2488 2488
         echo EEH_Template::display_template(
2489
-            EE_ADMIN_TEMPLATE . 'admin_details_publish_metabox.template.php',
2489
+            EE_ADMIN_TEMPLATE.'admin_details_publish_metabox.template.php',
2490 2490
             $this->_template_args,
2491 2491
             true
2492 2492
         );
@@ -2539,10 +2539,10 @@  discard block
 block discarded – undo
2539 2539
                 'submitdelete deletion button button--outline button--caution'
2540 2540
             );
2541 2541
         }
2542
-        if (! isset($this->_template_args['publish_delete_link'])) {
2542
+        if ( ! isset($this->_template_args['publish_delete_link'])) {
2543 2543
             $this->_template_args['publish_delete_link'] = '';
2544 2544
         }
2545
-        if (! empty($name) && ! empty($id)) {
2545
+        if ( ! empty($name) && ! empty($id)) {
2546 2546
             $this->addPublishPostMetaBoxHiddenFields($name, ['type' => 'hidden', 'value' => $id]);
2547 2547
         }
2548 2548
         $hidden_fields = $this->_generate_admin_form_fields($this->publish_post_meta_box_hidden_fields, 'array');
@@ -2575,7 +2575,7 @@  discard block
 block discarded – undo
2575 2575
 
2576 2576
     protected function addPublishPostMetaBoxHiddenFields(string $field_name, array $field_attributes)
2577 2577
     {
2578
-        $this->publish_post_meta_box_hidden_fields[ $field_name ] = $field_attributes;
2578
+        $this->publish_post_meta_box_hidden_fields[$field_name] = $field_attributes;
2579 2579
     }
2580 2580
 
2581 2581
 
@@ -2677,7 +2677,7 @@  discard block
 block discarded – undo
2677 2677
         }
2678 2678
         // if $create_func is true (default) then we automatically create the function for displaying the actual meta box.  If false then we take the $callback reference passed through and use it instead (so callers can define their own callback function/method if they wish)
2679 2679
         $call_back_func = $create_func
2680
-            ? static function ($post, $metabox) {
2680
+            ? static function($post, $metabox) {
2681 2681
                 echo EEH_Template::display_template(
2682 2682
                     $metabox['args']['template_path'],
2683 2683
                     $metabox['args']['template_args'],
@@ -2686,7 +2686,7 @@  discard block
 block discarded – undo
2686 2686
             }
2687 2687
             : $callback;
2688 2688
         $this->addMetaBox(
2689
-            str_replace('_', '-', $action) . '-mbox',
2689
+            str_replace('_', '-', $action).'-mbox',
2690 2690
             $title,
2691 2691
             $call_back_func,
2692 2692
             $this->_wp_page_slug,
@@ -2802,15 +2802,15 @@  discard block
 block discarded – undo
2802 2802
             'event-espresso_page_espresso_',
2803 2803
             '',
2804 2804
             $this->_wp_page_slug
2805
-        ) . ' ' . $this->_req_action . '-route';
2805
+        ).' '.$this->_req_action.'-route';
2806 2806
 
2807 2807
         $template_path = $sidebar
2808 2808
             ? EE_ADMIN_TEMPLATE . 'admin_details_wrapper.template.php'
2809
-            : EE_ADMIN_TEMPLATE . 'admin_details_wrapper_no_sidebar.template.php';
2809
+            : EE_ADMIN_TEMPLATE.'admin_details_wrapper_no_sidebar.template.php';
2810 2810
 
2811 2811
         $this->_template_args['is_ajax'] = $this->request->isAjax();
2812 2812
         if ($this->request->isAjax()) {
2813
-            $template_path = EE_ADMIN_TEMPLATE . 'admin_details_wrapper_no_sidebar_ajax.template.php';
2813
+            $template_path = EE_ADMIN_TEMPLATE.'admin_details_wrapper_no_sidebar_ajax.template.php';
2814 2814
         }
2815 2815
         $template_path = ! empty($this->_column_template_path) ? $this->_column_template_path : $template_path;
2816 2816
 
@@ -2822,10 +2822,10 @@  discard block
 block discarded – undo
2822 2822
         // to prevent WooCommerce from blowing things up if not using CPT
2823 2823
         global $post_type, $post;
2824 2824
         $this->_template_args['post_type'] = $post_type ?? '';
2825
-        $this->_template_args['post']  = $post ?? new WP_Post((object) [ 'ID' => 0, 'filter' => 'raw' ]);
2825
+        $this->_template_args['post'] = $post ?? new WP_Post((object) ['ID' => 0, 'filter' => 'raw']);
2826 2826
 
2827 2827
         $this->_template_args['post_body_content'] = EEH_Template::display_template(
2828
-            EE_ADMIN_TEMPLATE . 'admin_details_wrapper_post_body_content.template.php',
2828
+            EE_ADMIN_TEMPLATE.'admin_details_wrapper_post_body_content.template.php',
2829 2829
             $this->_template_args,
2830 2830
             true
2831 2831
         );
@@ -2857,11 +2857,11 @@  discard block
 block discarded – undo
2857 2857
     public function display_admin_caf_preview_page(string $utm_campaign_source = '', bool $display_sidebar = true)
2858 2858
     {
2859 2859
         // let's generate a default preview action button if there isn't one already present.
2860
-        $this->_labels['buttons']['buy_now']           = esc_html__(
2860
+        $this->_labels['buttons']['buy_now'] = esc_html__(
2861 2861
             'Upgrade to Event Espresso 4 Right Now',
2862 2862
             'event_espresso'
2863 2863
         );
2864
-        $buy_now_url                                   = add_query_arg(
2864
+        $buy_now_url = add_query_arg(
2865 2865
             [
2866 2866
                 'ee_ver'       => 'ee4',
2867 2867
                 'utm_source'   => 'ee4_plugin_admin',
@@ -2881,8 +2881,8 @@  discard block
 block discarded – undo
2881 2881
                 true
2882 2882
             )
2883 2883
             : $this->_template_args['preview_action_button'];
2884
-        $this->_template_args['admin_page_content']    = EEH_Template::display_template(
2885
-            EE_ADMIN_TEMPLATE . 'admin_caf_full_page_preview.template.php',
2884
+        $this->_template_args['admin_page_content'] = EEH_Template::display_template(
2885
+            EE_ADMIN_TEMPLATE.'admin_caf_full_page_preview.template.php',
2886 2886
             $this->_template_args,
2887 2887
             true
2888 2888
         );
@@ -2940,7 +2940,7 @@  discard block
 block discarded – undo
2940 2940
         // setup search attributes
2941 2941
         $this->_set_search_attributes();
2942 2942
         $this->_template_args['current_page']     = $this->_wp_page_slug;
2943
-        $template_path                            = EE_ADMIN_TEMPLATE . 'admin_list_wrapper.template.php';
2943
+        $template_path                            = EE_ADMIN_TEMPLATE.'admin_list_wrapper.template.php';
2944 2944
         $this->_template_args['table_url']        = $this->request->isAjax()
2945 2945
             ? add_query_arg(['noheader' => 'true', 'route' => $this->_req_action], $this->_admin_base_url)
2946 2946
             : add_query_arg(['route' => $this->_req_action], $this->_admin_base_url);
@@ -2948,10 +2948,10 @@  discard block
 block discarded – undo
2948 2948
         $this->_template_args['current_route']    = $this->_req_action;
2949 2949
         $this->_template_args['list_table_class'] = get_class($this->_list_table_object);
2950 2950
         $ajax_sorting_callback                    = $this->_list_table_object->get_ajax_sorting_callback();
2951
-        if (! empty($ajax_sorting_callback)) {
2951
+        if ( ! empty($ajax_sorting_callback)) {
2952 2952
             $sortable_list_table_form_fields = wp_nonce_field(
2953
-                $ajax_sorting_callback . '_nonce',
2954
-                $ajax_sorting_callback . '_nonce',
2953
+                $ajax_sorting_callback.'_nonce',
2954
+                $ajax_sorting_callback.'_nonce',
2955 2955
                 false,
2956 2956
                 false
2957 2957
             );
@@ -2968,18 +2968,18 @@  discard block
 block discarded – undo
2968 2968
 
2969 2969
         $hidden_form_fields = $this->_template_args['list_table_hidden_fields'] ?? '';
2970 2970
 
2971
-        $nonce_ref          = $this->_req_action . '_nonce';
2971
+        $nonce_ref          = $this->_req_action.'_nonce';
2972 2972
         $hidden_form_fields .= '
2973
-            <input type="hidden" name="' . $nonce_ref . '" value="' . wp_create_nonce($nonce_ref) . '">';
2973
+            <input type="hidden" name="' . $nonce_ref.'" value="'.wp_create_nonce($nonce_ref).'">';
2974 2974
 
2975 2975
         $this->_template_args['list_table_hidden_fields'] = $hidden_form_fields;
2976 2976
         // display message about search results?
2977
-        $search                                    = $this->request->getRequestParam('s');
2977
+        $search = $this->request->getRequestParam('s');
2978 2978
         $this->_template_args['before_list_table'] .= ! empty($search)
2979
-            ? '<p class="ee-search-results">' . sprintf(
2979
+            ? '<p class="ee-search-results">'.sprintf(
2980 2980
                 esc_html__('Displaying search results for the search string: %1$s', 'event_espresso'),
2981 2981
                 trim($search, '%')
2982
-            ) . '</p>'
2982
+            ).'</p>'
2983 2983
             : '';
2984 2984
         // filter before_list_table template arg
2985 2985
         $this->_template_args['before_list_table'] = apply_filters(
@@ -3013,7 +3013,7 @@  discard block
 block discarded – undo
3013 3013
         // convert to array and filter again
3014 3014
         // arrays are easier to inject new items in a specific location,
3015 3015
         // but would not be backwards compatible, so we have to add a new filter
3016
-        $this->_template_args['after_list_table']   = implode(
3016
+        $this->_template_args['after_list_table'] = implode(
3017 3017
             " \n",
3018 3018
             (array) apply_filters(
3019 3019
                 'FHEE__EE_Admin_Page___display_admin_list_table_page__after_list_table__template_args_array',
@@ -3068,7 +3068,7 @@  discard block
 block discarded – undo
3068 3068
             $this->page_slug
3069 3069
         );
3070 3070
         return EEH_Template::display_template(
3071
-            EE_ADMIN_TEMPLATE . 'admin_details_legend.template.php',
3071
+            EE_ADMIN_TEMPLATE.'admin_details_legend.template.php',
3072 3072
             $this->_template_args,
3073 3073
             true
3074 3074
         );
@@ -3191,7 +3191,7 @@  discard block
 block discarded – undo
3191 3191
         if ($this->request->isAjax()) {
3192 3192
             $this->_template_args['admin_page_content'] = EEH_Template::display_template(
3193 3193
             // $template_path,
3194
-                EE_ADMIN_TEMPLATE . 'admin_wrapper_ajax.template.php',
3194
+                EE_ADMIN_TEMPLATE.'admin_wrapper_ajax.template.php',
3195 3195
                 $this->_template_args,
3196 3196
                 true
3197 3197
             );
@@ -3200,7 +3200,7 @@  discard block
 block discarded – undo
3200 3200
         // load settings page wrapper template
3201 3201
         $template_path = $about
3202 3202
             ? EE_ADMIN_TEMPLATE . 'about_admin_wrapper.template.php'
3203
-            : EE_ADMIN_TEMPLATE . 'admin_wrapper.template.php';
3203
+            : EE_ADMIN_TEMPLATE.'admin_wrapper.template.php';
3204 3204
 
3205 3205
         EEH_Template::display_template($template_path, $this->_template_args);
3206 3206
     }
@@ -3284,12 +3284,12 @@  discard block
 block discarded – undo
3284 3284
         $default_names = ['save', 'save_and_close'];
3285 3285
         $buttons       = '';
3286 3286
         foreach ($button_text as $key => $button) {
3287
-            $ref     = $default_names[ $key ];
3288
-            $name    = ! empty($actions) ? $actions[ $key ] : $ref;
3289
-            $buttons .= '<input type="submit" class="button button--primary ' . $ref . '" '
3290
-                        . 'value="' . $button . '" name="' . $name . '" '
3291
-                        . 'id="' . $this->_current_view . '_' . $ref . '" />';
3292
-            if (! $both) {
3287
+            $ref     = $default_names[$key];
3288
+            $name    = ! empty($actions) ? $actions[$key] : $ref;
3289
+            $buttons .= '<input type="submit" class="button button--primary '.$ref.'" '
3290
+                        . 'value="'.$button.'" name="'.$name.'" '
3291
+                        . 'id="'.$this->_current_view.'_'.$ref.'" />';
3292
+            if ( ! $both) {
3293 3293
                 break;
3294 3294
             }
3295 3295
         }
@@ -3330,13 +3330,13 @@  discard block
 block discarded – undo
3330 3330
                 'An error occurred. No action was set for this page\'s form.',
3331 3331
                 'event_espresso'
3332 3332
             );
3333
-            $dev_msg  = $user_msg . "\n"
3333
+            $dev_msg = $user_msg."\n"
3334 3334
                         . sprintf(
3335 3335
                             esc_html__('The $route argument is required for the %s->%s method.', 'event_espresso'),
3336 3336
                             __FUNCTION__,
3337 3337
                             __CLASS__
3338 3338
                         );
3339
-            EE_Error::add_error($user_msg . '||' . $dev_msg, __FILE__, __FUNCTION__, __LINE__);
3339
+            EE_Error::add_error($user_msg.'||'.$dev_msg, __FILE__, __FUNCTION__, __LINE__);
3340 3340
         }
3341 3341
         // open form
3342 3342
         $action                                            = $this->_admin_base_url;
@@ -3344,9 +3344,9 @@  discard block
 block discarded – undo
3344 3344
             <form name='form' method='post' action='$action' id='{$route}_event_form' class='ee-admin-page-form' >
3345 3345
             ";
3346 3346
         // add nonce
3347
-        $nonce                                             =
3348
-            wp_nonce_field($route . '_nonce', $route . '_nonce', false, false);
3349
-        $this->_template_args['before_admin_page_content'] .= "\n\t" . $nonce;
3347
+        $nonce =
3348
+            wp_nonce_field($route.'_nonce', $route.'_nonce', false, false);
3349
+        $this->_template_args['before_admin_page_content'] .= "\n\t".$nonce;
3350 3350
         // add REQUIRED form action
3351 3351
         $hidden_fields = [
3352 3352
             'action' => ['type' => 'hidden', 'value' => $route],
@@ -3359,7 +3359,7 @@  discard block
 block discarded – undo
3359 3359
         $form_fields = $this->_generate_admin_form_fields($hidden_fields, 'array');
3360 3360
         // add fields to form
3361 3361
         foreach ((array) $form_fields as $form_field) {
3362
-            $this->_template_args['before_admin_page_content'] .= "\n\t" . $form_field['field'];
3362
+            $this->_template_args['before_admin_page_content'] .= "\n\t".$form_field['field'];
3363 3363
         }
3364 3364
         // close form
3365 3365
         $this->_template_args['after_admin_page_content'] = '</form>';
@@ -3442,10 +3442,10 @@  discard block
 block discarded – undo
3442 3442
     ) {
3443 3443
         $notices = EE_Error::get_notices(false);
3444 3444
         // overwrite default success messages //BUT ONLY if overwrite not overridden
3445
-        if (! $override_overwrite || ! empty($notices['errors'])) {
3445
+        if ( ! $override_overwrite || ! empty($notices['errors'])) {
3446 3446
             EE_Error::overwrite_success();
3447 3447
         }
3448
-        if (! $override_overwrite && ! empty($what) && ! empty($action_desc) && empty($notices['errors'])) {
3448
+        if ( ! $override_overwrite && ! empty($what) && ! empty($action_desc) && empty($notices['errors'])) {
3449 3449
             // how many records affected ? more than one record ? or just one ?
3450 3450
             EE_Error::add_success(
3451 3451
                 sprintf(
@@ -3496,7 +3496,7 @@  discard block
 block discarded – undo
3496 3496
             $redirect_url = admin_url('admin.php');
3497 3497
         }
3498 3498
         // merge any default query_args set in _default_route_query_args property
3499
-        if (! empty($this->_default_route_query_args) && ! $this->_is_UI_request) {
3499
+        if ( ! empty($this->_default_route_query_args) && ! $this->_is_UI_request) {
3500 3500
             $args_to_merge = [];
3501 3501
             foreach ($this->_default_route_query_args as $query_param => $query_value) {
3502 3502
                 // is there a wp_referer array in our _default_route_query_args property?
@@ -3508,15 +3508,15 @@  discard block
 block discarded – undo
3508 3508
                         }
3509 3509
                         // finally we will override any arguments in the referer with
3510 3510
                         // what might be set on the _default_route_query_args array.
3511
-                        if (isset($this->_default_route_query_args[ $reference ])) {
3512
-                            $args_to_merge[ $reference ] = urlencode($this->_default_route_query_args[ $reference ]);
3511
+                        if (isset($this->_default_route_query_args[$reference])) {
3512
+                            $args_to_merge[$reference] = urlencode($this->_default_route_query_args[$reference]);
3513 3513
                         } else {
3514
-                            $args_to_merge[ $reference ] = urlencode($value);
3514
+                            $args_to_merge[$reference] = urlencode($value);
3515 3515
                         }
3516 3516
                     }
3517 3517
                     continue;
3518 3518
                 }
3519
-                $args_to_merge[ $query_param ] = $query_value;
3519
+                $args_to_merge[$query_param] = $query_value;
3520 3520
             }
3521 3521
             // now let's merge these arguments but override with what was specifically sent in to the
3522 3522
             // redirect.
@@ -3528,19 +3528,19 @@  discard block
 block discarded – undo
3528 3528
         if (isset($query_args['action'])) {
3529 3529
             // manually generate wp_nonce and merge that with the query vars
3530 3530
             // becuz the wp_nonce_url function wrecks havoc on some vars
3531
-            $query_args['_wpnonce'] = wp_create_nonce($query_args['action'] . '_nonce');
3531
+            $query_args['_wpnonce'] = wp_create_nonce($query_args['action'].'_nonce');
3532 3532
         }
3533 3533
         // we're adding some hooks and filters in here for processing any things just before redirects
3534 3534
         // (example: an admin page has done an insert or update and we want to run something after that).
3535
-        do_action('AHEE_redirect_' . $this->class_name . $this->_req_action, $query_args);
3535
+        do_action('AHEE_redirect_'.$this->class_name.$this->_req_action, $query_args);
3536 3536
         $redirect_url = apply_filters(
3537
-            'FHEE_redirect_' . $this->class_name . $this->_req_action,
3537
+            'FHEE_redirect_'.$this->class_name.$this->_req_action,
3538 3538
             EE_Admin_Page::add_query_args_and_nonce($query_args, $redirect_url),
3539 3539
             $query_args
3540 3540
         );
3541 3541
         // check if we're doing ajax.  If we are then lets just return the results and js can handle how it wants.
3542 3542
         if ($this->request->isAjax()) {
3543
-            $default_data                    = [
3543
+            $default_data = [
3544 3544
                 'close'        => true,
3545 3545
                 'redirect_url' => $redirect_url,
3546 3546
                 'where'        => 'main',
@@ -3593,7 +3593,7 @@  discard block
 block discarded – undo
3593 3593
         }
3594 3594
         $this->_template_args['notices'] = EE_Error::get_notices();
3595 3595
         // IF this isn't ajax we need to create a transient for the notices using the route (however, overridden if $sticky_notices == true)
3596
-        if (! $this->request->isAjax() || $sticky_notices) {
3596
+        if ( ! $this->request->isAjax() || $sticky_notices) {
3597 3597
             $route = $query_args['action'] ?? 'default';
3598 3598
             $this->_add_transient(
3599 3599
                 $route,
@@ -3633,7 +3633,7 @@  discard block
 block discarded – undo
3633 3633
         bool $exclude_nonce = false
3634 3634
     ): string {
3635 3635
         // first let's validate the action (if $base_url is FALSE otherwise validation will happen further along)
3636
-        if (empty($base_url) && ! isset($this->_page_routes[ $action ])) {
3636
+        if (empty($base_url) && ! isset($this->_page_routes[$action])) {
3637 3637
             throw new EE_Error(
3638 3638
                 sprintf(
3639 3639
                     esc_html__(
@@ -3644,7 +3644,7 @@  discard block
 block discarded – undo
3644 3644
                 )
3645 3645
             );
3646 3646
         }
3647
-        if (! isset($this->_labels['buttons'][ $type ])) {
3647
+        if ( ! isset($this->_labels['buttons'][$type])) {
3648 3648
             throw new EE_Error(
3649 3649
                 sprintf(
3650 3650
                     esc_html__(
@@ -3657,7 +3657,7 @@  discard block
 block discarded – undo
3657 3657
         }
3658 3658
         // finally check user access for this button.
3659 3659
         $has_access = $this->check_user_access($action, true);
3660
-        if (! $has_access) {
3660
+        if ( ! $has_access) {
3661 3661
             return '';
3662 3662
         }
3663 3663
         $_base_url  = ! $base_url ? $this->_admin_base_url : $base_url;
@@ -3665,11 +3665,11 @@  discard block
 block discarded – undo
3665 3665
             'action' => $action,
3666 3666
         ];
3667 3667
         // merge extra_request args but make sure our original action takes precedence and doesn't get overwritten.
3668
-        if (! empty($extra_request)) {
3668
+        if ( ! empty($extra_request)) {
3669 3669
             $query_args = array_merge($extra_request, $query_args);
3670 3670
         }
3671 3671
         $url = EE_Admin_Page::add_query_args_and_nonce($query_args, $_base_url, false, $exclude_nonce);
3672
-        return EEH_Template::get_button_or_link($url, $this->_labels['buttons'][ $type ], $class);
3672
+        return EEH_Template::get_button_or_link($url, $this->_labels['buttons'][$type], $class);
3673 3673
     }
3674 3674
 
3675 3675
 
@@ -3695,7 +3695,7 @@  discard block
 block discarded – undo
3695 3695
                 'FHEE__EE_Admin_Page___per_page_screen_options__default',
3696 3696
                 20
3697 3697
             ),
3698
-            'option'  => $this->_current_page . '_' . $this->_current_view . '_per_page',
3698
+            'option'  => $this->_current_page.'_'.$this->_current_view.'_per_page',
3699 3699
         ];
3700 3700
         // ONLY add the screen option if the user has access to it.
3701 3701
         if ($this->check_user_access($this->_current_view, true)) {
@@ -3716,18 +3716,18 @@  discard block
 block discarded – undo
3716 3716
     {
3717 3717
         if ($this->request->requestParamIsSet('wp_screen_options')) {
3718 3718
             check_admin_referer('screen-options-nonce', 'screenoptionnonce');
3719
-            if (! $user = wp_get_current_user()) {
3719
+            if ( ! $user = wp_get_current_user()) {
3720 3720
                 return;
3721 3721
             }
3722 3722
             $option = $this->request->getRequestParam('wp_screen_options[option]', '', DataType::KEY);
3723
-            if (! $option) {
3723
+            if ( ! $option) {
3724 3724
                 return;
3725 3725
             }
3726 3726
             $value      = $this->request->getRequestParam('wp_screen_options[value]', 0, DataType::INT);
3727 3727
             $map_option = $option;
3728 3728
             $option     = str_replace('-', '_', $option);
3729 3729
             switch ($map_option) {
3730
-                case $this->_current_page . '_' . $this->_current_view . '_per_page':
3730
+                case $this->_current_page.'_'.$this->_current_view.'_per_page':
3731 3731
                     $max_value = apply_filters(
3732 3732
                         'FHEE__EE_Admin_Page___set_per_page_screen_options__max_value',
3733 3733
                         999,
@@ -3794,7 +3794,7 @@  discard block
 block discarded – undo
3794 3794
         bool $skip_route_verify = false
3795 3795
     ) {
3796 3796
         $user_id = get_current_user_id();
3797
-        if (! $skip_route_verify) {
3797
+        if ( ! $skip_route_verify) {
3798 3798
             $this->_verify_route($route);
3799 3799
         }
3800 3800
         // now let's set the string for what kind of transient we're setting
@@ -3827,8 +3827,8 @@  discard block
 block discarded – undo
3827 3827
         $user_id   = get_current_user_id();
3828 3828
         $route     = ! $route ? $this->_req_action : $route;
3829 3829
         $transient = $notices
3830
-            ? 'ee_rte_n_tx_' . $route . '_' . $user_id
3831
-            : 'rte_tx_' . $route . '_' . $user_id;
3830
+            ? 'ee_rte_n_tx_'.$route.'_'.$user_id
3831
+            : 'rte_tx_'.$route.'_'.$user_id;
3832 3832
         $data      = is_multisite() && is_network_admin()
3833 3833
             ? get_site_transient($transient)
3834 3834
             : get_transient($transient);
@@ -4088,7 +4088,7 @@  discard block
 block discarded – undo
4088 4088
      */
4089 4089
     protected function _next_link(string $url, string $class = 'dashicons dashicons-arrow-right'): string
4090 4090
     {
4091
-        return '<a class="' . $class . '" href="' . $url . '"></a>';
4091
+        return '<a class="'.$class.'" href="'.$url.'"></a>';
4092 4092
     }
4093 4093
 
4094 4094
 
@@ -4101,7 +4101,7 @@  discard block
 block discarded – undo
4101 4101
      */
4102 4102
     protected function _previous_link(string $url, string $class = 'dashicons dashicons-arrow-left'): string
4103 4103
     {
4104
-        return '<a class="' . $class . '" href="' . $url . '"></a>';
4104
+        return '<a class="'.$class.'" href="'.$url.'"></a>';
4105 4105
     }
4106 4106
 
4107 4107
 
@@ -4249,13 +4249,13 @@  discard block
 block discarded – undo
4249 4249
         ?callable $callback = null
4250 4250
     ): bool {
4251 4251
         $entity_ID = absint($entity_ID);
4252
-        if (! $entity_ID) {
4252
+        if ( ! $entity_ID) {
4253 4253
             $this->trashRestoreDeleteError($action, $entity_model);
4254 4254
         }
4255 4255
         $result = 0;
4256 4256
         try {
4257 4257
             $entity = $entity_model->get_one_by_ID($entity_ID);
4258
-            if (! $entity instanceof EE_Base_Class) {
4258
+            if ( ! $entity instanceof EE_Base_Class) {
4259 4259
                 throw new DomainException(
4260 4260
                     sprintf(
4261 4261
                         esc_html__(
@@ -4306,7 +4306,7 @@  discard block
 block discarded – undo
4306 4306
                 )
4307 4307
             );
4308 4308
         }
4309
-        if (! $entity_model->has_field($delete_column)) {
4309
+        if ( ! $entity_model->has_field($delete_column)) {
4310 4310
             throw new DomainException(
4311 4311
                 sprintf(
4312 4312
                     esc_html__(
Please login to merge, or discard this patch.
core/libraries/plugin_api/EE_Register_Addon.lib.php 1 patch
Indentation   +1256 added lines, -1256 removed lines patch added patch discarded remove patch
@@ -24,1260 +24,1260 @@
 block discarded – undo
24 24
  */
25 25
 class EE_Register_Addon implements EEI_Plugin_API
26 26
 {
27
-    /**
28
-     * possibly truncated version of the EE core version string
29
-     *
30
-     * @var string
31
-     */
32
-    protected static $_core_version = '';
33
-
34
-    /**
35
-     * Holds values for registered addons
36
-     *
37
-     * @var array
38
-     */
39
-    protected static $_settings = [];
40
-
41
-    /**
42
-     * @var  array $_incompatible_addons keys are addon SLUGS
43
-     *                                   (first argument passed to EE_Register_Addon::register()), keys are
44
-     *                                   their MINIMUM VERSION (with all 5 parts. Eg 1.2.3.rc.004).
45
-     *                                   Generally this should be used sparingly, as we don't want to muddle up
46
-     *                                   EE core with knowledge of ALL the addons out there.
47
-     *                                   If you want NO versions of an addon to run with a certain version of core,
48
-     *                                   it's usually best to define the addon's "min_core_version" as part of its call
49
-     *                                   to EE_Register_Addon::register(), rather than using this array with a super
50
-     *                                   high value for its minimum plugin version.
51
-     */
52
-    protected static $_incompatible_addons = [
53
-        'Multi_Event_Registration' => '2.0.11.rc.002',
54
-        'Promotions'               => '1.0.0.rc.084',
55
-        'EE_WPUsers'               => '2.1.3.p',
56
-    ];
57
-
58
-    /**
59
-     * @var LoaderInterface
60
-     */
61
-    protected static $loader;
62
-
63
-
64
-    /**
65
-     * We should always be comparing core to a version like '4.3.0.rc.000',
66
-     * not just '4.3.0'.
67
-     * So if the addon developer doesn't provide that full version string,
68
-     * fill in the blanks for them
69
-     *
70
-     * @param string $min_core_version
71
-     * @return string always like '4.3.0.rc.000'
72
-     */
73
-    protected static function _effective_version(string $min_core_version): string
74
-    {
75
-        // versions: 4 . 3 . 1 . p . 123
76
-        // offsets:    0 . 1 . 2 . 3 . 4
77
-        $version_parts = explode('.', $min_core_version);
78
-        // check they specified the micro version (after 2nd period)
79
-        if (! isset($version_parts[2])) {
80
-            $version_parts[2] = '0';
81
-        }
82
-        // if they didn't specify the 'p', or 'rc' part. Just assume the lowest possible
83
-        // soon we can assume that's 'rc', but this current version is 'alpha'
84
-        if (! isset($version_parts[3])) {
85
-            $version_parts[3] = 'dev';
86
-        }
87
-        if (! isset($version_parts[4])) {
88
-            $version_parts[4] = '000';
89
-        }
90
-        return implode('.', $version_parts);
91
-    }
92
-
93
-
94
-    /**
95
-     * Returns whether or not the min core version requirement of the addon is met
96
-     *
97
-     * @param string $min_core_version    the minimum core version required by the addon
98
-     * @param string $actual_core_version the actual core version, optional
99
-     * @return bool
100
-     */
101
-    public static function _meets_min_core_version_requirement(
102
-        string $min_core_version,
103
-        string $actual_core_version = EVENT_ESPRESSO_VERSION
104
-    ): bool {
105
-        return version_compare(
106
-            self::_effective_version($actual_core_version),
107
-            self::_effective_version($min_core_version),
108
-            '>='
109
-        );
110
-    }
111
-
112
-
113
-    /**
114
-     * Method for registering new EE_Addons.
115
-     * Should be called AFTER AHEE__EE_System__load_espresso_addons but BEFORE
116
-     * AHEE__EE_System___detect_if_activation_or_upgrade__begin in order to register all its components. However, it
117
-     * may also be called after the 'activate_plugin' action (when an addon is activated), because an activating addon
118
-     * won't be loaded by WP until after AHEE__EE_System__load_espresso_addons has fired. If its called after
119
-     * 'activate_plugin', it registers the addon still, but its components are not registered
120
-     * (they shouldn't be needed anyways, because it's just an activation request and they won't have a chance to do
121
-     * anything anyways). Instead, it just sets the newly-activated addon's activation indicator wp option and returns
122
-     * (so that we can detect that the addon has activated on the subsequent request)
123
-     *
124
-     * @param string                  $addon_name                       [Required] the EE_Addon's name.
125
-     * @param array                   $setup_args                       {
126
-     *                                                                  An array of arguments provided for registering
127
-     *                                                                  the message type.
128
-     * @type  string                  $class_name                       the addon's main file name.
129
-     *                                                                  If left blank, generated from the addon name,
130
-     *                                                                  changes something like "calendar" to
131
-     *                                                                  "EE_Calendar"
132
-     * @type string                   $min_core_version                 the minimum version of EE Core that the
133
-     *                                                                  addon will work with. eg "4.8.1.rc.084"
134
-     * @type string                   $version                          the "software" version for the addon. eg
135
-     *                                                                  "1.0.0.p" for a first stable release, or
136
-     *                                                                  "1.0.0.rc.043" for a version in progress
137
-     * @type string                   $main_file_path                   the full server path to the main file
138
-     *                                                                  loaded directly by WP
139
-     * @type DomainInterface          $domain                           child class of
140
-     *                                                                  EventEspresso\core\domain\DomainBase
141
-     * @type string                   $domain_fqcn                      Fully Qualified Class Name
142
-     *                                                                  for the addon's Domain class
143
-     *                                                                  (see EventEspresso\core\domain\Domain)
144
-     * @type string                   $admin_path                       full server path to the folder where the
145
-     *                                                                  addon\'s admin files reside
146
-     * @type string                   $admin_callback                   a method to be called when the EE Admin is
147
-     *                                                                  first invoked, can be used for hooking into
148
-     *                                                                  any admin page
149
-     * @type string                   $config_section                   the section name for this addon's
150
-     *                                                                  configuration settings section
151
-     *                                                                  (defaults to "addons")
152
-     * @type string                   $config_class                     the class name for this addon's
153
-     *                                                                  configuration settings object
154
-     * @type string                   $config_name                      the class name for this addon's
155
-     *                                                                  configuration settings object
156
-     * @type string                   $autoloader_paths                 [Required] an array of class names and the full
157
-     *                                                                  server paths to those files.
158
-     * @type string                   $autoloader_folders               an array of  "full server paths" for any
159
-     *                                                                  folders containing classes that might be
160
-     *                                                                  invoked by the addon
161
-     * @type string                   $dms_paths                        [Required] an array of full server paths to
162
-     *                                                                  folders that contain data migration scripts.
163
-     *                                                                  The key should be the EE_Addon class name that
164
-     *                                                                  this set of data migration scripts belongs to.
165
-     *                                                                  If the EE_Addon class is namespaced, then this
166
-     *                                                                  needs to be the Fully Qualified Class Name
167
-     * @type string                   $module_paths                     an array of full server paths to any
168
-     *                                                                  EED_Modules used by the addon
169
-     * @type string                   $shortcode_paths                  an array of full server paths to folders
170
-     *                                                                  that contain EES_Shortcodes
171
-     * @type string                   $widget_paths                     an array of full server paths to folders
172
-     *                                                                  that contain WP_Widgets
173
-     * @type array                    $capabilities                     an array indexed by role name
174
-     *                                                                  (i.e administrator,author ) and the values
175
-     *                                                                  are an array of caps to add to the role.
176
-     *                                                                  'administrator' => array(
177
-     *                                                                  'read_addon',
178
-     *                                                                  'edit_addon',
179
-     *                                                                  etc.
180
-     *                                                                  ).
181
-     * @type EE_Meta_Capability_Map[] $capability_maps                  an array of EE_Meta_Capability_Map object
182
-     *                                                                  for any addons that need to register any
183
-     *                                                                  special meta mapped capabilities.  Should
184
-     *                                                                  be indexed where the key is the
185
-     *                                                                  EE_Meta_Capability_Map class name and the
186
-     *                                                                  values are the arguments sent to the class.
187
-     * @type array                    $model_paths                      array of folders containing DB models
188
-     * @return bool
189
-     * @throws DomainException
190
-     * @throws EE_Error
191
-     * @throws InvalidArgumentException
192
-     * @throws InvalidDataTypeException
193
-     * @throws InvalidInterfaceException
194
-     * @since                                                           4.3.0
195
-     * @see                                                             EE_Register_Model
196
-     * @type array                    $class_paths                      array of folders containing DB classes
197
-     * @see                                                             EE_Register_Model
198
-     * @type array                    $model_extension_paths            array of folders containing DB model
199
-     *                                                                  extensions
200
-     * @see                                                             EE_Register_Model_Extension
201
-     * @type array                    $class_extension_paths            array of folders containing DB class
202
-     *                                                                  extensions
203
-     * @see                                                             EE_Register_Model_Extension
204
-     * @type array message_types {
205
-     *                                                                  An array of message types with the key as
206
-     *                                                                  the message type name and the values as
207
-     *                                                                  below:
208
-     * @type string                   $mtfilename                       [Required] The filename of the message type
209
-     *                                                                  being registered. This will be the main
210
-     *                                                                  EE_{Message Type Name}_message_type class.
211
-     *                                                                  for example:
212
-     *                                                                  EE_Declined_Registration_message_type.class.php
213
-     * @type array                    $autoloadpaths                    [Required] An array of paths to add to the
214
-     *                                                                  messages autoloader for the new message type.
215
-     * @type array                    $messengers_to_activate_with      An array of messengers that this message
216
-     *                                                                  type should activate with. Each value in
217
-     *                                                                  the
218
-     *                                                                  array
219
-     *                                                                  should match the name property of a
220
-     *                                                                  EE_messenger. Optional.
221
-     * @type array                    $messengers_to_validate_with      An array of messengers that this message
222
-     *                                                                  type should validate with. Each value in
223
-     *                                                                  the
224
-     *                                                                  array
225
-     *                                                                  should match the name property of an
226
-     *                                                                  EE_messenger.
227
-     *                                                                  Optional.
228
-     *                                                                  }
229
-     * @type array                    $custom_post_types
230
-     * @type array                    $custom_taxonomies
231
-     * @type array                    $payment_method_paths             each element is the folder containing the
232
-     *                                                                  EE_PMT_Base child class
233
-     *                                                                  (eg,
234
-     *                                                                  '/wp-content/plugins/my_plugin/Payomatic/'
235
-     *                                                                  which contains the files
236
-     *                                                                  EE_PMT_Payomatic.pm.php)
237
-     * @type array                    $default_terms
238
-     * @type array                    $namespace                        {
239
-     *                                                                  An array with two items for registering the
240
-     *                                                                  addon's namespace. (If, for some reason, you
241
-     *                                                                  require additional namespaces,
242
-     *                                                                  use
243
-     *                                                                  EventEspresso\core\Psr4Autoloader::addNamespace()
244
-     *                                                                  directly)
245
-     * @see                                                             EventEspresso\core\Psr4Autoloader::addNamespace()
246
-     * @type string                   $FQNS                             the namespace prefix
247
-     * @type string                   $DIR                              a base directory for class files in the
248
-     *                                                                  namespace.
249
-     *                                                                  }
250
-     *                                                                  }
251
-     * @type string                   $privacy_policies                 FQNSs (namespaces, each of which contains only
252
-     *                                                                  privacy policy classes) or FQCNs (specific
253
-     *                                                                  classnames of privacy policy classes)
254
-     * @type string                   $personal_data_exporters          FQNSs (namespaces, each of which contains only
255
-     *                                                                  privacy policy classes) or FQCNs (specific
256
-     *                                                                  classnames of privacy policy classes)
257
-     * @type string                   $personal_data_erasers            FQNSs (namespaces, each of which contains only
258
-     *                                                                  privacy policy classes) or FQCNs (specific
259
-     *                                                                  classnames of privacy policy classes)
260
-     */
261
-    public static function register(string $addon_name = '', array $setup_args = []): bool
262
-    {
263
-        // $addon_name = basename($addon_name);
264
-        if (! self::$loader instanceof LoaderInterface) {
265
-            self::$loader = LoaderFactory::getLoader();
266
-        }
267
-        // make sure this was called in the right place!
268
-        if (
269
-            ! did_action('activate_plugin')
270
-            && (
271
-                ! did_action('AHEE__EE_System__load_espresso_addons')
272
-                || did_action('AHEE__EE_System___detect_if_activation_or_upgrade__begin')
273
-            )
274
-        ) {
275
-            EE_Error::doing_it_wrong(
276
-                __METHOD__,
277
-                sprintf(
278
-                    esc_html__(
279
-                        'An attempt to register an EE_Addon named "%s" has failed because it was not registered at the correct time.  Please use the "AHEE__EE_System__load_espresso_addons" hook to register addons.',
280
-                        'event_espresso'
281
-                    ),
282
-                    $addon_name
283
-                ),
284
-                '4.3.0'
285
-            );
286
-            return false;
287
-        }
288
-        // required fields MUST be present, so let's make sure they are.
289
-        EE_Register_Addon::_verify_parameters($addon_name, $setup_args);
290
-        // get class name for addon
291
-        $class_name = EE_Register_Addon::_parse_class_name($addon_name, $setup_args);
292
-        // setup $_settings array from incoming values.
293
-        $addon_settings = EE_Register_Addon::_get_addon_settings($class_name, $setup_args);
294
-        // allow early addon setup or modification of addon api settings
295
-        self::$_settings = (array) apply_filters(
296
-            'FHEE__EE_Register_Addon__register',
297
-            self::$_settings,
298
-            $addon_name,
299
-            $class_name,
300
-            $setup_args
301
-        );
302
-        // does this addon work with this version of core or WordPress ?
303
-        // does this addon work with this version of core or WordPress ?
304
-        if (! EE_Register_Addon::_addon_is_compatible($addon_name, $addon_settings)) {
305
-            return false;
306
-        }
307
-        // register namespaces
308
-        EE_Register_Addon::_setup_namespaces($addon_settings);
309
-        // check if this is an activation request
310
-        if (EE_Register_Addon::_addon_activation($addon_name, $addon_settings)) {
311
-            // dont bother setting up the rest of the addon atm
312
-            return false;
313
-        }
314
-        // we need cars
315
-        EE_Register_Addon::_setup_autoloaders($addon_name);
316
-        // register new models and extensions
317
-        EE_Register_Addon::_register_models_and_extensions($addon_name);
318
-        // setup DMS
319
-        EE_Register_Addon::_register_data_migration_scripts($addon_name);
320
-        // if config_class is present let's register config.
321
-        EE_Register_Addon::_register_config($addon_name);
322
-        // register admin pages
323
-        EE_Register_Addon::_register_admin_pages($addon_name);
324
-        // add to list of modules to be registered
325
-        EE_Register_Addon::_register_modules($addon_name);
326
-        // add to list of shortcodes to be registered
327
-        EE_Register_Addon::_register_shortcodes($addon_name);
328
-        // add to list of widgets to be registered
329
-        EE_Register_Addon::_register_widgets($addon_name);
330
-        // register capability related stuff.
331
-        EE_Register_Addon::_register_capabilities($addon_name);
332
-        // any message type to register?
333
-        EE_Register_Addon::_register_message_types($addon_name);
334
-        // any custom post type/ custom capabilities or default terms to register
335
-        EE_Register_Addon::_register_custom_post_types($addon_name);
336
-        // and any payment methods
337
-        EE_Register_Addon::_register_payment_methods($addon_name);
338
-        // and privacy policy generators
339
-        EE_Register_Addon::registerPrivacyPolicies($addon_name);
340
-        // and privacy policy generators
341
-        EE_Register_Addon::registerPersonalDataExporters($addon_name);
342
-        // and privacy policy generators
343
-        EE_Register_Addon::registerPersonalDataErasers($addon_name);
344
-        EE_Register_Addon::registerLicense($addon_name);
345
-        // load and instantiate main addon class
346
-        $addon = EE_Register_Addon::_load_and_init_addon_class($addon_name);
347
-        // delay calling after_registration hook on each addon until after all add-ons have been registered.
348
-        add_action('AHEE__EE_System__load_espresso_addons__complete', [$addon, 'after_registration'], 999);
349
-        return $addon instanceof EE_Addon;
350
-    }
351
-
352
-
353
-    /**
354
-     * @param string $addon_name
355
-     * @param array  $setup_args
356
-     * @return void
357
-     * @throws EE_Error
358
-     */
359
-    private static function _verify_parameters(string $addon_name, array $setup_args)
360
-    {
361
-        // required fields MUST be present, so let's make sure they are.
362
-        if (empty($addon_name) || empty($setup_args)) {
363
-            throw new EE_Error(
364
-                esc_html__(
365
-                    'In order to register an EE_Addon with EE_Register_Addon::register(), you must include the "addon_name" (the name of the addon), and an array of arguments.',
366
-                    'event_espresso'
367
-                )
368
-            );
369
-        }
370
-        if (empty($setup_args['main_file_path'])) {
371
-            throw new EE_Error(
372
-                sprintf(
373
-                    esc_html__(
374
-                        'When registering an addon, you didn\'t provide the "main_file_path", which is the full path to the main file loaded directly by Wordpress. You only provided %s',
375
-                        'event_espresso'
376
-                    ),
377
-                    implode(',', array_keys($setup_args))
378
-                )
379
-            );
380
-        }
381
-        // check that addon has not already been registered with that name
382
-        if (isset(self::$_settings[ $addon_name ]) && ! did_action('activate_plugin')) {
383
-            throw new EE_Error(
384
-                sprintf(
385
-                    esc_html__(
386
-                        'An EE_Addon with the name "%s" has already been registered and each EE_Addon requires a unique name.',
387
-                        'event_espresso'
388
-                    ),
389
-                    $addon_name
390
-                )
391
-            );
392
-        }
393
-    }
394
-
395
-
396
-    /**
397
-     * @param string $addon_name
398
-     * @param array  $setup_args
399
-     * @return string
400
-     */
401
-    private static function _parse_class_name(string $addon_name, array $setup_args): string
402
-    {
403
-        if (empty($setup_args['class_name'])) {
404
-            // generate one by first separating name with spaces
405
-            $class_name = str_replace(['-', '_'], ' ', trim($addon_name));
406
-            // capitalize, then replace spaces with underscores
407
-            $class_name = str_replace(' ', '_', ucwords($class_name));
408
-        } else {
409
-            $class_name = $setup_args['class_name'];
410
-        }
411
-        // check if classname is fully  qualified or is a legacy classname already prefixed with 'EE_'
412
-        return strpos($class_name, '\\') || strpos($class_name, 'EE_') === 0
413
-            ? $class_name
414
-            : 'EE_' . $class_name;
415
-    }
416
-
417
-
418
-    /**
419
-     * @param string $class_name
420
-     * @param array  $setup_args
421
-     * @return array
422
-     */
423
-    private static function _get_addon_settings(string $class_name, array $setup_args): array
424
-    {
425
-        // setup $_settings array from incoming values.
426
-        $addon_settings = [
427
-            // generated from the addon name, changes something like "calendar" to "EE_Calendar"
428
-            'class_name'            => $class_name,
429
-            // the addon slug for use in URLs, etc
430
-            'plugin_slug'           => isset($setup_args['plugin_slug'])
431
-                ? (string) $setup_args['plugin_slug']
432
-                : sanitize_key($class_name),
433
-            // page slug to be used when generating the "Settings" link on the WP plugin page
434
-            'plugin_action_slug'    => isset($setup_args['plugin_action_slug'])
435
-                ? (string) $setup_args['plugin_action_slug']
436
-                : '',
437
-            // the "software" version for the addon
438
-            'version'               => isset($setup_args['version'])
439
-                ? (string) $setup_args['version']
440
-                : '',
441
-            // the minimum version of EE Core that the addon will work with
442
-            'min_core_version'      => isset($setup_args['min_core_version'])
443
-                ? (string) $setup_args['min_core_version']
444
-                : '',
445
-            // the minimum version of WordPress that the addon will work with
446
-            'min_wp_version'        => isset($setup_args['min_wp_version'])
447
-                ? (string) $setup_args['min_wp_version']
448
-                : EE_MIN_WP_VER_REQUIRED,
449
-            // full server path to main file (file loaded directly by WP)
450
-            'main_file_path'        => isset($setup_args['main_file_path'])
451
-                ? (string) $setup_args['main_file_path']
452
-                : '',
453
-            // instance of \EventEspresso\core\domain\DomainInterface
454
-            'domain'                => isset($setup_args['domain']) && $setup_args['domain'] instanceof DomainInterface
455
-                ? $setup_args['domain']
456
-                : null,
457
-            // Fully Qualified Class Name for the addon's Domain class
458
-            'domain_fqcn'           => isset($setup_args['domain_fqcn'])
459
-                ? (string) $setup_args['domain_fqcn']
460
-                : '',
461
-            // path to folder containing files for integrating with the EE core admin and/or setting up EE admin pages
462
-            'admin_path'            => isset($setup_args['admin_path'])
463
-                ? (string) $setup_args['admin_path']
464
-                : '',
465
-            // a method to be called when the EE Admin is first invoked, can be used for hooking into any admin page
466
-            'admin_callback'        => isset($setup_args['admin_callback'])
467
-                ? (string) $setup_args['admin_callback']
468
-                : '',
469
-            // the section name for this addon's configuration settings section (defaults to "addons")
470
-            'config_section'        => isset($setup_args['config_section'])
471
-                ? (string) $setup_args['config_section']
472
-                : 'addons',
473
-            // the class name for this addon's configuration settings object
474
-            'config_class'          => isset($setup_args['config_class'])
475
-                ? (string) $setup_args['config_class']
476
-                : '',
477
-            // the name given to the config for this addons' configuration settings object (optional)
478
-            'config_name'           => isset($setup_args['config_name'])
479
-                ? (string) $setup_args['config_name']
480
-                : '',
481
-            // an array of "class names" => "full server paths" for any classes that might be invoked by the addon
482
-            'autoloader_paths'      => isset($setup_args['autoloader_paths'])
483
-                ? (array) $setup_args['autoloader_paths']
484
-                : [],
485
-            // an array of  "full server paths" for any folders containing classes that might be invoked by the addon
486
-            'autoloader_folders'    => isset($setup_args['autoloader_folders'])
487
-                ? (array) $setup_args['autoloader_folders']
488
-                : [],
489
-            // array of full server paths to any EE_DMS data migration scripts used by the addon.
490
-            // The key should be the EE_Addon class name that this set of data migration scripts belongs to.
491
-            // If the EE_Addon class is namespaced, then this needs to be the Fully Qualified Class Name
492
-            'dms_paths'             => isset($setup_args['dms_paths'])
493
-                ? (array) $setup_args['dms_paths']
494
-                : [],
495
-            // array of full server paths to any EED_Modules used by the addon
496
-            'module_paths'          => isset($setup_args['module_paths'])
497
-                ? (array) $setup_args['module_paths']
498
-                : [],
499
-            // array of full server paths to any EES_Shortcodes used by the addon
500
-            'shortcode_paths'       => isset($setup_args['shortcode_paths'])
501
-                ? (array) $setup_args['shortcode_paths']
502
-                : [],
503
-            'shortcode_fqcns'       => isset($setup_args['shortcode_fqcns'])
504
-                ? (array) $setup_args['shortcode_fqcns']
505
-                : [],
506
-            // array of full server paths to any WP_Widgets used by the addon
507
-            'widget_paths'          => isset($setup_args['widget_paths'])
508
-                ? (array) $setup_args['widget_paths']
509
-                : [],
510
-            'message_types'         => isset($setup_args['message_types'])
511
-                ? (array) $setup_args['message_types']
512
-                : [],
513
-            'capabilities'          => isset($setup_args['capabilities'])
514
-                ? (array) $setup_args['capabilities']
515
-                : [],
516
-            'capability_maps'       => isset($setup_args['capability_maps'])
517
-                ? (array) $setup_args['capability_maps']
518
-                : [],
519
-            'model_paths'           => isset($setup_args['model_paths'])
520
-                ? (array) $setup_args['model_paths']
521
-                : [],
522
-            'class_paths'           => isset($setup_args['class_paths'])
523
-                ? (array) $setup_args['class_paths']
524
-                : [],
525
-            'model_extension_paths' => isset($setup_args['model_extension_paths'])
526
-                ? (array) $setup_args['model_extension_paths']
527
-                : [],
528
-            'class_extension_paths' => isset($setup_args['class_extension_paths'])
529
-                ? (array) $setup_args['class_extension_paths']
530
-                : [],
531
-            'custom_post_types'     => isset($setup_args['custom_post_types'])
532
-                ? (array) $setup_args['custom_post_types']
533
-                : [],
534
-            'custom_taxonomies'     => isset($setup_args['custom_taxonomies'])
535
-                ? (array) $setup_args['custom_taxonomies']
536
-                : [],
537
-            'payment_method_paths'  => isset($setup_args['payment_method_paths'])
538
-                ? (array) $setup_args['payment_method_paths']
539
-                : [],
540
-            'default_terms'         => isset($setup_args['default_terms'])
541
-                ? (array) $setup_args['default_terms']
542
-                : [],
543
-            // if not empty, inserts a new table row after this plugin's row on the WP Plugins page
544
-            // that can be used for adding upgrading/marketing info
545
-            'plugins_page_row'      => isset($setup_args['plugins_page_row'])
546
-                ? (array) $setup_args['plugins_page_row']
547
-                : [],
548
-            'namespace'             => isset(
549
-                $setup_args['namespace']['FQNS'],
550
-                $setup_args['namespace']['DIR']
551
-            )
552
-                ? (array) $setup_args['namespace']
553
-                : [],
554
-            'privacy_policies'      => isset($setup_args['privacy_policies'])
555
-                ? (array) $setup_args['privacy_policies']
556
-                : [],
557
-            'license'               => isset($setup_args['license'])
558
-                ? (array) $setup_args['license']
559
-                : [],
560
-        ];
561
-        // if plugin_action_slug is NOT set, but an admin page path IS set,
562
-        // then let's just use the plugin_slug since that will be used for linking to the admin page
563
-        $addon_settings['plugin_action_slug'] = empty($addon_settings['plugin_action_slug'])
564
-                                                && ! empty($addon_settings['admin_path'])
565
-            ? $addon_settings['plugin_slug']
566
-            : $addon_settings['plugin_action_slug'];
567
-        // full server path to main file (file loaded directly by WP)
568
-        $addon_settings['plugin_basename'] = plugin_basename($addon_settings['main_file_path']);
569
-        return $addon_settings;
570
-    }
571
-
572
-
573
-    /**
574
-     * @param string $addon_name
575
-     * @param array  $addon_settings
576
-     * @return bool
577
-     */
578
-    private static function _addon_is_compatible(string $addon_name, array $addon_settings): bool
579
-    {
580
-        global $wp_version;
581
-        $incompatibility_message = '';
582
-        // check whether this addon version is compatible with EE core
583
-        if (
584
-            isset(EE_Register_Addon::$_incompatible_addons[ $addon_name ])
585
-            && ! self::_meets_min_core_version_requirement(
586
-                EE_Register_Addon::$_incompatible_addons[ $addon_name ],
587
-                $addon_settings['version']
588
-            )
589
-        ) {
590
-            $incompatibility_message = sprintf(
591
-                esc_html__(
592
-                    '%4$sIMPORTANT!%5$sThe Event Espresso "%1$s" addon is not compatible with this version of Event Espresso.%2$sPlease upgrade your "%1$s" addon to version %3$s or newer to resolve this issue.',
593
-                    'event_espresso'
594
-                ),
595
-                $addon_name,
596
-                '<br />',
597
-                EE_Register_Addon::$_incompatible_addons[ $addon_name ],
598
-                '<span style="font-weight: bold; color: #D54E21;">',
599
-                '</span><br />'
600
-            );
601
-        } elseif (
602
-            ! self::_meets_min_core_version_requirement($addon_settings['min_core_version'], espresso_version())
603
-        ) {
604
-            $incompatibility_message = sprintf(
605
-                esc_html__(
606
-                    '%5$sIMPORTANT!%6$sThe Event Espresso "%1$s" addon requires Event Espresso Core version "%2$s" or higher in order to run.%4$sYour version of Event Espresso Core is currently at "%3$s". Please upgrade Event Espresso Core first and then re-activate "%1$s".',
607
-                    'event_espresso'
608
-                ),
609
-                $addon_name,
610
-                self::_effective_version($addon_settings['min_core_version']),
611
-                self::_effective_version(espresso_version()),
612
-                '<br />',
613
-                '<span style="font-weight: bold; color: #D54E21;">',
614
-                '</span><br />'
615
-            );
616
-        } elseif (version_compare($wp_version, $addon_settings['min_wp_version'], '<')) {
617
-            $incompatibility_message = sprintf(
618
-                esc_html__(
619
-                    '%4$sIMPORTANT!%5$sThe Event Espresso "%1$s" addon requires WordPress version "%2$s" or greater.%3$sPlease update your version of WordPress to use the "%1$s" addon and to keep your site secure.',
620
-                    'event_espresso'
621
-                ),
622
-                $addon_name,
623
-                $addon_settings['min_wp_version'],
624
-                '<br />',
625
-                '<span style="font-weight: bold; color: #D54E21;">',
626
-                '</span><br />'
627
-            );
628
-        }
629
-        if (! empty($incompatibility_message)) {
630
-            // remove 'activate' from the REQUEST
631
-            // so WP doesn't erroneously tell the user the plugin activated fine when it didn't
632
-            /** @var RequestInterface $request */
633
-            $request = LoaderFactory::getLoader()->getShared(RequestInterface::class);
634
-            $request->unSetRequestParam('activate', true);
635
-            if (current_user_can('activate_plugins')) {
636
-                // show an error message indicating the plugin didn't activate properly
637
-                EE_Error::add_error($incompatibility_message, __FILE__, __FUNCTION__, __LINE__);
638
-            }
639
-            unset($_GET['activate'], $_REQUEST['activate']);
640
-            if (! function_exists('deactivate_plugins')) {
641
-                require_once ABSPATH . 'wp-admin/includes/plugin.php';
642
-            }
643
-            deactivate_plugins(plugin_basename($addon_settings['main_file_path']));
644
-            // BAIL FROM THE ADDON REGISTRATION PROCESS
645
-            return false;
646
-        }
647
-        // addon IS compatible
648
-        return true;
649
-    }
650
-
651
-
652
-    /**
653
-     * register namespaces right away before any other files or classes get loaded, but AFTER the version checks
654
-     *
655
-     * @param array $addon_settings
656
-     * @return void
657
-     * @throws EE_Error
658
-     */
659
-    private static function _setup_namespaces(array $addon_settings)
660
-    {
661
-        //
662
-        if (
663
-            isset(
664
-                $addon_settings['namespace']['FQNS'],
665
-                $addon_settings['namespace']['DIR']
666
-            )
667
-        ) {
668
-            EE_Psr4AutoloaderInit::psr4_loader()->addNamespace(
669
-                $addon_settings['namespace']['FQNS'],
670
-                $addon_settings['namespace']['DIR']
671
-            );
672
-        }
673
-    }
674
-
675
-
676
-    /**
677
-     * @param string $addon_name
678
-     * @param array  $addon_settings
679
-     * @return bool
680
-     * @throws InvalidArgumentException
681
-     * @throws InvalidDataTypeException
682
-     * @throws InvalidInterfaceException
683
-     */
684
-    private static function _addon_activation(string $addon_name, array $addon_settings): bool
685
-    {
686
-        // this is an activation request
687
-        if (did_action('activate_plugin')) {
688
-            // to find if THIS is the addon that was activated, just check if we have already registered it or not
689
-            // (as the newly-activated addon wasn't around the first time addons were registered).
690
-            if (
691
-                ! isset(self::$_settings[ $addon_name ])
692
-                || (isset(self::$_settings[ $addon_name ])
693
-                    && ! isset(self::$_settings[ $addon_name ]['class_name'])
694
-                )
695
-            ) {
696
-                self::$_settings[ $addon_name ] = $addon_settings;
697
-                $addon                          = self::_load_and_init_addon_class($addon_name);
698
-                $addon->set_activation_indicator_option();
699
-                // dont bother setting up the rest of the addon.
700
-                // we know it was just activated and the request will end soon
701
-            }
702
-            return true;
703
-        }
704
-        // make sure addon settings are set correctly without overwriting anything existing
705
-        if (isset(self::$_settings[ $addon_name ])) {
706
-            self::$_settings[ $addon_name ] += $addon_settings;
707
-        } else {
708
-            self::$_settings[ $addon_name ] = $addon_settings;
709
-        }
710
-        return false;
711
-    }
712
-
713
-
714
-    /**
715
-     * @param string $addon_name
716
-     * @return void
717
-     * @throws EE_Error
718
-     */
719
-    private static function _setup_autoloaders(string $addon_name)
720
-    {
721
-        if (! empty(self::$_settings[ $addon_name ]['autoloader_paths'])) {
722
-            // setup autoloader for single file
723
-            EEH_Autoloader::instance()->register_autoloader(self::$_settings[ $addon_name ]['autoloader_paths']);
724
-        }
725
-        // setup autoloaders for folders
726
-        if (! empty(self::$_settings[ $addon_name ]['autoloader_folders'])) {
727
-            foreach ((array) self::$_settings[ $addon_name ]['autoloader_folders'] as $autoloader_folder) {
728
-                EEH_Autoloader::register_autoloaders_for_each_file_in_folder($autoloader_folder);
729
-            }
730
-        }
731
-    }
732
-
733
-
734
-    /**
735
-     * register new models and extensions
736
-     *
737
-     * @param string $addon_name
738
-     * @return void
739
-     * @throws EE_Error
740
-     */
741
-    private static function _register_models_and_extensions(string $addon_name)
742
-    {
743
-        // register new models
744
-        if (
745
-            ! empty(self::$_settings[ $addon_name ]['model_paths'])
746
-            || ! empty(self::$_settings[ $addon_name ]['class_paths'])
747
-        ) {
748
-            EE_Register_Model::register(
749
-                $addon_name,
750
-                [
751
-                    'model_paths' => self::$_settings[ $addon_name ]['model_paths'],
752
-                    'class_paths' => self::$_settings[ $addon_name ]['class_paths'],
753
-                ]
754
-            );
755
-        }
756
-        // register model extensions
757
-        if (
758
-            ! empty(self::$_settings[ $addon_name ]['model_extension_paths'])
759
-            || ! empty(self::$_settings[ $addon_name ]['class_extension_paths'])
760
-        ) {
761
-            EE_Register_Model_Extensions::register(
762
-                $addon_name,
763
-                [
764
-                    'model_extension_paths' => self::$_settings[ $addon_name ]['model_extension_paths'],
765
-                    'class_extension_paths' => self::$_settings[ $addon_name ]['class_extension_paths'],
766
-                ]
767
-            );
768
-        }
769
-    }
770
-
771
-
772
-    /**
773
-     * @param string $addon_name
774
-     * @return void
775
-     * @throws EE_Error
776
-     */
777
-    private static function _register_data_migration_scripts(string $addon_name)
778
-    {
779
-        // setup DMS
780
-        if (! empty(self::$_settings[ $addon_name ]['dms_paths'])) {
781
-            EE_Register_Data_Migration_Scripts::register(
782
-                $addon_name,
783
-                ['dms_paths' => self::$_settings[ $addon_name ]['dms_paths']]
784
-            );
785
-        }
786
-    }
787
-
788
-
789
-    /**
790
-     * @param string $addon_name
791
-     * @return void
792
-     * @throws EE_Error
793
-     */
794
-    private static function _register_config(string $addon_name)
795
-    {
796
-        // if config_class is present let's register config.
797
-        if (! empty(self::$_settings[ $addon_name ]['config_class'])) {
798
-            EE_Register_Config::register(
799
-                self::$_settings[ $addon_name ]['config_class'],
800
-                [
801
-                    'config_section' => self::$_settings[ $addon_name ]['config_section'],
802
-                    'config_name'    => self::$_settings[ $addon_name ]['config_name'],
803
-                ]
804
-            );
805
-        }
806
-    }
807
-
808
-
809
-    /**
810
-     * @param string $addon_name
811
-     * @return void
812
-     * @throws EE_Error
813
-     */
814
-    private static function _register_admin_pages(string $addon_name)
815
-    {
816
-        if (! empty(self::$_settings[ $addon_name ]['admin_path'])) {
817
-            EE_Register_Admin_Page::register(
818
-                $addon_name,
819
-                ['page_path' => self::$_settings[ $addon_name ]['admin_path']]
820
-            );
821
-        }
822
-    }
823
-
824
-
825
-    /**
826
-     * @param string $addon_name
827
-     * @return void
828
-     * @throws EE_Error
829
-     */
830
-    private static function _register_modules(string $addon_name)
831
-    {
832
-        if (! empty(self::$_settings[ $addon_name ]['module_paths'])) {
833
-            EE_Register_Module::register(
834
-                $addon_name,
835
-                ['module_paths' => self::$_settings[ $addon_name ]['module_paths']]
836
-            );
837
-        }
838
-    }
839
-
840
-
841
-    /**
842
-     * @param string $addon_name
843
-     * @return void
844
-     * @throws EE_Error
845
-     */
846
-    private static function _register_shortcodes(string $addon_name)
847
-    {
848
-        if (
849
-            ! empty(self::$_settings[ $addon_name ]['shortcode_paths'])
850
-            || ! empty(self::$_settings[ $addon_name ]['shortcode_fqcns'])
851
-        ) {
852
-            EE_Register_Shortcode::register(
853
-                $addon_name,
854
-                [
855
-                    'shortcode_paths' => self::$_settings[ $addon_name ]['shortcode_paths'] ?? [],
856
-                    'shortcode_fqcns' => self::$_settings[ $addon_name ]['shortcode_fqcns'] ?? [],
857
-                ]
858
-            );
859
-        }
860
-    }
861
-
862
-
863
-    /**
864
-     * @param string $addon_name
865
-     * @return void
866
-     * @throws EE_Error
867
-     */
868
-    private static function _register_widgets(string $addon_name)
869
-    {
870
-        if (! empty(self::$_settings[ $addon_name ]['widget_paths'])) {
871
-            EE_Register_Widget::register(
872
-                $addon_name,
873
-                ['widget_paths' => self::$_settings[ $addon_name ]['widget_paths']]
874
-            );
875
-        }
876
-    }
877
-
878
-
879
-    /**
880
-     * @param string $addon_name
881
-     * @return void
882
-     * @throws EE_Error
883
-     */
884
-    private static function _register_capabilities(string $addon_name)
885
-    {
886
-        if (! empty(self::$_settings[ $addon_name ]['capabilities'])) {
887
-            EE_Register_Capabilities::register(
888
-                $addon_name,
889
-                [
890
-                    'capabilities'    => self::$_settings[ $addon_name ]['capabilities'],
891
-                    'capability_maps' => self::$_settings[ $addon_name ]['capability_maps'],
892
-                ]
893
-            );
894
-        }
895
-    }
896
-
897
-
898
-    /**
899
-     * @param string $addon_name
900
-     * @return void
901
-     */
902
-    private static function _register_message_types(string $addon_name)
903
-    {
904
-        if (! empty(self::$_settings[ $addon_name ]['message_types'])) {
905
-            add_action(
906
-                'EE_Brewing_Regular___messages_caf',
907
-                ['EE_Register_Addon', 'register_message_types']
908
-            );
909
-        }
910
-    }
911
-
912
-
913
-    /**
914
-     * @param string $addon_name
915
-     * @return void
916
-     * @throws EE_Error
917
-     */
918
-    private static function _register_custom_post_types(string $addon_name)
919
-    {
920
-        if (
921
-            ! empty(self::$_settings[ $addon_name ]['custom_post_types'])
922
-            || ! empty(self::$_settings[ $addon_name ]['custom_taxonomies'])
923
-        ) {
924
-            EE_Register_CPT::register(
925
-                $addon_name,
926
-                [
927
-                    'cpts'          => self::$_settings[ $addon_name ]['custom_post_types'],
928
-                    'cts'           => self::$_settings[ $addon_name ]['custom_taxonomies'],
929
-                    'default_terms' => self::$_settings[ $addon_name ]['default_terms'],
930
-                ]
931
-            );
932
-        }
933
-    }
934
-
935
-
936
-    /**
937
-     * @param string $addon_name
938
-     * @return void
939
-     * @throws InvalidArgumentException
940
-     * @throws InvalidInterfaceException
941
-     * @throws InvalidDataTypeException
942
-     * @throws DomainException
943
-     * @throws EE_Error
944
-     */
945
-    private static function _register_payment_methods(string $addon_name)
946
-    {
947
-        if (! empty(self::$_settings[ $addon_name ]['payment_method_paths'])) {
948
-            EE_Register_Payment_Method::register(
949
-                $addon_name,
950
-                ['payment_method_paths' => self::$_settings[ $addon_name ]['payment_method_paths']]
951
-            );
952
-        }
953
-    }
954
-
955
-
956
-    /**
957
-     * @param string $addon_name
958
-     * @return void
959
-     * @throws InvalidArgumentException
960
-     * @throws InvalidInterfaceException
961
-     * @throws InvalidDataTypeException
962
-     * @throws DomainException
963
-     */
964
-    private static function registerPrivacyPolicies(string $addon_name)
965
-    {
966
-        if (! empty(self::$_settings[ $addon_name ]['privacy_policies'])) {
967
-            EE_Register_Privacy_Policy::register(
968
-                $addon_name,
969
-                self::$_settings[ $addon_name ]['privacy_policies']
970
-            );
971
-        }
972
-    }
973
-
974
-
975
-    /**
976
-     * @param string $addon_name
977
-     * @return void
978
-     */
979
-    private static function registerPersonalDataExporters(string $addon_name)
980
-    {
981
-        if (! empty(self::$_settings[ $addon_name ]['personal_data_exporters'])) {
982
-            EE_Register_Personal_Data_Eraser::register(
983
-                $addon_name,
984
-                self::$_settings[ $addon_name ]['personal_data_exporters']
985
-            );
986
-        }
987
-    }
988
-
989
-
990
-    /**
991
-     * @param string $addon_name
992
-     * @return void
993
-     */
994
-    private static function registerPersonalDataErasers(string $addon_name)
995
-    {
996
-        if (! empty(self::$_settings[ $addon_name ]['personal_data_erasers'])) {
997
-            EE_Register_Personal_Data_Eraser::register(
998
-                $addon_name,
999
-                self::$_settings[ $addon_name ]['personal_data_erasers']
1000
-            );
1001
-        }
1002
-    }
1003
-
1004
-
1005
-    /**
1006
-     * Loads and instantiates the EE_Addon class and adds it onto the registry
1007
-     *
1008
-     * @param string $addon_name
1009
-     * @return EE_Addon
1010
-     * @throws InvalidArgumentException
1011
-     * @throws InvalidInterfaceException
1012
-     * @throws InvalidDataTypeException
1013
-     */
1014
-    private static function _load_and_init_addon_class(string $addon_name): EE_Addon
1015
-    {
1016
-        $addon = self::$loader->getShared(
1017
-            self::$_settings[ $addon_name ]['class_name'],
1018
-            ['EE_Registry::create(addon)' => true]
1019
-        );
1020
-        if (! $addon instanceof EE_Addon) {
1021
-            throw new DomainException(
1022
-                sprintf(
1023
-                    esc_html__('The "%1$s" EE_Addon class failed to instantiate!', 'event_espresso'),
1024
-                    self::$_settings[ $addon_name ]['class_name']
1025
-                )
1026
-            );
1027
-        }
1028
-        // setter inject dep map if required
1029
-        if ($addon->dependencyMap() === null) {
1030
-            $addon->setDependencyMap(self::$loader->getShared('EE_Dependency_Map'));
1031
-        }
1032
-        // setter inject domain if required
1033
-        EE_Register_Addon::injectAddonDomain($addon_name, $addon);
1034
-
1035
-        $addon->set_name($addon_name);
1036
-        $addon->set_plugin_slug(self::$_settings[ $addon_name ]['plugin_slug']);
1037
-        $addon->set_plugin_basename(self::$_settings[ $addon_name ]['plugin_basename']);
1038
-        $addon->set_main_plugin_file(self::$_settings[ $addon_name ]['main_file_path']);
1039
-        $addon->set_plugin_action_slug(self::$_settings[ $addon_name ]['plugin_action_slug']);
1040
-        $addon->set_plugins_page_row(self::$_settings[ $addon_name ]['plugins_page_row']);
1041
-        $addon->set_version(self::$_settings[ $addon_name ]['version']);
1042
-        $addon->set_min_core_version(self::_effective_version(self::$_settings[ $addon_name ]['min_core_version']));
1043
-        $addon->set_config_section(self::$_settings[ $addon_name ]['config_section']);
1044
-        $addon->set_config_class(self::$_settings[ $addon_name ]['config_class']);
1045
-        $addon->set_config_name(self::$_settings[ $addon_name ]['config_name']);
1046
-        do_action(
1047
-            'AHEE__EE_Register_Addon___load_and_init_addon_class',
1048
-            $addon,
1049
-            $addon_name,
1050
-            self::$_settings
1051
-        );
1052
-        // unfortunately this can't be hooked in upon construction,
1053
-        // because we don't have the plugin's mainfile path upon construction.
1054
-        register_deactivation_hook($addon->get_main_plugin_file(), [$addon, 'deactivation']);
1055
-        // call any additional admin_callback functions during load_admin_controller hook
1056
-        if (! empty(self::$_settings[ $addon_name ]['admin_callback'])) {
1057
-            add_action(
1058
-                'AHEE__EE_System__load_controllers__load_admin_controllers',
1059
-                [$addon, self::$_settings[ $addon_name ]['admin_callback']]
1060
-            );
1061
-        }
1062
-        return $addon;
1063
-    }
1064
-
1065
-
1066
-    /**
1067
-     * @param string   $addon_name
1068
-     * @param EE_Addon $addon
1069
-     * @since   4.10.13.p
1070
-     */
1071
-    private static function injectAddonDomain(string $addon_name, EE_Addon $addon)
1072
-    {
1073
-        if ($addon instanceof RequiresDomainInterface && $addon->domain() === null) {
1074
-            // using supplied Domain object
1075
-            $domain = self::$_settings[ $addon_name ]['domain'] instanceof DomainInterface
1076
-                ? self::$_settings[ $addon_name ]['domain']
1077
-                : null;
1078
-            // or construct one using Domain FQCN
1079
-            if ($domain === null && self::$_settings[ $addon_name ]['domain_fqcn'] !== '') {
1080
-                $domain = self::$loader->getShared(
1081
-                    self::$_settings[ $addon_name ]['domain_fqcn'],
1082
-                    [
1083
-                        new EventEspresso\core\domain\values\FilePath(
1084
-                            self::$_settings[ $addon_name ]['main_file_path']
1085
-                        ),
1086
-                        EventEspresso\core\domain\values\Version::fromString(
1087
-                            self::$_settings[ $addon_name ]['version']
1088
-                        ),
1089
-                    ]
1090
-                );
1091
-            }
1092
-            if ($domain instanceof DomainInterface) {
1093
-                $addon->setDomain($domain);
1094
-            }
1095
-        }
1096
-    }
1097
-
1098
-
1099
-    /**
1100
-     * @return void
1101
-     * @deprecated 5.0.0.p
1102
-     */
1103
-    public static function load_pue_update()
1104
-    {
1105
-    }
1106
-
1107
-
1108
-    /**
1109
-     * Callback for EE_Brewing_Regular__messages_caf hook used to register message types.
1110
-     *
1111
-     * @return void
1112
-     * @throws EE_Error
1113
-     * @since 4.4.0
1114
-     */
1115
-    public static function register_message_types()
1116
-    {
1117
-        foreach (self::$_settings as $settings) {
1118
-            if (! empty($settings['message_types'])) {
1119
-                foreach ((array) $settings['message_types'] as $message_type => $message_type_settings) {
1120
-                    EE_Register_Message_Type::register($message_type, $message_type_settings);
1121
-                }
1122
-            }
1123
-        }
1124
-    }
1125
-
1126
-
1127
-    private static function registerLicense($addon_name)
1128
-    {
1129
-        $addon_settings = self::$_settings[ $addon_name ] ?? [];
1130
-        if (empty($addon_settings)) {
1131
-            return;
1132
-        }
1133
-        $license_data = isset($addon_settings['license']) ? (array) $addon_settings['license'] : [];
1134
-        // copy known values from addon settings to license data if anything's missing
1135
-        $license_data += [
1136
-            'main_file_path'   => $addon_settings['main_file_path'] ?? '',
1137
-            'min_core_version' => $addon_settings['min_core_version'] ?? '',
1138
-            'plugin_id'        => 0, // no corresponding value in addon settings
1139
-            'plugin_slug'      => $addon_settings['plugin_slug'] ?? '',
1140
-            'version'          => $addon_settings['version'] ?? '',
1141
-        ];
1142
-        EventEspresso\core\services\licensing\AddonLicense::register($addon_name, $license_data);
1143
-    }
1144
-
1145
-
1146
-    /**
1147
-     * This deregisters an addon that was previously registered with a specific addon_name.
1148
-     *
1149
-     * @param string $addon_name the name for the addon that was previously registered
1150
-     * @throws DomainException
1151
-     * @throws InvalidArgumentException
1152
-     * @throws InvalidDataTypeException
1153
-     * @throws InvalidInterfaceException
1154
-     * @since    4.3.0
1155
-     */
1156
-    public static function deregister(string $addon_name = '')
1157
-    {
1158
-        if (isset(self::$_settings[ $addon_name ]['class_name'])) {
1159
-            try {
1160
-                do_action('AHEE__EE_Register_Addon__deregister__before', $addon_name);
1161
-                $class_name = self::$_settings[ $addon_name ]['class_name'];
1162
-                if (! empty(self::$_settings[ $addon_name ]['dms_paths'])) {
1163
-                    // setup DMS
1164
-                    EE_Register_Data_Migration_Scripts::deregister($addon_name);
1165
-                }
1166
-                if (! empty(self::$_settings[ $addon_name ]['admin_path'])) {
1167
-                    // register admin page
1168
-                    EE_Register_Admin_Page::deregister($addon_name);
1169
-                }
1170
-                if (! empty(self::$_settings[ $addon_name ]['module_paths'])) {
1171
-                    // add to list of modules to be registered
1172
-                    EE_Register_Module::deregister($addon_name);
1173
-                }
1174
-                if (
1175
-                    ! empty(self::$_settings[ $addon_name ]['shortcode_paths'])
1176
-                    || ! empty(self::$_settings[ $addon_name ]['shortcode_fqcns'])
1177
-                ) {
1178
-                    // add to list of shortcodes to be registered
1179
-                    EE_Register_Shortcode::deregister($addon_name);
1180
-                }
1181
-                if (! empty(self::$_settings[ $addon_name ]['config_class'])) {
1182
-                    // if config_class present let's register config.
1183
-                    EE_Register_Config::deregister(self::$_settings[ $addon_name ]['config_class']);
1184
-                }
1185
-                if (! empty(self::$_settings[ $addon_name ]['widget_paths'])) {
1186
-                    // add to list of widgets to be registered
1187
-                    EE_Register_Widget::deregister($addon_name);
1188
-                }
1189
-                if (
1190
-                    ! empty(self::$_settings[ $addon_name ]['model_paths'])
1191
-                    || ! empty(self::$_settings[ $addon_name ]['class_paths'])
1192
-                ) {
1193
-                    // add to list of shortcodes to be registered
1194
-                    EE_Register_Model::deregister($addon_name);
1195
-                }
1196
-                if (
1197
-                    ! empty(self::$_settings[ $addon_name ]['model_extension_paths'])
1198
-                    || ! empty(self::$_settings[ $addon_name ]['class_extension_paths'])
1199
-                ) {
1200
-                    // add to list of shortcodes to be registered
1201
-                    EE_Register_Model_Extensions::deregister($addon_name);
1202
-                }
1203
-                if (! empty(self::$_settings[ $addon_name ]['message_types'])) {
1204
-                    foreach ((array) self::$_settings[ $addon_name ]['message_types'] as $message_type => $message_type_settings) {
1205
-                        EE_Register_Message_Type::deregister($message_type);
1206
-                    }
1207
-                }
1208
-                // deregister capabilities for addon
1209
-                if (
1210
-                    ! empty(self::$_settings[ $addon_name ]['capabilities'])
1211
-                    || ! empty(self::$_settings[ $addon_name ]['capability_maps'])
1212
-                ) {
1213
-                    EE_Register_Capabilities::deregister($addon_name);
1214
-                }
1215
-                // deregister custom_post_types for addon
1216
-                if (! empty(self::$_settings[ $addon_name ]['custom_post_types'])) {
1217
-                    EE_Register_CPT::deregister($addon_name);
1218
-                }
1219
-                if (! empty(self::$_settings[ $addon_name ]['payment_method_paths'])) {
1220
-                    EE_Register_Payment_Method::deregister($addon_name);
1221
-                }
1222
-                $addon = EE_Registry::instance()->getAddon($class_name);
1223
-                if ($addon instanceof EE_Addon) {
1224
-                    remove_action(
1225
-                        'deactivate_' . $addon->get_main_plugin_file_basename(),
1226
-                        [$addon, 'deactivation']
1227
-                    );
1228
-                    remove_action(
1229
-                        'AHEE__EE_System__perform_activations_upgrades_and_migrations',
1230
-                        [$addon, 'initialize_db_if_no_migrations_required']
1231
-                    );
1232
-                    // remove `after_registration` call
1233
-                    remove_action(
1234
-                        'AHEE__EE_System__load_espresso_addons__complete',
1235
-                        [$addon, 'after_registration'],
1236
-                        999
1237
-                    );
1238
-                }
1239
-                EE_Registry::instance()->removeAddon($class_name);
1240
-                LoaderFactory::getLoader()->remove($class_name);
1241
-            } catch (OutOfBoundsException $addon_not_yet_registered_exception) {
1242
-                // the add-on was not yet registered in the registry,
1243
-                // so RegistryContainer::__get() throws this exception.
1244
-                // also no need to worry about this or log it,
1245
-                // it's ok to deregister an add-on before its registered in the registry
1246
-            } catch (Exception $e) {
1247
-                new ExceptionLogger($e);
1248
-            }
1249
-            unset(self::$_settings[ $addon_name ]);
1250
-            do_action('AHEE__EE_Register_Addon__deregister__after', $addon_name);
1251
-        }
1252
-    }
1253
-
1254
-
1255
-    public static function reset(): void
1256
-    {
1257
-        EE_Register_Addon::$_settings = [];
1258
-    }
1259
-
1260
-
1261
-    public static function resetAll(): void
1262
-    {
1263
-        // EE_Register_Addon::reset();
1264
-        EE_Register_Admin_Page::reset();
1265
-        EE_Register_Capabilities::reset();
1266
-        EE_Register_Config::reset();
1267
-        EE_Register_CPT::reset();
1268
-        EE_Register_Data_Migration_Scripts::reset();
1269
-        EE_Register_Message_Type::reset();
1270
-        EE_Register_Messages_Shortcode_Library::reset();
1271
-        EE_Register_Messages_Template_Pack::reset();
1272
-        EE_Register_Messages_Template_Variations::reset();
1273
-        EE_Register_Model::reset();
1274
-        EE_Register_Model_Extensions::reset();
1275
-        EE_Register_Module::reset();
1276
-        EE_Register_Payment_Method::reset();
1277
-        EE_Register_Personal_Data_Eraser::reset();
1278
-        EE_Register_Personal_Data_Exporter::reset();
1279
-        EE_Register_Privacy_Policy::reset();
1280
-        EE_Register_Shortcode::reset();
1281
-        EE_Register_Widget::reset();
1282
-    }
27
+	/**
28
+	 * possibly truncated version of the EE core version string
29
+	 *
30
+	 * @var string
31
+	 */
32
+	protected static $_core_version = '';
33
+
34
+	/**
35
+	 * Holds values for registered addons
36
+	 *
37
+	 * @var array
38
+	 */
39
+	protected static $_settings = [];
40
+
41
+	/**
42
+	 * @var  array $_incompatible_addons keys are addon SLUGS
43
+	 *                                   (first argument passed to EE_Register_Addon::register()), keys are
44
+	 *                                   their MINIMUM VERSION (with all 5 parts. Eg 1.2.3.rc.004).
45
+	 *                                   Generally this should be used sparingly, as we don't want to muddle up
46
+	 *                                   EE core with knowledge of ALL the addons out there.
47
+	 *                                   If you want NO versions of an addon to run with a certain version of core,
48
+	 *                                   it's usually best to define the addon's "min_core_version" as part of its call
49
+	 *                                   to EE_Register_Addon::register(), rather than using this array with a super
50
+	 *                                   high value for its minimum plugin version.
51
+	 */
52
+	protected static $_incompatible_addons = [
53
+		'Multi_Event_Registration' => '2.0.11.rc.002',
54
+		'Promotions'               => '1.0.0.rc.084',
55
+		'EE_WPUsers'               => '2.1.3.p',
56
+	];
57
+
58
+	/**
59
+	 * @var LoaderInterface
60
+	 */
61
+	protected static $loader;
62
+
63
+
64
+	/**
65
+	 * We should always be comparing core to a version like '4.3.0.rc.000',
66
+	 * not just '4.3.0'.
67
+	 * So if the addon developer doesn't provide that full version string,
68
+	 * fill in the blanks for them
69
+	 *
70
+	 * @param string $min_core_version
71
+	 * @return string always like '4.3.0.rc.000'
72
+	 */
73
+	protected static function _effective_version(string $min_core_version): string
74
+	{
75
+		// versions: 4 . 3 . 1 . p . 123
76
+		// offsets:    0 . 1 . 2 . 3 . 4
77
+		$version_parts = explode('.', $min_core_version);
78
+		// check they specified the micro version (after 2nd period)
79
+		if (! isset($version_parts[2])) {
80
+			$version_parts[2] = '0';
81
+		}
82
+		// if they didn't specify the 'p', or 'rc' part. Just assume the lowest possible
83
+		// soon we can assume that's 'rc', but this current version is 'alpha'
84
+		if (! isset($version_parts[3])) {
85
+			$version_parts[3] = 'dev';
86
+		}
87
+		if (! isset($version_parts[4])) {
88
+			$version_parts[4] = '000';
89
+		}
90
+		return implode('.', $version_parts);
91
+	}
92
+
93
+
94
+	/**
95
+	 * Returns whether or not the min core version requirement of the addon is met
96
+	 *
97
+	 * @param string $min_core_version    the minimum core version required by the addon
98
+	 * @param string $actual_core_version the actual core version, optional
99
+	 * @return bool
100
+	 */
101
+	public static function _meets_min_core_version_requirement(
102
+		string $min_core_version,
103
+		string $actual_core_version = EVENT_ESPRESSO_VERSION
104
+	): bool {
105
+		return version_compare(
106
+			self::_effective_version($actual_core_version),
107
+			self::_effective_version($min_core_version),
108
+			'>='
109
+		);
110
+	}
111
+
112
+
113
+	/**
114
+	 * Method for registering new EE_Addons.
115
+	 * Should be called AFTER AHEE__EE_System__load_espresso_addons but BEFORE
116
+	 * AHEE__EE_System___detect_if_activation_or_upgrade__begin in order to register all its components. However, it
117
+	 * may also be called after the 'activate_plugin' action (when an addon is activated), because an activating addon
118
+	 * won't be loaded by WP until after AHEE__EE_System__load_espresso_addons has fired. If its called after
119
+	 * 'activate_plugin', it registers the addon still, but its components are not registered
120
+	 * (they shouldn't be needed anyways, because it's just an activation request and they won't have a chance to do
121
+	 * anything anyways). Instead, it just sets the newly-activated addon's activation indicator wp option and returns
122
+	 * (so that we can detect that the addon has activated on the subsequent request)
123
+	 *
124
+	 * @param string                  $addon_name                       [Required] the EE_Addon's name.
125
+	 * @param array                   $setup_args                       {
126
+	 *                                                                  An array of arguments provided for registering
127
+	 *                                                                  the message type.
128
+	 * @type  string                  $class_name                       the addon's main file name.
129
+	 *                                                                  If left blank, generated from the addon name,
130
+	 *                                                                  changes something like "calendar" to
131
+	 *                                                                  "EE_Calendar"
132
+	 * @type string                   $min_core_version                 the minimum version of EE Core that the
133
+	 *                                                                  addon will work with. eg "4.8.1.rc.084"
134
+	 * @type string                   $version                          the "software" version for the addon. eg
135
+	 *                                                                  "1.0.0.p" for a first stable release, or
136
+	 *                                                                  "1.0.0.rc.043" for a version in progress
137
+	 * @type string                   $main_file_path                   the full server path to the main file
138
+	 *                                                                  loaded directly by WP
139
+	 * @type DomainInterface          $domain                           child class of
140
+	 *                                                                  EventEspresso\core\domain\DomainBase
141
+	 * @type string                   $domain_fqcn                      Fully Qualified Class Name
142
+	 *                                                                  for the addon's Domain class
143
+	 *                                                                  (see EventEspresso\core\domain\Domain)
144
+	 * @type string                   $admin_path                       full server path to the folder where the
145
+	 *                                                                  addon\'s admin files reside
146
+	 * @type string                   $admin_callback                   a method to be called when the EE Admin is
147
+	 *                                                                  first invoked, can be used for hooking into
148
+	 *                                                                  any admin page
149
+	 * @type string                   $config_section                   the section name for this addon's
150
+	 *                                                                  configuration settings section
151
+	 *                                                                  (defaults to "addons")
152
+	 * @type string                   $config_class                     the class name for this addon's
153
+	 *                                                                  configuration settings object
154
+	 * @type string                   $config_name                      the class name for this addon's
155
+	 *                                                                  configuration settings object
156
+	 * @type string                   $autoloader_paths                 [Required] an array of class names and the full
157
+	 *                                                                  server paths to those files.
158
+	 * @type string                   $autoloader_folders               an array of  "full server paths" for any
159
+	 *                                                                  folders containing classes that might be
160
+	 *                                                                  invoked by the addon
161
+	 * @type string                   $dms_paths                        [Required] an array of full server paths to
162
+	 *                                                                  folders that contain data migration scripts.
163
+	 *                                                                  The key should be the EE_Addon class name that
164
+	 *                                                                  this set of data migration scripts belongs to.
165
+	 *                                                                  If the EE_Addon class is namespaced, then this
166
+	 *                                                                  needs to be the Fully Qualified Class Name
167
+	 * @type string                   $module_paths                     an array of full server paths to any
168
+	 *                                                                  EED_Modules used by the addon
169
+	 * @type string                   $shortcode_paths                  an array of full server paths to folders
170
+	 *                                                                  that contain EES_Shortcodes
171
+	 * @type string                   $widget_paths                     an array of full server paths to folders
172
+	 *                                                                  that contain WP_Widgets
173
+	 * @type array                    $capabilities                     an array indexed by role name
174
+	 *                                                                  (i.e administrator,author ) and the values
175
+	 *                                                                  are an array of caps to add to the role.
176
+	 *                                                                  'administrator' => array(
177
+	 *                                                                  'read_addon',
178
+	 *                                                                  'edit_addon',
179
+	 *                                                                  etc.
180
+	 *                                                                  ).
181
+	 * @type EE_Meta_Capability_Map[] $capability_maps                  an array of EE_Meta_Capability_Map object
182
+	 *                                                                  for any addons that need to register any
183
+	 *                                                                  special meta mapped capabilities.  Should
184
+	 *                                                                  be indexed where the key is the
185
+	 *                                                                  EE_Meta_Capability_Map class name and the
186
+	 *                                                                  values are the arguments sent to the class.
187
+	 * @type array                    $model_paths                      array of folders containing DB models
188
+	 * @return bool
189
+	 * @throws DomainException
190
+	 * @throws EE_Error
191
+	 * @throws InvalidArgumentException
192
+	 * @throws InvalidDataTypeException
193
+	 * @throws InvalidInterfaceException
194
+	 * @since                                                           4.3.0
195
+	 * @see                                                             EE_Register_Model
196
+	 * @type array                    $class_paths                      array of folders containing DB classes
197
+	 * @see                                                             EE_Register_Model
198
+	 * @type array                    $model_extension_paths            array of folders containing DB model
199
+	 *                                                                  extensions
200
+	 * @see                                                             EE_Register_Model_Extension
201
+	 * @type array                    $class_extension_paths            array of folders containing DB class
202
+	 *                                                                  extensions
203
+	 * @see                                                             EE_Register_Model_Extension
204
+	 * @type array message_types {
205
+	 *                                                                  An array of message types with the key as
206
+	 *                                                                  the message type name and the values as
207
+	 *                                                                  below:
208
+	 * @type string                   $mtfilename                       [Required] The filename of the message type
209
+	 *                                                                  being registered. This will be the main
210
+	 *                                                                  EE_{Message Type Name}_message_type class.
211
+	 *                                                                  for example:
212
+	 *                                                                  EE_Declined_Registration_message_type.class.php
213
+	 * @type array                    $autoloadpaths                    [Required] An array of paths to add to the
214
+	 *                                                                  messages autoloader for the new message type.
215
+	 * @type array                    $messengers_to_activate_with      An array of messengers that this message
216
+	 *                                                                  type should activate with. Each value in
217
+	 *                                                                  the
218
+	 *                                                                  array
219
+	 *                                                                  should match the name property of a
220
+	 *                                                                  EE_messenger. Optional.
221
+	 * @type array                    $messengers_to_validate_with      An array of messengers that this message
222
+	 *                                                                  type should validate with. Each value in
223
+	 *                                                                  the
224
+	 *                                                                  array
225
+	 *                                                                  should match the name property of an
226
+	 *                                                                  EE_messenger.
227
+	 *                                                                  Optional.
228
+	 *                                                                  }
229
+	 * @type array                    $custom_post_types
230
+	 * @type array                    $custom_taxonomies
231
+	 * @type array                    $payment_method_paths             each element is the folder containing the
232
+	 *                                                                  EE_PMT_Base child class
233
+	 *                                                                  (eg,
234
+	 *                                                                  '/wp-content/plugins/my_plugin/Payomatic/'
235
+	 *                                                                  which contains the files
236
+	 *                                                                  EE_PMT_Payomatic.pm.php)
237
+	 * @type array                    $default_terms
238
+	 * @type array                    $namespace                        {
239
+	 *                                                                  An array with two items for registering the
240
+	 *                                                                  addon's namespace. (If, for some reason, you
241
+	 *                                                                  require additional namespaces,
242
+	 *                                                                  use
243
+	 *                                                                  EventEspresso\core\Psr4Autoloader::addNamespace()
244
+	 *                                                                  directly)
245
+	 * @see                                                             EventEspresso\core\Psr4Autoloader::addNamespace()
246
+	 * @type string                   $FQNS                             the namespace prefix
247
+	 * @type string                   $DIR                              a base directory for class files in the
248
+	 *                                                                  namespace.
249
+	 *                                                                  }
250
+	 *                                                                  }
251
+	 * @type string                   $privacy_policies                 FQNSs (namespaces, each of which contains only
252
+	 *                                                                  privacy policy classes) or FQCNs (specific
253
+	 *                                                                  classnames of privacy policy classes)
254
+	 * @type string                   $personal_data_exporters          FQNSs (namespaces, each of which contains only
255
+	 *                                                                  privacy policy classes) or FQCNs (specific
256
+	 *                                                                  classnames of privacy policy classes)
257
+	 * @type string                   $personal_data_erasers            FQNSs (namespaces, each of which contains only
258
+	 *                                                                  privacy policy classes) or FQCNs (specific
259
+	 *                                                                  classnames of privacy policy classes)
260
+	 */
261
+	public static function register(string $addon_name = '', array $setup_args = []): bool
262
+	{
263
+		// $addon_name = basename($addon_name);
264
+		if (! self::$loader instanceof LoaderInterface) {
265
+			self::$loader = LoaderFactory::getLoader();
266
+		}
267
+		// make sure this was called in the right place!
268
+		if (
269
+			! did_action('activate_plugin')
270
+			&& (
271
+				! did_action('AHEE__EE_System__load_espresso_addons')
272
+				|| did_action('AHEE__EE_System___detect_if_activation_or_upgrade__begin')
273
+			)
274
+		) {
275
+			EE_Error::doing_it_wrong(
276
+				__METHOD__,
277
+				sprintf(
278
+					esc_html__(
279
+						'An attempt to register an EE_Addon named "%s" has failed because it was not registered at the correct time.  Please use the "AHEE__EE_System__load_espresso_addons" hook to register addons.',
280
+						'event_espresso'
281
+					),
282
+					$addon_name
283
+				),
284
+				'4.3.0'
285
+			);
286
+			return false;
287
+		}
288
+		// required fields MUST be present, so let's make sure they are.
289
+		EE_Register_Addon::_verify_parameters($addon_name, $setup_args);
290
+		// get class name for addon
291
+		$class_name = EE_Register_Addon::_parse_class_name($addon_name, $setup_args);
292
+		// setup $_settings array from incoming values.
293
+		$addon_settings = EE_Register_Addon::_get_addon_settings($class_name, $setup_args);
294
+		// allow early addon setup or modification of addon api settings
295
+		self::$_settings = (array) apply_filters(
296
+			'FHEE__EE_Register_Addon__register',
297
+			self::$_settings,
298
+			$addon_name,
299
+			$class_name,
300
+			$setup_args
301
+		);
302
+		// does this addon work with this version of core or WordPress ?
303
+		// does this addon work with this version of core or WordPress ?
304
+		if (! EE_Register_Addon::_addon_is_compatible($addon_name, $addon_settings)) {
305
+			return false;
306
+		}
307
+		// register namespaces
308
+		EE_Register_Addon::_setup_namespaces($addon_settings);
309
+		// check if this is an activation request
310
+		if (EE_Register_Addon::_addon_activation($addon_name, $addon_settings)) {
311
+			// dont bother setting up the rest of the addon atm
312
+			return false;
313
+		}
314
+		// we need cars
315
+		EE_Register_Addon::_setup_autoloaders($addon_name);
316
+		// register new models and extensions
317
+		EE_Register_Addon::_register_models_and_extensions($addon_name);
318
+		// setup DMS
319
+		EE_Register_Addon::_register_data_migration_scripts($addon_name);
320
+		// if config_class is present let's register config.
321
+		EE_Register_Addon::_register_config($addon_name);
322
+		// register admin pages
323
+		EE_Register_Addon::_register_admin_pages($addon_name);
324
+		// add to list of modules to be registered
325
+		EE_Register_Addon::_register_modules($addon_name);
326
+		// add to list of shortcodes to be registered
327
+		EE_Register_Addon::_register_shortcodes($addon_name);
328
+		// add to list of widgets to be registered
329
+		EE_Register_Addon::_register_widgets($addon_name);
330
+		// register capability related stuff.
331
+		EE_Register_Addon::_register_capabilities($addon_name);
332
+		// any message type to register?
333
+		EE_Register_Addon::_register_message_types($addon_name);
334
+		// any custom post type/ custom capabilities or default terms to register
335
+		EE_Register_Addon::_register_custom_post_types($addon_name);
336
+		// and any payment methods
337
+		EE_Register_Addon::_register_payment_methods($addon_name);
338
+		// and privacy policy generators
339
+		EE_Register_Addon::registerPrivacyPolicies($addon_name);
340
+		// and privacy policy generators
341
+		EE_Register_Addon::registerPersonalDataExporters($addon_name);
342
+		// and privacy policy generators
343
+		EE_Register_Addon::registerPersonalDataErasers($addon_name);
344
+		EE_Register_Addon::registerLicense($addon_name);
345
+		// load and instantiate main addon class
346
+		$addon = EE_Register_Addon::_load_and_init_addon_class($addon_name);
347
+		// delay calling after_registration hook on each addon until after all add-ons have been registered.
348
+		add_action('AHEE__EE_System__load_espresso_addons__complete', [$addon, 'after_registration'], 999);
349
+		return $addon instanceof EE_Addon;
350
+	}
351
+
352
+
353
+	/**
354
+	 * @param string $addon_name
355
+	 * @param array  $setup_args
356
+	 * @return void
357
+	 * @throws EE_Error
358
+	 */
359
+	private static function _verify_parameters(string $addon_name, array $setup_args)
360
+	{
361
+		// required fields MUST be present, so let's make sure they are.
362
+		if (empty($addon_name) || empty($setup_args)) {
363
+			throw new EE_Error(
364
+				esc_html__(
365
+					'In order to register an EE_Addon with EE_Register_Addon::register(), you must include the "addon_name" (the name of the addon), and an array of arguments.',
366
+					'event_espresso'
367
+				)
368
+			);
369
+		}
370
+		if (empty($setup_args['main_file_path'])) {
371
+			throw new EE_Error(
372
+				sprintf(
373
+					esc_html__(
374
+						'When registering an addon, you didn\'t provide the "main_file_path", which is the full path to the main file loaded directly by Wordpress. You only provided %s',
375
+						'event_espresso'
376
+					),
377
+					implode(',', array_keys($setup_args))
378
+				)
379
+			);
380
+		}
381
+		// check that addon has not already been registered with that name
382
+		if (isset(self::$_settings[ $addon_name ]) && ! did_action('activate_plugin')) {
383
+			throw new EE_Error(
384
+				sprintf(
385
+					esc_html__(
386
+						'An EE_Addon with the name "%s" has already been registered and each EE_Addon requires a unique name.',
387
+						'event_espresso'
388
+					),
389
+					$addon_name
390
+				)
391
+			);
392
+		}
393
+	}
394
+
395
+
396
+	/**
397
+	 * @param string $addon_name
398
+	 * @param array  $setup_args
399
+	 * @return string
400
+	 */
401
+	private static function _parse_class_name(string $addon_name, array $setup_args): string
402
+	{
403
+		if (empty($setup_args['class_name'])) {
404
+			// generate one by first separating name with spaces
405
+			$class_name = str_replace(['-', '_'], ' ', trim($addon_name));
406
+			// capitalize, then replace spaces with underscores
407
+			$class_name = str_replace(' ', '_', ucwords($class_name));
408
+		} else {
409
+			$class_name = $setup_args['class_name'];
410
+		}
411
+		// check if classname is fully  qualified or is a legacy classname already prefixed with 'EE_'
412
+		return strpos($class_name, '\\') || strpos($class_name, 'EE_') === 0
413
+			? $class_name
414
+			: 'EE_' . $class_name;
415
+	}
416
+
417
+
418
+	/**
419
+	 * @param string $class_name
420
+	 * @param array  $setup_args
421
+	 * @return array
422
+	 */
423
+	private static function _get_addon_settings(string $class_name, array $setup_args): array
424
+	{
425
+		// setup $_settings array from incoming values.
426
+		$addon_settings = [
427
+			// generated from the addon name, changes something like "calendar" to "EE_Calendar"
428
+			'class_name'            => $class_name,
429
+			// the addon slug for use in URLs, etc
430
+			'plugin_slug'           => isset($setup_args['plugin_slug'])
431
+				? (string) $setup_args['plugin_slug']
432
+				: sanitize_key($class_name),
433
+			// page slug to be used when generating the "Settings" link on the WP plugin page
434
+			'plugin_action_slug'    => isset($setup_args['plugin_action_slug'])
435
+				? (string) $setup_args['plugin_action_slug']
436
+				: '',
437
+			// the "software" version for the addon
438
+			'version'               => isset($setup_args['version'])
439
+				? (string) $setup_args['version']
440
+				: '',
441
+			// the minimum version of EE Core that the addon will work with
442
+			'min_core_version'      => isset($setup_args['min_core_version'])
443
+				? (string) $setup_args['min_core_version']
444
+				: '',
445
+			// the minimum version of WordPress that the addon will work with
446
+			'min_wp_version'        => isset($setup_args['min_wp_version'])
447
+				? (string) $setup_args['min_wp_version']
448
+				: EE_MIN_WP_VER_REQUIRED,
449
+			// full server path to main file (file loaded directly by WP)
450
+			'main_file_path'        => isset($setup_args['main_file_path'])
451
+				? (string) $setup_args['main_file_path']
452
+				: '',
453
+			// instance of \EventEspresso\core\domain\DomainInterface
454
+			'domain'                => isset($setup_args['domain']) && $setup_args['domain'] instanceof DomainInterface
455
+				? $setup_args['domain']
456
+				: null,
457
+			// Fully Qualified Class Name for the addon's Domain class
458
+			'domain_fqcn'           => isset($setup_args['domain_fqcn'])
459
+				? (string) $setup_args['domain_fqcn']
460
+				: '',
461
+			// path to folder containing files for integrating with the EE core admin and/or setting up EE admin pages
462
+			'admin_path'            => isset($setup_args['admin_path'])
463
+				? (string) $setup_args['admin_path']
464
+				: '',
465
+			// a method to be called when the EE Admin is first invoked, can be used for hooking into any admin page
466
+			'admin_callback'        => isset($setup_args['admin_callback'])
467
+				? (string) $setup_args['admin_callback']
468
+				: '',
469
+			// the section name for this addon's configuration settings section (defaults to "addons")
470
+			'config_section'        => isset($setup_args['config_section'])
471
+				? (string) $setup_args['config_section']
472
+				: 'addons',
473
+			// the class name for this addon's configuration settings object
474
+			'config_class'          => isset($setup_args['config_class'])
475
+				? (string) $setup_args['config_class']
476
+				: '',
477
+			// the name given to the config for this addons' configuration settings object (optional)
478
+			'config_name'           => isset($setup_args['config_name'])
479
+				? (string) $setup_args['config_name']
480
+				: '',
481
+			// an array of "class names" => "full server paths" for any classes that might be invoked by the addon
482
+			'autoloader_paths'      => isset($setup_args['autoloader_paths'])
483
+				? (array) $setup_args['autoloader_paths']
484
+				: [],
485
+			// an array of  "full server paths" for any folders containing classes that might be invoked by the addon
486
+			'autoloader_folders'    => isset($setup_args['autoloader_folders'])
487
+				? (array) $setup_args['autoloader_folders']
488
+				: [],
489
+			// array of full server paths to any EE_DMS data migration scripts used by the addon.
490
+			// The key should be the EE_Addon class name that this set of data migration scripts belongs to.
491
+			// If the EE_Addon class is namespaced, then this needs to be the Fully Qualified Class Name
492
+			'dms_paths'             => isset($setup_args['dms_paths'])
493
+				? (array) $setup_args['dms_paths']
494
+				: [],
495
+			// array of full server paths to any EED_Modules used by the addon
496
+			'module_paths'          => isset($setup_args['module_paths'])
497
+				? (array) $setup_args['module_paths']
498
+				: [],
499
+			// array of full server paths to any EES_Shortcodes used by the addon
500
+			'shortcode_paths'       => isset($setup_args['shortcode_paths'])
501
+				? (array) $setup_args['shortcode_paths']
502
+				: [],
503
+			'shortcode_fqcns'       => isset($setup_args['shortcode_fqcns'])
504
+				? (array) $setup_args['shortcode_fqcns']
505
+				: [],
506
+			// array of full server paths to any WP_Widgets used by the addon
507
+			'widget_paths'          => isset($setup_args['widget_paths'])
508
+				? (array) $setup_args['widget_paths']
509
+				: [],
510
+			'message_types'         => isset($setup_args['message_types'])
511
+				? (array) $setup_args['message_types']
512
+				: [],
513
+			'capabilities'          => isset($setup_args['capabilities'])
514
+				? (array) $setup_args['capabilities']
515
+				: [],
516
+			'capability_maps'       => isset($setup_args['capability_maps'])
517
+				? (array) $setup_args['capability_maps']
518
+				: [],
519
+			'model_paths'           => isset($setup_args['model_paths'])
520
+				? (array) $setup_args['model_paths']
521
+				: [],
522
+			'class_paths'           => isset($setup_args['class_paths'])
523
+				? (array) $setup_args['class_paths']
524
+				: [],
525
+			'model_extension_paths' => isset($setup_args['model_extension_paths'])
526
+				? (array) $setup_args['model_extension_paths']
527
+				: [],
528
+			'class_extension_paths' => isset($setup_args['class_extension_paths'])
529
+				? (array) $setup_args['class_extension_paths']
530
+				: [],
531
+			'custom_post_types'     => isset($setup_args['custom_post_types'])
532
+				? (array) $setup_args['custom_post_types']
533
+				: [],
534
+			'custom_taxonomies'     => isset($setup_args['custom_taxonomies'])
535
+				? (array) $setup_args['custom_taxonomies']
536
+				: [],
537
+			'payment_method_paths'  => isset($setup_args['payment_method_paths'])
538
+				? (array) $setup_args['payment_method_paths']
539
+				: [],
540
+			'default_terms'         => isset($setup_args['default_terms'])
541
+				? (array) $setup_args['default_terms']
542
+				: [],
543
+			// if not empty, inserts a new table row after this plugin's row on the WP Plugins page
544
+			// that can be used for adding upgrading/marketing info
545
+			'plugins_page_row'      => isset($setup_args['plugins_page_row'])
546
+				? (array) $setup_args['plugins_page_row']
547
+				: [],
548
+			'namespace'             => isset(
549
+				$setup_args['namespace']['FQNS'],
550
+				$setup_args['namespace']['DIR']
551
+			)
552
+				? (array) $setup_args['namespace']
553
+				: [],
554
+			'privacy_policies'      => isset($setup_args['privacy_policies'])
555
+				? (array) $setup_args['privacy_policies']
556
+				: [],
557
+			'license'               => isset($setup_args['license'])
558
+				? (array) $setup_args['license']
559
+				: [],
560
+		];
561
+		// if plugin_action_slug is NOT set, but an admin page path IS set,
562
+		// then let's just use the plugin_slug since that will be used for linking to the admin page
563
+		$addon_settings['plugin_action_slug'] = empty($addon_settings['plugin_action_slug'])
564
+												&& ! empty($addon_settings['admin_path'])
565
+			? $addon_settings['plugin_slug']
566
+			: $addon_settings['plugin_action_slug'];
567
+		// full server path to main file (file loaded directly by WP)
568
+		$addon_settings['plugin_basename'] = plugin_basename($addon_settings['main_file_path']);
569
+		return $addon_settings;
570
+	}
571
+
572
+
573
+	/**
574
+	 * @param string $addon_name
575
+	 * @param array  $addon_settings
576
+	 * @return bool
577
+	 */
578
+	private static function _addon_is_compatible(string $addon_name, array $addon_settings): bool
579
+	{
580
+		global $wp_version;
581
+		$incompatibility_message = '';
582
+		// check whether this addon version is compatible with EE core
583
+		if (
584
+			isset(EE_Register_Addon::$_incompatible_addons[ $addon_name ])
585
+			&& ! self::_meets_min_core_version_requirement(
586
+				EE_Register_Addon::$_incompatible_addons[ $addon_name ],
587
+				$addon_settings['version']
588
+			)
589
+		) {
590
+			$incompatibility_message = sprintf(
591
+				esc_html__(
592
+					'%4$sIMPORTANT!%5$sThe Event Espresso "%1$s" addon is not compatible with this version of Event Espresso.%2$sPlease upgrade your "%1$s" addon to version %3$s or newer to resolve this issue.',
593
+					'event_espresso'
594
+				),
595
+				$addon_name,
596
+				'<br />',
597
+				EE_Register_Addon::$_incompatible_addons[ $addon_name ],
598
+				'<span style="font-weight: bold; color: #D54E21;">',
599
+				'</span><br />'
600
+			);
601
+		} elseif (
602
+			! self::_meets_min_core_version_requirement($addon_settings['min_core_version'], espresso_version())
603
+		) {
604
+			$incompatibility_message = sprintf(
605
+				esc_html__(
606
+					'%5$sIMPORTANT!%6$sThe Event Espresso "%1$s" addon requires Event Espresso Core version "%2$s" or higher in order to run.%4$sYour version of Event Espresso Core is currently at "%3$s". Please upgrade Event Espresso Core first and then re-activate "%1$s".',
607
+					'event_espresso'
608
+				),
609
+				$addon_name,
610
+				self::_effective_version($addon_settings['min_core_version']),
611
+				self::_effective_version(espresso_version()),
612
+				'<br />',
613
+				'<span style="font-weight: bold; color: #D54E21;">',
614
+				'</span><br />'
615
+			);
616
+		} elseif (version_compare($wp_version, $addon_settings['min_wp_version'], '<')) {
617
+			$incompatibility_message = sprintf(
618
+				esc_html__(
619
+					'%4$sIMPORTANT!%5$sThe Event Espresso "%1$s" addon requires WordPress version "%2$s" or greater.%3$sPlease update your version of WordPress to use the "%1$s" addon and to keep your site secure.',
620
+					'event_espresso'
621
+				),
622
+				$addon_name,
623
+				$addon_settings['min_wp_version'],
624
+				'<br />',
625
+				'<span style="font-weight: bold; color: #D54E21;">',
626
+				'</span><br />'
627
+			);
628
+		}
629
+		if (! empty($incompatibility_message)) {
630
+			// remove 'activate' from the REQUEST
631
+			// so WP doesn't erroneously tell the user the plugin activated fine when it didn't
632
+			/** @var RequestInterface $request */
633
+			$request = LoaderFactory::getLoader()->getShared(RequestInterface::class);
634
+			$request->unSetRequestParam('activate', true);
635
+			if (current_user_can('activate_plugins')) {
636
+				// show an error message indicating the plugin didn't activate properly
637
+				EE_Error::add_error($incompatibility_message, __FILE__, __FUNCTION__, __LINE__);
638
+			}
639
+			unset($_GET['activate'], $_REQUEST['activate']);
640
+			if (! function_exists('deactivate_plugins')) {
641
+				require_once ABSPATH . 'wp-admin/includes/plugin.php';
642
+			}
643
+			deactivate_plugins(plugin_basename($addon_settings['main_file_path']));
644
+			// BAIL FROM THE ADDON REGISTRATION PROCESS
645
+			return false;
646
+		}
647
+		// addon IS compatible
648
+		return true;
649
+	}
650
+
651
+
652
+	/**
653
+	 * register namespaces right away before any other files or classes get loaded, but AFTER the version checks
654
+	 *
655
+	 * @param array $addon_settings
656
+	 * @return void
657
+	 * @throws EE_Error
658
+	 */
659
+	private static function _setup_namespaces(array $addon_settings)
660
+	{
661
+		//
662
+		if (
663
+			isset(
664
+				$addon_settings['namespace']['FQNS'],
665
+				$addon_settings['namespace']['DIR']
666
+			)
667
+		) {
668
+			EE_Psr4AutoloaderInit::psr4_loader()->addNamespace(
669
+				$addon_settings['namespace']['FQNS'],
670
+				$addon_settings['namespace']['DIR']
671
+			);
672
+		}
673
+	}
674
+
675
+
676
+	/**
677
+	 * @param string $addon_name
678
+	 * @param array  $addon_settings
679
+	 * @return bool
680
+	 * @throws InvalidArgumentException
681
+	 * @throws InvalidDataTypeException
682
+	 * @throws InvalidInterfaceException
683
+	 */
684
+	private static function _addon_activation(string $addon_name, array $addon_settings): bool
685
+	{
686
+		// this is an activation request
687
+		if (did_action('activate_plugin')) {
688
+			// to find if THIS is the addon that was activated, just check if we have already registered it or not
689
+			// (as the newly-activated addon wasn't around the first time addons were registered).
690
+			if (
691
+				! isset(self::$_settings[ $addon_name ])
692
+				|| (isset(self::$_settings[ $addon_name ])
693
+					&& ! isset(self::$_settings[ $addon_name ]['class_name'])
694
+				)
695
+			) {
696
+				self::$_settings[ $addon_name ] = $addon_settings;
697
+				$addon                          = self::_load_and_init_addon_class($addon_name);
698
+				$addon->set_activation_indicator_option();
699
+				// dont bother setting up the rest of the addon.
700
+				// we know it was just activated and the request will end soon
701
+			}
702
+			return true;
703
+		}
704
+		// make sure addon settings are set correctly without overwriting anything existing
705
+		if (isset(self::$_settings[ $addon_name ])) {
706
+			self::$_settings[ $addon_name ] += $addon_settings;
707
+		} else {
708
+			self::$_settings[ $addon_name ] = $addon_settings;
709
+		}
710
+		return false;
711
+	}
712
+
713
+
714
+	/**
715
+	 * @param string $addon_name
716
+	 * @return void
717
+	 * @throws EE_Error
718
+	 */
719
+	private static function _setup_autoloaders(string $addon_name)
720
+	{
721
+		if (! empty(self::$_settings[ $addon_name ]['autoloader_paths'])) {
722
+			// setup autoloader for single file
723
+			EEH_Autoloader::instance()->register_autoloader(self::$_settings[ $addon_name ]['autoloader_paths']);
724
+		}
725
+		// setup autoloaders for folders
726
+		if (! empty(self::$_settings[ $addon_name ]['autoloader_folders'])) {
727
+			foreach ((array) self::$_settings[ $addon_name ]['autoloader_folders'] as $autoloader_folder) {
728
+				EEH_Autoloader::register_autoloaders_for_each_file_in_folder($autoloader_folder);
729
+			}
730
+		}
731
+	}
732
+
733
+
734
+	/**
735
+	 * register new models and extensions
736
+	 *
737
+	 * @param string $addon_name
738
+	 * @return void
739
+	 * @throws EE_Error
740
+	 */
741
+	private static function _register_models_and_extensions(string $addon_name)
742
+	{
743
+		// register new models
744
+		if (
745
+			! empty(self::$_settings[ $addon_name ]['model_paths'])
746
+			|| ! empty(self::$_settings[ $addon_name ]['class_paths'])
747
+		) {
748
+			EE_Register_Model::register(
749
+				$addon_name,
750
+				[
751
+					'model_paths' => self::$_settings[ $addon_name ]['model_paths'],
752
+					'class_paths' => self::$_settings[ $addon_name ]['class_paths'],
753
+				]
754
+			);
755
+		}
756
+		// register model extensions
757
+		if (
758
+			! empty(self::$_settings[ $addon_name ]['model_extension_paths'])
759
+			|| ! empty(self::$_settings[ $addon_name ]['class_extension_paths'])
760
+		) {
761
+			EE_Register_Model_Extensions::register(
762
+				$addon_name,
763
+				[
764
+					'model_extension_paths' => self::$_settings[ $addon_name ]['model_extension_paths'],
765
+					'class_extension_paths' => self::$_settings[ $addon_name ]['class_extension_paths'],
766
+				]
767
+			);
768
+		}
769
+	}
770
+
771
+
772
+	/**
773
+	 * @param string $addon_name
774
+	 * @return void
775
+	 * @throws EE_Error
776
+	 */
777
+	private static function _register_data_migration_scripts(string $addon_name)
778
+	{
779
+		// setup DMS
780
+		if (! empty(self::$_settings[ $addon_name ]['dms_paths'])) {
781
+			EE_Register_Data_Migration_Scripts::register(
782
+				$addon_name,
783
+				['dms_paths' => self::$_settings[ $addon_name ]['dms_paths']]
784
+			);
785
+		}
786
+	}
787
+
788
+
789
+	/**
790
+	 * @param string $addon_name
791
+	 * @return void
792
+	 * @throws EE_Error
793
+	 */
794
+	private static function _register_config(string $addon_name)
795
+	{
796
+		// if config_class is present let's register config.
797
+		if (! empty(self::$_settings[ $addon_name ]['config_class'])) {
798
+			EE_Register_Config::register(
799
+				self::$_settings[ $addon_name ]['config_class'],
800
+				[
801
+					'config_section' => self::$_settings[ $addon_name ]['config_section'],
802
+					'config_name'    => self::$_settings[ $addon_name ]['config_name'],
803
+				]
804
+			);
805
+		}
806
+	}
807
+
808
+
809
+	/**
810
+	 * @param string $addon_name
811
+	 * @return void
812
+	 * @throws EE_Error
813
+	 */
814
+	private static function _register_admin_pages(string $addon_name)
815
+	{
816
+		if (! empty(self::$_settings[ $addon_name ]['admin_path'])) {
817
+			EE_Register_Admin_Page::register(
818
+				$addon_name,
819
+				['page_path' => self::$_settings[ $addon_name ]['admin_path']]
820
+			);
821
+		}
822
+	}
823
+
824
+
825
+	/**
826
+	 * @param string $addon_name
827
+	 * @return void
828
+	 * @throws EE_Error
829
+	 */
830
+	private static function _register_modules(string $addon_name)
831
+	{
832
+		if (! empty(self::$_settings[ $addon_name ]['module_paths'])) {
833
+			EE_Register_Module::register(
834
+				$addon_name,
835
+				['module_paths' => self::$_settings[ $addon_name ]['module_paths']]
836
+			);
837
+		}
838
+	}
839
+
840
+
841
+	/**
842
+	 * @param string $addon_name
843
+	 * @return void
844
+	 * @throws EE_Error
845
+	 */
846
+	private static function _register_shortcodes(string $addon_name)
847
+	{
848
+		if (
849
+			! empty(self::$_settings[ $addon_name ]['shortcode_paths'])
850
+			|| ! empty(self::$_settings[ $addon_name ]['shortcode_fqcns'])
851
+		) {
852
+			EE_Register_Shortcode::register(
853
+				$addon_name,
854
+				[
855
+					'shortcode_paths' => self::$_settings[ $addon_name ]['shortcode_paths'] ?? [],
856
+					'shortcode_fqcns' => self::$_settings[ $addon_name ]['shortcode_fqcns'] ?? [],
857
+				]
858
+			);
859
+		}
860
+	}
861
+
862
+
863
+	/**
864
+	 * @param string $addon_name
865
+	 * @return void
866
+	 * @throws EE_Error
867
+	 */
868
+	private static function _register_widgets(string $addon_name)
869
+	{
870
+		if (! empty(self::$_settings[ $addon_name ]['widget_paths'])) {
871
+			EE_Register_Widget::register(
872
+				$addon_name,
873
+				['widget_paths' => self::$_settings[ $addon_name ]['widget_paths']]
874
+			);
875
+		}
876
+	}
877
+
878
+
879
+	/**
880
+	 * @param string $addon_name
881
+	 * @return void
882
+	 * @throws EE_Error
883
+	 */
884
+	private static function _register_capabilities(string $addon_name)
885
+	{
886
+		if (! empty(self::$_settings[ $addon_name ]['capabilities'])) {
887
+			EE_Register_Capabilities::register(
888
+				$addon_name,
889
+				[
890
+					'capabilities'    => self::$_settings[ $addon_name ]['capabilities'],
891
+					'capability_maps' => self::$_settings[ $addon_name ]['capability_maps'],
892
+				]
893
+			);
894
+		}
895
+	}
896
+
897
+
898
+	/**
899
+	 * @param string $addon_name
900
+	 * @return void
901
+	 */
902
+	private static function _register_message_types(string $addon_name)
903
+	{
904
+		if (! empty(self::$_settings[ $addon_name ]['message_types'])) {
905
+			add_action(
906
+				'EE_Brewing_Regular___messages_caf',
907
+				['EE_Register_Addon', 'register_message_types']
908
+			);
909
+		}
910
+	}
911
+
912
+
913
+	/**
914
+	 * @param string $addon_name
915
+	 * @return void
916
+	 * @throws EE_Error
917
+	 */
918
+	private static function _register_custom_post_types(string $addon_name)
919
+	{
920
+		if (
921
+			! empty(self::$_settings[ $addon_name ]['custom_post_types'])
922
+			|| ! empty(self::$_settings[ $addon_name ]['custom_taxonomies'])
923
+		) {
924
+			EE_Register_CPT::register(
925
+				$addon_name,
926
+				[
927
+					'cpts'          => self::$_settings[ $addon_name ]['custom_post_types'],
928
+					'cts'           => self::$_settings[ $addon_name ]['custom_taxonomies'],
929
+					'default_terms' => self::$_settings[ $addon_name ]['default_terms'],
930
+				]
931
+			);
932
+		}
933
+	}
934
+
935
+
936
+	/**
937
+	 * @param string $addon_name
938
+	 * @return void
939
+	 * @throws InvalidArgumentException
940
+	 * @throws InvalidInterfaceException
941
+	 * @throws InvalidDataTypeException
942
+	 * @throws DomainException
943
+	 * @throws EE_Error
944
+	 */
945
+	private static function _register_payment_methods(string $addon_name)
946
+	{
947
+		if (! empty(self::$_settings[ $addon_name ]['payment_method_paths'])) {
948
+			EE_Register_Payment_Method::register(
949
+				$addon_name,
950
+				['payment_method_paths' => self::$_settings[ $addon_name ]['payment_method_paths']]
951
+			);
952
+		}
953
+	}
954
+
955
+
956
+	/**
957
+	 * @param string $addon_name
958
+	 * @return void
959
+	 * @throws InvalidArgumentException
960
+	 * @throws InvalidInterfaceException
961
+	 * @throws InvalidDataTypeException
962
+	 * @throws DomainException
963
+	 */
964
+	private static function registerPrivacyPolicies(string $addon_name)
965
+	{
966
+		if (! empty(self::$_settings[ $addon_name ]['privacy_policies'])) {
967
+			EE_Register_Privacy_Policy::register(
968
+				$addon_name,
969
+				self::$_settings[ $addon_name ]['privacy_policies']
970
+			);
971
+		}
972
+	}
973
+
974
+
975
+	/**
976
+	 * @param string $addon_name
977
+	 * @return void
978
+	 */
979
+	private static function registerPersonalDataExporters(string $addon_name)
980
+	{
981
+		if (! empty(self::$_settings[ $addon_name ]['personal_data_exporters'])) {
982
+			EE_Register_Personal_Data_Eraser::register(
983
+				$addon_name,
984
+				self::$_settings[ $addon_name ]['personal_data_exporters']
985
+			);
986
+		}
987
+	}
988
+
989
+
990
+	/**
991
+	 * @param string $addon_name
992
+	 * @return void
993
+	 */
994
+	private static function registerPersonalDataErasers(string $addon_name)
995
+	{
996
+		if (! empty(self::$_settings[ $addon_name ]['personal_data_erasers'])) {
997
+			EE_Register_Personal_Data_Eraser::register(
998
+				$addon_name,
999
+				self::$_settings[ $addon_name ]['personal_data_erasers']
1000
+			);
1001
+		}
1002
+	}
1003
+
1004
+
1005
+	/**
1006
+	 * Loads and instantiates the EE_Addon class and adds it onto the registry
1007
+	 *
1008
+	 * @param string $addon_name
1009
+	 * @return EE_Addon
1010
+	 * @throws InvalidArgumentException
1011
+	 * @throws InvalidInterfaceException
1012
+	 * @throws InvalidDataTypeException
1013
+	 */
1014
+	private static function _load_and_init_addon_class(string $addon_name): EE_Addon
1015
+	{
1016
+		$addon = self::$loader->getShared(
1017
+			self::$_settings[ $addon_name ]['class_name'],
1018
+			['EE_Registry::create(addon)' => true]
1019
+		);
1020
+		if (! $addon instanceof EE_Addon) {
1021
+			throw new DomainException(
1022
+				sprintf(
1023
+					esc_html__('The "%1$s" EE_Addon class failed to instantiate!', 'event_espresso'),
1024
+					self::$_settings[ $addon_name ]['class_name']
1025
+				)
1026
+			);
1027
+		}
1028
+		// setter inject dep map if required
1029
+		if ($addon->dependencyMap() === null) {
1030
+			$addon->setDependencyMap(self::$loader->getShared('EE_Dependency_Map'));
1031
+		}
1032
+		// setter inject domain if required
1033
+		EE_Register_Addon::injectAddonDomain($addon_name, $addon);
1034
+
1035
+		$addon->set_name($addon_name);
1036
+		$addon->set_plugin_slug(self::$_settings[ $addon_name ]['plugin_slug']);
1037
+		$addon->set_plugin_basename(self::$_settings[ $addon_name ]['plugin_basename']);
1038
+		$addon->set_main_plugin_file(self::$_settings[ $addon_name ]['main_file_path']);
1039
+		$addon->set_plugin_action_slug(self::$_settings[ $addon_name ]['plugin_action_slug']);
1040
+		$addon->set_plugins_page_row(self::$_settings[ $addon_name ]['plugins_page_row']);
1041
+		$addon->set_version(self::$_settings[ $addon_name ]['version']);
1042
+		$addon->set_min_core_version(self::_effective_version(self::$_settings[ $addon_name ]['min_core_version']));
1043
+		$addon->set_config_section(self::$_settings[ $addon_name ]['config_section']);
1044
+		$addon->set_config_class(self::$_settings[ $addon_name ]['config_class']);
1045
+		$addon->set_config_name(self::$_settings[ $addon_name ]['config_name']);
1046
+		do_action(
1047
+			'AHEE__EE_Register_Addon___load_and_init_addon_class',
1048
+			$addon,
1049
+			$addon_name,
1050
+			self::$_settings
1051
+		);
1052
+		// unfortunately this can't be hooked in upon construction,
1053
+		// because we don't have the plugin's mainfile path upon construction.
1054
+		register_deactivation_hook($addon->get_main_plugin_file(), [$addon, 'deactivation']);
1055
+		// call any additional admin_callback functions during load_admin_controller hook
1056
+		if (! empty(self::$_settings[ $addon_name ]['admin_callback'])) {
1057
+			add_action(
1058
+				'AHEE__EE_System__load_controllers__load_admin_controllers',
1059
+				[$addon, self::$_settings[ $addon_name ]['admin_callback']]
1060
+			);
1061
+		}
1062
+		return $addon;
1063
+	}
1064
+
1065
+
1066
+	/**
1067
+	 * @param string   $addon_name
1068
+	 * @param EE_Addon $addon
1069
+	 * @since   4.10.13.p
1070
+	 */
1071
+	private static function injectAddonDomain(string $addon_name, EE_Addon $addon)
1072
+	{
1073
+		if ($addon instanceof RequiresDomainInterface && $addon->domain() === null) {
1074
+			// using supplied Domain object
1075
+			$domain = self::$_settings[ $addon_name ]['domain'] instanceof DomainInterface
1076
+				? self::$_settings[ $addon_name ]['domain']
1077
+				: null;
1078
+			// or construct one using Domain FQCN
1079
+			if ($domain === null && self::$_settings[ $addon_name ]['domain_fqcn'] !== '') {
1080
+				$domain = self::$loader->getShared(
1081
+					self::$_settings[ $addon_name ]['domain_fqcn'],
1082
+					[
1083
+						new EventEspresso\core\domain\values\FilePath(
1084
+							self::$_settings[ $addon_name ]['main_file_path']
1085
+						),
1086
+						EventEspresso\core\domain\values\Version::fromString(
1087
+							self::$_settings[ $addon_name ]['version']
1088
+						),
1089
+					]
1090
+				);
1091
+			}
1092
+			if ($domain instanceof DomainInterface) {
1093
+				$addon->setDomain($domain);
1094
+			}
1095
+		}
1096
+	}
1097
+
1098
+
1099
+	/**
1100
+	 * @return void
1101
+	 * @deprecated 5.0.0.p
1102
+	 */
1103
+	public static function load_pue_update()
1104
+	{
1105
+	}
1106
+
1107
+
1108
+	/**
1109
+	 * Callback for EE_Brewing_Regular__messages_caf hook used to register message types.
1110
+	 *
1111
+	 * @return void
1112
+	 * @throws EE_Error
1113
+	 * @since 4.4.0
1114
+	 */
1115
+	public static function register_message_types()
1116
+	{
1117
+		foreach (self::$_settings as $settings) {
1118
+			if (! empty($settings['message_types'])) {
1119
+				foreach ((array) $settings['message_types'] as $message_type => $message_type_settings) {
1120
+					EE_Register_Message_Type::register($message_type, $message_type_settings);
1121
+				}
1122
+			}
1123
+		}
1124
+	}
1125
+
1126
+
1127
+	private static function registerLicense($addon_name)
1128
+	{
1129
+		$addon_settings = self::$_settings[ $addon_name ] ?? [];
1130
+		if (empty($addon_settings)) {
1131
+			return;
1132
+		}
1133
+		$license_data = isset($addon_settings['license']) ? (array) $addon_settings['license'] : [];
1134
+		// copy known values from addon settings to license data if anything's missing
1135
+		$license_data += [
1136
+			'main_file_path'   => $addon_settings['main_file_path'] ?? '',
1137
+			'min_core_version' => $addon_settings['min_core_version'] ?? '',
1138
+			'plugin_id'        => 0, // no corresponding value in addon settings
1139
+			'plugin_slug'      => $addon_settings['plugin_slug'] ?? '',
1140
+			'version'          => $addon_settings['version'] ?? '',
1141
+		];
1142
+		EventEspresso\core\services\licensing\AddonLicense::register($addon_name, $license_data);
1143
+	}
1144
+
1145
+
1146
+	/**
1147
+	 * This deregisters an addon that was previously registered with a specific addon_name.
1148
+	 *
1149
+	 * @param string $addon_name the name for the addon that was previously registered
1150
+	 * @throws DomainException
1151
+	 * @throws InvalidArgumentException
1152
+	 * @throws InvalidDataTypeException
1153
+	 * @throws InvalidInterfaceException
1154
+	 * @since    4.3.0
1155
+	 */
1156
+	public static function deregister(string $addon_name = '')
1157
+	{
1158
+		if (isset(self::$_settings[ $addon_name ]['class_name'])) {
1159
+			try {
1160
+				do_action('AHEE__EE_Register_Addon__deregister__before', $addon_name);
1161
+				$class_name = self::$_settings[ $addon_name ]['class_name'];
1162
+				if (! empty(self::$_settings[ $addon_name ]['dms_paths'])) {
1163
+					// setup DMS
1164
+					EE_Register_Data_Migration_Scripts::deregister($addon_name);
1165
+				}
1166
+				if (! empty(self::$_settings[ $addon_name ]['admin_path'])) {
1167
+					// register admin page
1168
+					EE_Register_Admin_Page::deregister($addon_name);
1169
+				}
1170
+				if (! empty(self::$_settings[ $addon_name ]['module_paths'])) {
1171
+					// add to list of modules to be registered
1172
+					EE_Register_Module::deregister($addon_name);
1173
+				}
1174
+				if (
1175
+					! empty(self::$_settings[ $addon_name ]['shortcode_paths'])
1176
+					|| ! empty(self::$_settings[ $addon_name ]['shortcode_fqcns'])
1177
+				) {
1178
+					// add to list of shortcodes to be registered
1179
+					EE_Register_Shortcode::deregister($addon_name);
1180
+				}
1181
+				if (! empty(self::$_settings[ $addon_name ]['config_class'])) {
1182
+					// if config_class present let's register config.
1183
+					EE_Register_Config::deregister(self::$_settings[ $addon_name ]['config_class']);
1184
+				}
1185
+				if (! empty(self::$_settings[ $addon_name ]['widget_paths'])) {
1186
+					// add to list of widgets to be registered
1187
+					EE_Register_Widget::deregister($addon_name);
1188
+				}
1189
+				if (
1190
+					! empty(self::$_settings[ $addon_name ]['model_paths'])
1191
+					|| ! empty(self::$_settings[ $addon_name ]['class_paths'])
1192
+				) {
1193
+					// add to list of shortcodes to be registered
1194
+					EE_Register_Model::deregister($addon_name);
1195
+				}
1196
+				if (
1197
+					! empty(self::$_settings[ $addon_name ]['model_extension_paths'])
1198
+					|| ! empty(self::$_settings[ $addon_name ]['class_extension_paths'])
1199
+				) {
1200
+					// add to list of shortcodes to be registered
1201
+					EE_Register_Model_Extensions::deregister($addon_name);
1202
+				}
1203
+				if (! empty(self::$_settings[ $addon_name ]['message_types'])) {
1204
+					foreach ((array) self::$_settings[ $addon_name ]['message_types'] as $message_type => $message_type_settings) {
1205
+						EE_Register_Message_Type::deregister($message_type);
1206
+					}
1207
+				}
1208
+				// deregister capabilities for addon
1209
+				if (
1210
+					! empty(self::$_settings[ $addon_name ]['capabilities'])
1211
+					|| ! empty(self::$_settings[ $addon_name ]['capability_maps'])
1212
+				) {
1213
+					EE_Register_Capabilities::deregister($addon_name);
1214
+				}
1215
+				// deregister custom_post_types for addon
1216
+				if (! empty(self::$_settings[ $addon_name ]['custom_post_types'])) {
1217
+					EE_Register_CPT::deregister($addon_name);
1218
+				}
1219
+				if (! empty(self::$_settings[ $addon_name ]['payment_method_paths'])) {
1220
+					EE_Register_Payment_Method::deregister($addon_name);
1221
+				}
1222
+				$addon = EE_Registry::instance()->getAddon($class_name);
1223
+				if ($addon instanceof EE_Addon) {
1224
+					remove_action(
1225
+						'deactivate_' . $addon->get_main_plugin_file_basename(),
1226
+						[$addon, 'deactivation']
1227
+					);
1228
+					remove_action(
1229
+						'AHEE__EE_System__perform_activations_upgrades_and_migrations',
1230
+						[$addon, 'initialize_db_if_no_migrations_required']
1231
+					);
1232
+					// remove `after_registration` call
1233
+					remove_action(
1234
+						'AHEE__EE_System__load_espresso_addons__complete',
1235
+						[$addon, 'after_registration'],
1236
+						999
1237
+					);
1238
+				}
1239
+				EE_Registry::instance()->removeAddon($class_name);
1240
+				LoaderFactory::getLoader()->remove($class_name);
1241
+			} catch (OutOfBoundsException $addon_not_yet_registered_exception) {
1242
+				// the add-on was not yet registered in the registry,
1243
+				// so RegistryContainer::__get() throws this exception.
1244
+				// also no need to worry about this or log it,
1245
+				// it's ok to deregister an add-on before its registered in the registry
1246
+			} catch (Exception $e) {
1247
+				new ExceptionLogger($e);
1248
+			}
1249
+			unset(self::$_settings[ $addon_name ]);
1250
+			do_action('AHEE__EE_Register_Addon__deregister__after', $addon_name);
1251
+		}
1252
+	}
1253
+
1254
+
1255
+	public static function reset(): void
1256
+	{
1257
+		EE_Register_Addon::$_settings = [];
1258
+	}
1259
+
1260
+
1261
+	public static function resetAll(): void
1262
+	{
1263
+		// EE_Register_Addon::reset();
1264
+		EE_Register_Admin_Page::reset();
1265
+		EE_Register_Capabilities::reset();
1266
+		EE_Register_Config::reset();
1267
+		EE_Register_CPT::reset();
1268
+		EE_Register_Data_Migration_Scripts::reset();
1269
+		EE_Register_Message_Type::reset();
1270
+		EE_Register_Messages_Shortcode_Library::reset();
1271
+		EE_Register_Messages_Template_Pack::reset();
1272
+		EE_Register_Messages_Template_Variations::reset();
1273
+		EE_Register_Model::reset();
1274
+		EE_Register_Model_Extensions::reset();
1275
+		EE_Register_Module::reset();
1276
+		EE_Register_Payment_Method::reset();
1277
+		EE_Register_Personal_Data_Eraser::reset();
1278
+		EE_Register_Personal_Data_Exporter::reset();
1279
+		EE_Register_Privacy_Policy::reset();
1280
+		EE_Register_Shortcode::reset();
1281
+		EE_Register_Widget::reset();
1282
+	}
1283 1283
 }
Please login to merge, or discard this patch.