Completed
Branch BUG-11137-domain-base (1215f0)
by
unknown
115:05 queued 104:10
created
modules/core_rest_api/EED_Core_Rest_Api.module.php 2 patches
Indentation   +1249 added lines, -1249 removed lines patch added patch discarded remove patch
@@ -23,1256 +23,1256 @@
 block discarded – undo
23 23
 class EED_Core_Rest_Api extends \EED_Module
24 24
 {
25 25
 
26
-    const ee_api_namespace           = 'ee/v';
26
+	const ee_api_namespace           = 'ee/v';
27 27
 
28
-    const ee_api_namespace_for_regex = 'ee\/v([^/]*)\/';
29
-
30
-    const saved_routes_option_names  = 'ee_core_routes';
31
-
32
-    /**
33
-     * string used in _links response bodies to make them globally unique.
34
-     *
35
-     * @see http://v2.wp-api.org/extending/linking/
36
-     */
37
-    const ee_api_link_namespace = 'https://api.eventespresso.com/';
38
-
39
-    /**
40
-     * @var CalculatedModelFields
41
-     */
42
-    protected static $_field_calculator;
43
-
44
-
45
-
46
-    /**
47
-     * @return EED_Core_Rest_Api|EED_Module
48
-     */
49
-    public static function instance()
50
-    {
51
-        self::$_field_calculator = new CalculatedModelFields();
52
-        return parent::get_instance(__CLASS__);
53
-    }
54
-
55
-
56
-
57
-    /**
58
-     *    set_hooks - for hooking into EE Core, other modules, etc
59
-     *
60
-     * @access    public
61
-     * @return    void
62
-     */
63
-    public static function set_hooks()
64
-    {
65
-        self::set_hooks_both();
66
-    }
67
-
68
-
69
-
70
-    /**
71
-     *    set_hooks_admin - for hooking into EE Admin Core, other modules, etc
72
-     *
73
-     * @access    public
74
-     * @return    void
75
-     */
76
-    public static function set_hooks_admin()
77
-    {
78
-        self::set_hooks_both();
79
-    }
80
-
81
-
82
-
83
-    public static function set_hooks_both()
84
-    {
85
-        add_action('rest_api_init', array('EED_Core_Rest_Api', 'register_routes'), 10);
86
-        add_action('rest_api_init', array('EED_Core_Rest_Api', 'set_hooks_rest_api'), 5);
87
-        add_filter('rest_route_data', array('EED_Core_Rest_Api', 'hide_old_endpoints'), 10, 2);
88
-        add_filter('rest_index',
89
-            array('EventEspresso\core\libraries\rest_api\controllers\model\Meta', 'filterEeMetadataIntoIndex'));
90
-        EED_Core_Rest_Api::invalidate_cached_route_data_on_version_change();
91
-    }
92
-
93
-
94
-
95
-    /**
96
-     * sets up hooks which only need to be included as part of REST API requests;
97
-     * other requests like to the frontend or admin etc don't need them
98
-     *
99
-     * @throws \EE_Error
100
-     */
101
-    public static function set_hooks_rest_api()
102
-    {
103
-        //set hooks which account for changes made to the API
104
-        EED_Core_Rest_Api::_set_hooks_for_changes();
105
-    }
106
-
107
-
108
-
109
-    /**
110
-     * public wrapper of _set_hooks_for_changes.
111
-     * Loads all the hooks which make requests to old versions of the API
112
-     * appear the same as they always did
113
-     *
114
-     * @throws EE_Error
115
-     */
116
-    public static function set_hooks_for_changes()
117
-    {
118
-        self::_set_hooks_for_changes();
119
-    }
120
-
121
-
122
-
123
-    /**
124
-     * Loads all the hooks which make requests to old versions of the API
125
-     * appear the same as they always did
126
-     *
127
-     * @throws EE_Error
128
-     */
129
-    protected static function _set_hooks_for_changes()
130
-    {
131
-        $folder_contents = EEH_File::get_contents_of_folders(array(EE_LIBRARIES . 'rest_api' . DS . 'changes'), false);
132
-        foreach ($folder_contents as $classname_in_namespace => $filepath) {
133
-            //ignore the base parent class
134
-            //and legacy named classes
135
-            if ($classname_in_namespace === 'ChangesInBase'
136
-                || strpos($classname_in_namespace, 'Changes_In_') === 0
137
-            ) {
138
-                continue;
139
-            }
140
-            $full_classname = 'EventEspresso\core\libraries\rest_api\changes\\' . $classname_in_namespace;
141
-            if (class_exists($full_classname)) {
142
-                $instance_of_class = new $full_classname;
143
-                if ($instance_of_class instanceof ChangesInBase) {
144
-                    $instance_of_class->setHooks();
145
-                }
146
-            }
147
-        }
148
-    }
149
-
150
-
151
-
152
-    /**
153
-     * Filters the WP routes to add our EE-related ones. This takes a bit of time
154
-     * so we actually prefer to only do it when an EE plugin is activated or upgraded
155
-     *
156
-     * @throws \EE_Error
157
-     */
158
-    public static function register_routes()
159
-    {
160
-        foreach (EED_Core_Rest_Api::get_ee_route_data() as $namespace => $relative_routes) {
161
-            foreach ($relative_routes as $relative_route => $data_for_multiple_endpoints) {
162
-                /**
163
-                 * @var array $data_for_multiple_endpoints numerically indexed array
164
-                 *                                         but can also contain route options like {
165
-                 * @type array    $schema                      {
166
-                 * @type callable $schema_callback
167
-                 * @type array    $callback_args               arguments that will be passed to the callback, after the
168
-                 * WP_REST_Request of course
169
-                 * }
170
-                 * }
171
-                 */
172
-                //when registering routes, register all the endpoints' data at the same time
173
-                $multiple_endpoint_args = array();
174
-                foreach ($data_for_multiple_endpoints as $endpoint_key => $data_for_single_endpoint) {
175
-                    /**
176
-                     * @var array     $data_for_single_endpoint {
177
-                     * @type callable $callback
178
-                     * @type string methods
179
-                     * @type array args
180
-                     * @type array _links
181
-                     * @type array    $callback_args            arguments that will be passed to the callback, after the
182
-                     * WP_REST_Request of course
183
-                     * }
184
-                     */
185
-                    //skip route options
186
-                    if (! is_numeric($endpoint_key)) {
187
-                        continue;
188
-                    }
189
-                    if (! isset($data_for_single_endpoint['callback'], $data_for_single_endpoint['methods'])) {
190
-                        throw new EE_Error(
191
-                            esc_html__(
192
-                                // @codingStandardsIgnoreStart
193
-                                'Endpoint configuration data needs to have entries "callback" (callable) and "methods" (comma-separated list of accepts HTTP methods).',
194
-                                // @codingStandardsIgnoreEnd
195
-                                'event_espresso')
196
-                        );
197
-                    }
198
-                    $callback = $data_for_single_endpoint['callback'];
199
-                    $single_endpoint_args = array(
200
-                        'methods' => $data_for_single_endpoint['methods'],
201
-                        'args'    => isset($data_for_single_endpoint['args']) ? $data_for_single_endpoint['args']
202
-                            : array(),
203
-                    );
204
-                    if (isset($data_for_single_endpoint['_links'])) {
205
-                        $single_endpoint_args['_links'] = $data_for_single_endpoint['_links'];
206
-                    }
207
-                    if (isset($data_for_single_endpoint['callback_args'])) {
208
-                        $callback_args = $data_for_single_endpoint['callback_args'];
209
-                        $single_endpoint_args['callback'] = function (\WP_REST_Request $request) use (
210
-                            $callback,
211
-                            $callback_args
212
-                        ) {
213
-                            array_unshift($callback_args, $request);
214
-                            return call_user_func_array(
215
-                                $callback,
216
-                                $callback_args
217
-                            );
218
-                        };
219
-                    } else {
220
-                        $single_endpoint_args['callback'] = $data_for_single_endpoint['callback'];
221
-                    }
222
-                    $multiple_endpoint_args[] = $single_endpoint_args;
223
-                }
224
-                if (isset($data_for_multiple_endpoints['schema'])) {
225
-                    $schema_route_data = $data_for_multiple_endpoints['schema'];
226
-                    $schema_callback = $schema_route_data['schema_callback'];
227
-                    $callback_args = $schema_route_data['callback_args'];
228
-                    $multiple_endpoint_args['schema'] = function () use ($schema_callback, $callback_args) {
229
-                        return call_user_func_array(
230
-                            $schema_callback,
231
-                            $callback_args
232
-                        );
233
-                    };
234
-                }
235
-                register_rest_route(
236
-                    $namespace,
237
-                    $relative_route,
238
-                    $multiple_endpoint_args
239
-                );
240
-            }
241
-        }
242
-    }
243
-
244
-
245
-
246
-    /**
247
-     * Checks if there was a version change or something that merits invalidating the cached
248
-     * route data. If so, invalidates the cached route data so that it gets refreshed
249
-     * next time the WP API is used
250
-     */
251
-    public static function invalidate_cached_route_data_on_version_change()
252
-    {
253
-        if (EE_System::instance()->detect_req_type() !== EE_System::req_type_normal) {
254
-            EED_Core_Rest_Api::invalidate_cached_route_data();
255
-        }
256
-        foreach (EE_Registry::instance()->addons as $addon) {
257
-            if ($addon instanceof EE_Addon && $addon->detect_req_type() !== EE_System::req_type_normal) {
258
-                EED_Core_Rest_Api::invalidate_cached_route_data();
259
-            }
260
-        }
261
-    }
262
-
263
-
264
-
265
-    /**
266
-     * Removes the cached route data so it will get refreshed next time the WP API is used
267
-     */
268
-    public static function invalidate_cached_route_data()
269
-    {
270
-        //delete the saved EE REST API routes
271
-        foreach (EED_Core_Rest_Api::versions_served() as $version => $hidden) {
272
-            delete_option(EED_Core_Rest_Api::saved_routes_option_names . $version);
273
-        }
274
-    }
275
-
276
-
277
-
278
-    /**
279
-     * Gets the EE route data
280
-     *
281
-     * @return array top-level key is the namespace, next-level key is the route and its value is array{
282
-     * @throws \EE_Error
283
-     * @type string|array $callback
284
-     * @type string       $methods
285
-     * @type boolean      $hidden_endpoint
286
-     * }
287
-     */
288
-    public static function get_ee_route_data()
289
-    {
290
-        $ee_routes = array();
291
-        foreach (self::versions_served() as $version => $hidden_endpoints) {
292
-            $ee_routes[self::ee_api_namespace . $version] = self::_get_ee_route_data_for_version(
293
-                $version,
294
-                $hidden_endpoints
295
-            );
296
-        }
297
-        return $ee_routes;
298
-    }
299
-
300
-
301
-
302
-    /**
303
-     * Gets the EE route data from the wp options if it exists already,
304
-     * otherwise re-generates it and saves it to the option
305
-     *
306
-     * @param string  $version
307
-     * @param boolean $hidden_endpoints
308
-     * @return array
309
-     * @throws \EE_Error
310
-     */
311
-    protected static function _get_ee_route_data_for_version($version, $hidden_endpoints = false)
312
-    {
313
-        $ee_routes = get_option(self::saved_routes_option_names . $version, null);
314
-        if (! $ee_routes || (defined('EE_REST_API_DEBUG_MODE') && EE_REST_API_DEBUG_MODE)) {
315
-            $ee_routes = self::_save_ee_route_data_for_version($version, $hidden_endpoints);
316
-        }
317
-        return $ee_routes;
318
-    }
319
-
320
-
321
-
322
-    /**
323
-     * Saves the EE REST API route data to a wp option and returns it
324
-     *
325
-     * @param string  $version
326
-     * @param boolean $hidden_endpoints
327
-     * @return mixed|null
328
-     * @throws \EE_Error
329
-     */
330
-    protected static function _save_ee_route_data_for_version($version, $hidden_endpoints = false)
331
-    {
332
-        $instance = self::instance();
333
-        $routes = apply_filters(
334
-            'EED_Core_Rest_Api__save_ee_route_data_for_version__routes',
335
-            array_replace_recursive(
336
-                $instance->_get_config_route_data_for_version($version, $hidden_endpoints),
337
-                $instance->_get_meta_route_data_for_version($version, $hidden_endpoints),
338
-                $instance->_get_model_route_data_for_version($version, $hidden_endpoints),
339
-                $instance->_get_rpc_route_data_for_version($version, $hidden_endpoints)
340
-            )
341
-        );
342
-        $option_name = self::saved_routes_option_names . $version;
343
-        if (get_option($option_name)) {
344
-            update_option($option_name, $routes, true);
345
-        } else {
346
-            add_option($option_name, $routes, null, 'no');
347
-        }
348
-        return $routes;
349
-    }
350
-
351
-
352
-
353
-    /**
354
-     * Calculates all the EE routes and saves it to a WordPress option so we don't
355
-     * need to calculate it on every request
356
-     *
357
-     * @deprecated since version 4.9.1
358
-     * @return void
359
-     */
360
-    public static function save_ee_routes()
361
-    {
362
-        if (EE_Maintenance_Mode::instance()->models_can_query()) {
363
-            $instance = self::instance();
364
-            $routes = apply_filters(
365
-                'EED_Core_Rest_Api__save_ee_routes__routes',
366
-                array_replace_recursive(
367
-                    $instance->_register_config_routes(),
368
-                    $instance->_register_meta_routes(),
369
-                    $instance->_register_model_routes(),
370
-                    $instance->_register_rpc_routes()
371
-                )
372
-            );
373
-            update_option(self::saved_routes_option_names, $routes, true);
374
-        }
375
-    }
376
-
377
-
378
-
379
-    /**
380
-     * Gets all the route information relating to EE models
381
-     *
382
-     * @return array @see get_ee_route_data
383
-     * @deprecated since version 4.9.1
384
-     */
385
-    protected function _register_model_routes()
386
-    {
387
-        $model_routes = array();
388
-        foreach (self::versions_served() as $version => $hidden_endpoint) {
389
-            $model_routes[EED_Core_Rest_Api::ee_api_namespace
390
-                          . $version] = $this->_get_config_route_data_for_version($version, $hidden_endpoint);
391
-        }
392
-        return $model_routes;
393
-    }
394
-
395
-
396
-
397
-    /**
398
-     * Decides whether or not to add write endpoints for this model.
399
-     *
400
-     * Currently, this defaults to exclude all global tables and models
401
-     * which would allow inserting WP core data (we don't want to duplicate
402
-     * what WP API does, as it's unnecessary, extra work, and potentially extra bugs)
403
-     * @param EEM_Base $model
404
-     * @return bool
405
-     */
406
-    public static function should_have_write_endpoints(EEM_Base $model)
407
-    {
408
-        if ($model->is_wp_core_model()){
409
-            return false;
410
-        }
411
-        foreach($model->get_tables() as $table){
412
-            if( $table->is_global()){
413
-                return false;
414
-            }
415
-        }
416
-        return true;
417
-    }
418
-
419
-
420
-
421
-    /**
422
-     * Gets the names of all models which should have plural routes (eg `ee/v4.8.36/events`)
423
-     * in this versioned namespace of EE4
424
-     * @param $version
425
-     * @return array keys are model names (eg 'Event') and values ar either classnames (eg 'EEM_Event')
426
-     */
427
-    public static function model_names_with_plural_routes($version){
428
-        $model_version_info = new ModelVersionInfo($version);
429
-        $models_to_register = $model_version_info->modelsForRequestedVersion();
430
-        //let's not bother having endpoints for extra metas
431
-        unset(
432
-            $models_to_register['Extra_Meta'],
433
-            $models_to_register['Extra_Join'],
434
-            $models_to_register['Post_Meta']
435
-        );
436
-        return apply_filters(
437
-            'FHEE__EED_Core_REST_API___register_model_routes',
438
-            $models_to_register
439
-        );
440
-    }
441
-
442
-
443
-
444
-    /**
445
-     * Gets the route data for EE models in the specified version
446
-     *
447
-     * @param string  $version
448
-     * @param boolean $hidden_endpoint
449
-     * @return array
450
-     * @throws EE_Error
451
-     */
452
-    protected function _get_model_route_data_for_version($version, $hidden_endpoint = false)
453
-    {
454
-        $model_routes = array();
455
-        $model_version_info = new ModelVersionInfo($version);
456
-        foreach (EED_Core_Rest_Api::model_names_with_plural_routes($version) as $model_name => $model_classname) {
457
-            $model = \EE_Registry::instance()->load_model($model_name);
458
-            //if this isn't a valid model then let's skip iterate to the next item in the loop.
459
-            if (! $model instanceof EEM_Base) {
460
-                continue;
461
-            }
462
-            //yes we could just register one route for ALL models, but then they wouldn't show up in the index
463
-            $plural_model_route = EED_Core_Rest_Api::get_collection_route($model);
464
-            $singular_model_route = EED_Core_Rest_Api::get_entity_route($model, '(?P<id>[^\/]+)');
465
-            $model_routes[$plural_model_route] = array(
466
-                array(
467
-                    'callback'        => array(
468
-                        'EventEspresso\core\libraries\rest_api\controllers\model\Read',
469
-                        'handleRequestGetAll',
470
-                    ),
471
-                    'callback_args'   => array($version, $model_name),
472
-                    'methods'         => WP_REST_Server::READABLE,
473
-                    'hidden_endpoint' => $hidden_endpoint,
474
-                    'args'            => $this->_get_read_query_params($model, $version),
475
-                    '_links'          => array(
476
-                        'self' => rest_url(EED_Core_Rest_Api::ee_api_namespace . $version . $singular_model_route),
477
-                    ),
478
-                ),
479
-                'schema' => array(
480
-                    'schema_callback' => array(
481
-                        'EventEspresso\core\libraries\rest_api\controllers\model\Read',
482
-                        'handleSchemaRequest',
483
-                    ),
484
-                    'callback_args'   => array($version, $model_name),
485
-                ),
486
-            );
487
-            $model_routes[$singular_model_route] = array(
488
-                array(
489
-                    'callback'        => array(
490
-                        'EventEspresso\core\libraries\rest_api\controllers\model\Read',
491
-                        'handleRequestGetOne',
492
-                    ),
493
-                    'callback_args'   => array($version, $model_name),
494
-                    'methods'         => WP_REST_Server::READABLE,
495
-                    'hidden_endpoint' => $hidden_endpoint,
496
-                    'args'            => $this->_get_response_selection_query_params($model, $version),
497
-                ),
498
-            );
499
-            if( apply_filters(
500
-                'FHEE__EED_Core_Rest_Api___get_model_route_data_for_version__add_write_endpoints',
501
-                EED_Core_Rest_Api::should_have_write_endpoints($model),
502
-                $model
503
-            )){
504
-                $model_routes[$plural_model_route][] = array(
505
-                    'callback'        => array(
506
-                        'EventEspresso\core\libraries\rest_api\controllers\model\Write',
507
-                        'handleRequestInsert',
508
-                    ),
509
-                    'callback_args'   => array($version, $model_name),
510
-                    'methods'         => WP_REST_Server::CREATABLE,
511
-                    'hidden_endpoint' => $hidden_endpoint,
512
-                    'args'            => $this->_get_write_params($model_name, $model_version_info, true),
513
-                );
514
-                $model_routes[$singular_model_route] = array_merge(
515
-                    $model_routes[$singular_model_route],
516
-                    array(
517
-                        array(
518
-                            'callback'        => array(
519
-                                'EventEspresso\core\libraries\rest_api\controllers\model\Write',
520
-                                'handleRequestUpdate',
521
-                            ),
522
-                            'callback_args'   => array($version, $model_name),
523
-                            'methods'         => WP_REST_Server::EDITABLE,
524
-                            'hidden_endpoint' => $hidden_endpoint,
525
-                            'args'            => $this->_get_write_params($model_name, $model_version_info),
526
-                        ),
527
-                        array(
528
-                            'callback'        => array(
529
-                                'EventEspresso\core\libraries\rest_api\controllers\model\Write',
530
-                                'handleRequestDelete',
531
-                            ),
532
-                            'callback_args'   => array($version, $model_name),
533
-                            'methods'         => WP_REST_Server::DELETABLE,
534
-                            'hidden_endpoint' => $hidden_endpoint,
535
-                            'args'            => $this->_get_delete_query_params($model, $version),
536
-                        )
537
-                    )
538
-                );
539
-            }
540
-            foreach ($model->relation_settings() as $relation_name => $relation_obj) {
541
-
542
-                $related_route = EED_Core_Rest_Api::get_relation_route_via(
543
-                    $model,
544
-                    '(?P<id>[^\/]+)',
545
-                    $relation_obj
546
-                );
547
-                $endpoints = array(
548
-                    array(
549
-                        'callback'        => array(
550
-                            'EventEspresso\core\libraries\rest_api\controllers\model\Read',
551
-                            'handleRequestGetRelated',
552
-                        ),
553
-                        'callback_args'   => array($version, $model_name, $relation_name),
554
-                        'methods'         => WP_REST_Server::READABLE,
555
-                        'hidden_endpoint' => $hidden_endpoint,
556
-                        'args'            => $this->_get_read_query_params($relation_obj->get_other_model(), $version),
557
-                    ),
558
-                );
559
-                $model_routes[$related_route] = $endpoints;
560
-            }
561
-        }
562
-        return $model_routes;
563
-    }
564
-
565
-
566
-
567
-    /**
568
-     * Gets the relative URI to a model's REST API plural route, after the EE4 versioned namespace,
569
-     * excluding the preceding slash.
570
-     * Eg you pass get_plural_route_to('Event') = 'events'
571
-     *
572
-     * @param EEM_Base $model
573
-     * @return string
574
-     */
575
-    public static function get_collection_route(EEM_Base $model)
576
-    {
577
-        return EEH_Inflector::pluralize_and_lower($model->get_this_model_name());
578
-    }
579
-
580
-
581
-
582
-    /**
583
-     * Gets the relative URI to a model's REST API singular route, after the EE4 versioned namespace,
584
-     * excluding the preceding slash.
585
-     * Eg you pass get_plural_route_to('Event', 12) = 'events/12'
586
-     *
587
-     * @param EEM_Base $model eg Event or Venue
588
-     * @param string $id
589
-     * @return string
590
-     */
591
-    public static function get_entity_route($model, $id)
592
-    {
593
-        return EED_Core_Rest_Api::get_collection_route($model). '/' . $id;
594
-    }
595
-
596
-
597
-    /**
598
-     * Gets the relative URI to a model's REST API singular route, after the EE4 versioned namespace,
599
-     * excluding the preceding slash.
600
-     * Eg you pass get_plural_route_to('Event', 12) = 'events/12'
601
-     *
602
-     * @param EEM_Base                 $model eg Event or Venue
603
-     * @param string                 $id
604
-     * @param EE_Model_Relation_Base $relation_obj
605
-     * @return string
606
-     */
607
-    public static function get_relation_route_via(EEM_Base $model, $id, EE_Model_Relation_Base $relation_obj)
608
-    {
609
-        $related_model_name_endpoint_part = ModelRead::getRelatedEntityName(
610
-            $relation_obj->get_other_model()->get_this_model_name(),
611
-            $relation_obj
612
-        );
613
-        return EED_Core_Rest_Api::get_entity_route($model, $id) . '/' . $related_model_name_endpoint_part;
614
-    }
615
-
616
-
617
-
618
-    /**
619
-     * Adds onto the $relative_route the EE4 REST API versioned namespace.
620
-     * Eg if given '4.8.36' and 'events', will return 'ee/v4.8.36/events'
621
-     * @param string $relative_route
622
-     * @param string $version
623
-     * @return string
624
-     */
625
-    public static function get_versioned_route_to($relative_route, $version = '4.8.36'){
626
-        return '/' . EED_Core_Rest_Api::ee_api_namespace . $version . '/' . $relative_route;
627
-    }
628
-
629
-
630
-
631
-    /**
632
-     * Adds all the RPC-style routes (remote procedure call-like routes, ie
633
-     * routes that don't conform to the traditional REST CRUD-style).
634
-     *
635
-     * @deprecated since 4.9.1
636
-     */
637
-    protected function _register_rpc_routes()
638
-    {
639
-        $routes = array();
640
-        foreach (self::versions_served() as $version => $hidden_endpoint) {
641
-            $routes[self::ee_api_namespace . $version] = $this->_get_rpc_route_data_for_version(
642
-                $version,
643
-                $hidden_endpoint
644
-            );
645
-        }
646
-        return $routes;
647
-    }
648
-
649
-
650
-
651
-    /**
652
-     * @param string  $version
653
-     * @param boolean $hidden_endpoint
654
-     * @return array
655
-     */
656
-    protected function _get_rpc_route_data_for_version($version, $hidden_endpoint = false)
657
-    {
658
-        $this_versions_routes = array();
659
-        //checkin endpoint
660
-        $this_versions_routes['registrations/(?P<REG_ID>\d+)/toggle_checkin_for_datetime/(?P<DTT_ID>\d+)'] = array(
661
-            array(
662
-                'callback'        => array(
663
-                    'EventEspresso\core\libraries\rest_api\controllers\rpc\Checkin',
664
-                    'handleRequestToggleCheckin',
665
-                ),
666
-                'methods'         => WP_REST_Server::CREATABLE,
667
-                'hidden_endpoint' => $hidden_endpoint,
668
-                'args'            => array(
669
-                    'force' => array(
670
-                        'required'    => false,
671
-                        'default'     => false,
672
-                        'description' => __(
673
-                            // @codingStandardsIgnoreStart
674
-                            'Whether to force toggle checkin, or to verify the registration status and allowed ticket uses',
675
-                            // @codingStandardsIgnoreEnd
676
-                            'event_espresso'
677
-                        ),
678
-                    ),
679
-                ),
680
-                'callback_args'   => array($version),
681
-            ),
682
-        );
683
-        return apply_filters(
684
-            'FHEE__EED_Core_Rest_Api___register_rpc_routes__this_versions_routes',
685
-            $this_versions_routes,
686
-            $version,
687
-            $hidden_endpoint
688
-        );
689
-    }
690
-
691
-
692
-
693
-    /**
694
-     * Gets the query params that can be used when request one or many
695
-     *
696
-     * @param EEM_Base $model
697
-     * @param string   $version
698
-     * @return array
699
-     */
700
-    protected function _get_response_selection_query_params(\EEM_Base $model, $version)
701
-    {
702
-        return apply_filters(
703
-            'FHEE__EED_Core_Rest_Api___get_response_selection_query_params',
704
-            array(
705
-                'include'   => array(
706
-                    'required' => false,
707
-                    'default'  => '*',
708
-                    'type'     => 'string',
709
-                ),
710
-                'calculate' => array(
711
-                    'required'          => false,
712
-                    'default'           => '',
713
-                    'enum'              => self::$_field_calculator->retrieveCalculatedFieldsForModel($model),
714
-                    'type'              => 'string',
715
-                    //because we accept a CSV'd list of the enumerated strings, WP core validation and sanitization
716
-                    //freaks out. We'll just validate this argument while handling the request
717
-                    'validate_callback' => null,
718
-                    'sanitize_callback' => null,
719
-                ),
720
-            ),
721
-            $model,
722
-            $version
723
-        );
724
-    }
725
-
726
-
727
-
728
-    /**
729
-     * Gets the parameters acceptable for delete requests
730
-     *
731
-     * @param \EEM_Base $model
732
-     * @param string    $version
733
-     * @return array
734
-     */
735
-    protected function _get_delete_query_params(\EEM_Base $model, $version)
736
-    {
737
-        $params_for_delete = array(
738
-            'allow_blocking' => array(
739
-                'required' => false,
740
-                'default'  => true,
741
-                'type'     => 'boolean',
742
-            ),
743
-        );
744
-        $params_for_delete['force'] = array(
745
-            'required' => false,
746
-            'default'  => false,
747
-            'type'     => 'boolean',
748
-        );
749
-        return apply_filters(
750
-            'FHEE__EED_Core_Rest_Api___get_delete_query_params',
751
-            $params_for_delete,
752
-            $model,
753
-            $version
754
-        );
755
-    }
756
-
757
-
758
-
759
-    /**
760
-     * Gets info about reading query params that are acceptable
761
-     *
762
-     * @param \EEM_Base $model eg 'Event' or 'Venue'
763
-     * @param  string   $version
764
-     * @return array    describing the args acceptable when querying this model
765
-     * @throws EE_Error
766
-     */
767
-    protected function _get_read_query_params(\EEM_Base $model, $version)
768
-    {
769
-        $default_orderby = array();
770
-        foreach ($model->get_combined_primary_key_fields() as $key_field) {
771
-            $default_orderby[$key_field->get_name()] = 'ASC';
772
-        }
773
-        return array_merge(
774
-            $this->_get_response_selection_query_params($model, $version),
775
-            array(
776
-                'where'    => array(
777
-                    'required' => false,
778
-                    'default'  => array(),
779
-                    'type'     => 'object',
780
-                    //because we accept an almost infinite list of possible where conditions, WP
781
-                    // core validation and sanitization freaks out. We'll just validate this argument
782
-                    // while handling the request
783
-                    'validate_callback' => null,
784
-                    'sanitize_callback' => null,
785
-                ),
786
-                'limit'    => array(
787
-                    'required' => false,
788
-                    'default'  => EED_Core_Rest_Api::get_default_query_limit(),
789
-                    'type'     => array(
790
-                        'array',
791
-                        'string',
792
-                        'integer',
793
-                    ),
794
-                    //because we accept a variety of types, WP core validation and sanitization
795
-                    //freaks out. We'll just validate this argument while handling the request
796
-                    'validate_callback' => null,
797
-                    'sanitize_callback' => null,
798
-                ),
799
-                'order_by' => array(
800
-                    'required' => false,
801
-                    'default'  => $default_orderby,
802
-                    'type'     => array(
803
-                        'object',
804
-                        'string',
805
-                    ),//because we accept a variety of types, WP core validation and sanitization
806
-                    //freaks out. We'll just validate this argument while handling the request
807
-                    'validate_callback' => null,
808
-                    'sanitize_callback' => null,
809
-                ),
810
-                'group_by' => array(
811
-                    'required' => false,
812
-                    'default'  => null,
813
-                    'type'     => array(
814
-                        'object',
815
-                        'string',
816
-                    ),
817
-                    //because we accept  an almost infinite list of possible groupings,
818
-                    // WP core validation and sanitization
819
-                    //freaks out. We'll just validate this argument while handling the request
820
-                    'validate_callback' => null,
821
-                    'sanitize_callback' => null,
822
-                ),
823
-                'having'   => array(
824
-                    'required' => false,
825
-                    'default'  => null,
826
-                    'type'     => 'object',
827
-                    //because we accept an almost infinite list of possible where conditions, WP
828
-                    // core validation and sanitization freaks out. We'll just validate this argument
829
-                    // while handling the request
830
-                    'validate_callback' => null,
831
-                    'sanitize_callback' => null,
832
-                ),
833
-                'caps'     => array(
834
-                    'required' => false,
835
-                    'default'  => EEM_Base::caps_read,
836
-                    'type'     => 'string',
837
-                    'enum'     => array(
838
-                        EEM_Base::caps_read,
839
-                        EEM_Base::caps_read_admin,
840
-                        EEM_Base::caps_edit,
841
-                        EEM_Base::caps_delete
842
-                    )
843
-                ),
844
-            )
845
-        );
846
-    }
847
-
848
-
849
-
850
-    /**
851
-     * Gets parameter information for a model regarding writing data
852
-     *
853
-     * @param string           $model_name
854
-     * @param ModelVersionInfo $model_version_info
855
-     * @param boolean          $create                                       whether this is for request to create (in which case we need
856
-     *                                                                       all required params) or just to update (in which case we don't need those on every request)
857
-     * @return array
858
-     */
859
-    protected function _get_write_params(
860
-        $model_name,
861
-        ModelVersionInfo $model_version_info,
862
-        $create = false
863
-    ) {
864
-        $model = EE_Registry::instance()->load_model($model_name);
865
-        $fields = $model_version_info->fieldsOnModelInThisVersion($model);
866
-        $args_info = array();
867
-        foreach ($fields as $field_name => $field_obj) {
868
-            if ($field_obj->is_auto_increment()) {
869
-                //totally ignore auto increment IDs
870
-                continue;
871
-            }
872
-            $arg_info = $field_obj->getSchema();
873
-            $required = $create && ! $field_obj->is_nullable() && $field_obj->get_default_value() === null;
874
-            $arg_info['required'] = $required;
875
-            //remove the read-only flag. If it were read-only we wouldn't list it as an argument while writing, right?
876
-            unset($arg_info['readonly']);
877
-            $schema_properties = $field_obj->getSchemaProperties();
878
-            if (
879
-                isset($schema_properties['raw'])
880
-                && $field_obj->getSchemaType() === 'object'
881
-            ) {
882
-                //if there's a "raw" form of this argument, use those properties instead
883
-                $arg_info = array_replace(
884
-                    $arg_info,
885
-                    $schema_properties['raw']
886
-                );
887
-            }
888
-            $arg_info['default'] = ModelDataTranslator::prepareFieldValueForJson(
889
-                $field_obj,
890
-                $field_obj->get_default_value(),
891
-                $model_version_info->requestedVersion()
892
-            );
893
-            //we do our own validation and sanitization within the controller
894
-            $arg_info['sanitize_callback'] =
895
-                array(
896
-                    'EED_Core_Rest_Api',
897
-                    'default_sanitize_callback',
898
-                );
899
-            $args_info[$field_name] = $arg_info;
900
-            if ($field_obj instanceof EE_Datetime_Field) {
901
-                $gmt_arg_info = $arg_info;
902
-                $gmt_arg_info['description'] = sprintf(
903
-                    esc_html__(
904
-                        '%1$s - the value for this field in UTC. Ignored if %2$s is provided.',
905
-                        'event_espresso'
906
-                    ),
907
-                    $field_obj->get_nicename(),
908
-                    $field_name
909
-                );
910
-                $args_info[$field_name . '_gmt'] = $gmt_arg_info;
911
-            }
912
-        }
913
-        return $args_info;
914
-    }
915
-
916
-
917
-
918
-    /**
919
-     * Replacement for WP API's 'rest_parse_request_arg'.
920
-     * If the value is blank but not required, don't bother validating it.
921
-     * Also, it uses our email validation instead of WP API's default.
922
-     *
923
-     * @param                 $value
924
-     * @param WP_REST_Request $request
925
-     * @param                 $param
926
-     * @return bool|true|WP_Error
927
-     * @throws InvalidArgumentException
928
-     * @throws InvalidInterfaceException
929
-     * @throws InvalidDataTypeException
930
-     */
931
-    public static function default_sanitize_callback( $value, WP_REST_Request $request, $param)
932
-    {
933
-        $attributes = $request->get_attributes();
934
-        if (! isset($attributes['args'][$param])
935
-            || ! is_array($attributes['args'][$param])) {
936
-            $validation_result = true;
937
-        } else {
938
-            $args = $attributes['args'][$param];
939
-            if ((
940
-                    $value === ''
941
-                    || $value === null
942
-                )
943
-                && (! isset($args['required'])
944
-                    || $args['required'] === false
945
-                )
946
-            ) {
947
-                //not required and not provided? that's cool
948
-                $validation_result = true;
949
-            } elseif (isset($args['format'])
950
-                && $args['format'] === 'email'
951
-            ) {
952
-                $validation_result = true;
953
-                if (! self::_validate_email($value)) {
954
-                    $validation_result = new WP_Error(
955
-                        'rest_invalid_param',
956
-                        esc_html__(
957
-                            'The email address is not valid or does not exist.',
958
-                            'event_espresso'
959
-                        )
960
-                    );
961
-                }
962
-            } else {
963
-                $validation_result = rest_validate_value_from_schema($value, $args, $param);
964
-            }
965
-        }
966
-        if (is_wp_error($validation_result)) {
967
-            return $validation_result;
968
-        }
969
-        return rest_sanitize_request_arg($value, $request, $param);
970
-    }
971
-
972
-
973
-
974
-    /**
975
-     * Returns whether or not this email address is valid. Copied from EE_Email_Validation_Strategy::_validate_email()
976
-     *
977
-     * @param $email
978
-     * @return bool
979
-     * @throws InvalidArgumentException
980
-     * @throws InvalidInterfaceException
981
-     * @throws InvalidDataTypeException
982
-     */
983
-    protected static function _validate_email($email){
984
-        try {
985
-            EmailAddressFactory::create($email);
986
-            return true;
987
-        } catch (EmailValidationException $e) {
988
-            return false;
989
-        }
990
-    }
991
-
992
-
993
-
994
-    /**
995
-     * Gets routes for the config
996
-     *
997
-     * @return array @see _register_model_routes
998
-     * @deprecated since version 4.9.1
999
-     */
1000
-    protected function _register_config_routes()
1001
-    {
1002
-        $config_routes = array();
1003
-        foreach (self::versions_served() as $version => $hidden_endpoint) {
1004
-            $config_routes[self::ee_api_namespace . $version] = $this->_get_config_route_data_for_version(
1005
-                $version,
1006
-                $hidden_endpoint
1007
-            );
1008
-        }
1009
-        return $config_routes;
1010
-    }
1011
-
1012
-
1013
-
1014
-    /**
1015
-     * Gets routes for the config for the specified version
1016
-     *
1017
-     * @param string  $version
1018
-     * @param boolean $hidden_endpoint
1019
-     * @return array
1020
-     */
1021
-    protected function _get_config_route_data_for_version($version, $hidden_endpoint)
1022
-    {
1023
-        return array(
1024
-            'config'    => array(
1025
-                array(
1026
-                    'callback'        => array(
1027
-                        'EventEspresso\core\libraries\rest_api\controllers\config\Read',
1028
-                        'handleRequest',
1029
-                    ),
1030
-                    'methods'         => WP_REST_Server::READABLE,
1031
-                    'hidden_endpoint' => $hidden_endpoint,
1032
-                    'callback_args'   => array($version),
1033
-                ),
1034
-            ),
1035
-            'site_info' => array(
1036
-                array(
1037
-                    'callback'        => array(
1038
-                        'EventEspresso\core\libraries\rest_api\controllers\config\Read',
1039
-                        'handleRequestSiteInfo',
1040
-                    ),
1041
-                    'methods'         => WP_REST_Server::READABLE,
1042
-                    'hidden_endpoint' => $hidden_endpoint,
1043
-                    'callback_args'   => array($version),
1044
-                ),
1045
-            ),
1046
-        );
1047
-    }
1048
-
1049
-
1050
-
1051
-    /**
1052
-     * Gets the meta info routes
1053
-     *
1054
-     * @return array @see _register_model_routes
1055
-     * @deprecated since version 4.9.1
1056
-     */
1057
-    protected function _register_meta_routes()
1058
-    {
1059
-        $meta_routes = array();
1060
-        foreach (self::versions_served() as $version => $hidden_endpoint) {
1061
-            $meta_routes[self::ee_api_namespace . $version] = $this->_get_meta_route_data_for_version(
1062
-                $version,
1063
-                $hidden_endpoint
1064
-            );
1065
-        }
1066
-        return $meta_routes;
1067
-    }
1068
-
1069
-
1070
-
1071
-    /**
1072
-     * @param string  $version
1073
-     * @param boolean $hidden_endpoint
1074
-     * @return array
1075
-     */
1076
-    protected function _get_meta_route_data_for_version($version, $hidden_endpoint = false)
1077
-    {
1078
-        return array(
1079
-            'resources' => array(
1080
-                array(
1081
-                    'callback'        => array(
1082
-                        'EventEspresso\core\libraries\rest_api\controllers\model\Meta',
1083
-                        'handleRequestModelsMeta',
1084
-                    ),
1085
-                    'methods'         => WP_REST_Server::READABLE,
1086
-                    'hidden_endpoint' => $hidden_endpoint,
1087
-                    'callback_args'   => array($version),
1088
-                ),
1089
-            ),
1090
-        );
1091
-    }
1092
-
1093
-
1094
-
1095
-    /**
1096
-     * Tries to hide old 4.6 endpoints from the
1097
-     *
1098
-     * @param array $route_data
1099
-     * @return array
1100
-     * @throws \EE_Error
1101
-     */
1102
-    public static function hide_old_endpoints($route_data)
1103
-    {
1104
-        //allow API clients to override which endpoints get hidden, in case
1105
-        //they want to discover particular endpoints
1106
-        //also, we don't have access to the request so we have to just grab it from the superglobal
1107
-        $force_show_ee_namespace = ltrim(
1108
-            EEH_Array::is_set($_REQUEST, 'force_show_ee_namespace', ''),
1109
-            '/'
1110
-        );
1111
-        foreach (EED_Core_Rest_Api::get_ee_route_data() as $namespace => $relative_urls) {
1112
-            foreach ($relative_urls as $resource_name => $endpoints) {
1113
-                foreach ($endpoints as $key => $endpoint) {
1114
-                    //skip schema and other route options
1115
-                    if (! is_numeric($key)) {
1116
-                        continue;
1117
-                    }
1118
-                    //by default, hide "hidden_endpoint"s, unless the request indicates
1119
-                    //to $force_show_ee_namespace, in which case only show that one
1120
-                    //namespace's endpoints (and hide all others)
1121
-                    if (
1122
-                        ($force_show_ee_namespace !== '' && $force_show_ee_namespace !== $namespace)
1123
-                        || ($endpoint['hidden_endpoint'] && $force_show_ee_namespace === '')
1124
-                    ) {
1125
-                        $full_route = '/' . ltrim($namespace, '/');
1126
-                        $full_route .= '/' . ltrim($resource_name, '/');
1127
-                        unset($route_data[$full_route]);
1128
-                    }
1129
-                }
1130
-            }
1131
-        }
1132
-        return $route_data;
1133
-    }
1134
-
1135
-
1136
-
1137
-    /**
1138
-     * Returns an array describing which versions of core support serving requests for.
1139
-     * Keys are core versions' major and minor version, and values are the
1140
-     * LOWEST requested version they can serve. Eg, 4.7 can serve requests for 4.6-like
1141
-     * data by just removing a few models and fields from the responses. However, 4.15 might remove
1142
-     * the answers table entirely, in which case it would be very difficult for
1143
-     * it to serve 4.6-style responses.
1144
-     * Versions of core that are missing from this array are unknowns.
1145
-     * previous ver
1146
-     *
1147
-     * @return array
1148
-     */
1149
-    public static function version_compatibilities()
1150
-    {
1151
-        return apply_filters(
1152
-            'FHEE__EED_Core_REST_API__version_compatibilities',
1153
-            array(
1154
-                '4.8.29' => '4.8.29',
1155
-                '4.8.33' => '4.8.29',
1156
-                '4.8.34' => '4.8.29',
1157
-                '4.8.36' => '4.8.29',
1158
-            )
1159
-        );
1160
-    }
1161
-
1162
-
1163
-
1164
-    /**
1165
-     * Gets the latest API version served. Eg if there
1166
-     * are two versions served of the API, 4.8.29 and 4.8.32, and
1167
-     * we are on core version 4.8.34, it will return the string "4.8.32"
1168
-     *
1169
-     * @return string
1170
-     */
1171
-    public static function latest_rest_api_version()
1172
-    {
1173
-        $versions_served = \EED_Core_Rest_Api::versions_served();
1174
-        $versions_served_keys = array_keys($versions_served);
1175
-        return end($versions_served_keys);
1176
-    }
1177
-
1178
-
1179
-
1180
-    /**
1181
-     * Using EED_Core_Rest_Api::version_compatibilities(), determines what version of
1182
-     * EE the API can serve requests for. Eg, if we are on 4.15 of core, and
1183
-     * we can serve requests from 4.12 or later, this will return array( '4.12', '4.13', '4.14', '4.15' ).
1184
-     * We also indicate whether or not this version should be put in the index or not
1185
-     *
1186
-     * @return array keys are API version numbers (just major and minor numbers), and values
1187
-     * are whether or not they should be hidden
1188
-     */
1189
-    public static function versions_served()
1190
-    {
1191
-        $versions_served = array();
1192
-        $possibly_served_versions = EED_Core_Rest_Api::version_compatibilities();
1193
-        $lowest_compatible_version = end($possibly_served_versions);
1194
-        reset($possibly_served_versions);
1195
-        $versions_served_historically = array_keys($possibly_served_versions);
1196
-        $latest_version = end($versions_served_historically);
1197
-        reset($versions_served_historically);
1198
-        //for each version of core we have ever served:
1199
-        foreach ($versions_served_historically as $key_versioned_endpoint) {
1200
-            //if it's not above the current core version, and it's compatible with the current version of core
1201
-            if ($key_versioned_endpoint === $latest_version) {
1202
-                //don't hide the latest version in the index
1203
-                $versions_served[$key_versioned_endpoint] = false;
1204
-            } elseif (
1205
-                $key_versioned_endpoint >= $lowest_compatible_version
1206
-                && $key_versioned_endpoint < EED_Core_Rest_Api::core_version()
1207
-            ) {
1208
-                //include, but hide, previous versions which are still supported
1209
-                $versions_served[$key_versioned_endpoint] = true;
1210
-            } elseif (apply_filters(
1211
-                'FHEE__EED_Core_Rest_Api__versions_served__include_incompatible_versions',
1212
-                false,
1213
-                $possibly_served_versions
1214
-            )) {
1215
-                //if a version is no longer supported, don't include it in index or list of versions served
1216
-                $versions_served[$key_versioned_endpoint] = true;
1217
-            }
1218
-        }
1219
-        return $versions_served;
1220
-    }
1221
-
1222
-
1223
-
1224
-    /**
1225
-     * Gets the major and minor version of EE core's version string
1226
-     *
1227
-     * @return string
1228
-     */
1229
-    public static function core_version()
1230
-    {
1231
-        return apply_filters(
1232
-            'FHEE__EED_Core_REST_API__core_version',
1233
-            implode(
1234
-                '.',
1235
-                array_slice(
1236
-                    explode(
1237
-                        '.',
1238
-                        espresso_version()
1239
-                    ),
1240
-                0,
1241
-                3
1242
-                )
1243
-            )
1244
-        );
1245
-    }
1246
-
1247
-
1248
-
1249
-    /**
1250
-     * Gets the default limit that should be used when querying for resources
1251
-     *
1252
-     * @return int
1253
-     */
1254
-    public static function get_default_query_limit()
1255
-    {
1256
-        //we actually don't use a const because we want folks to always use
1257
-        //this method, not the const directly
1258
-        return apply_filters(
1259
-            'FHEE__EED_Core_Rest_Api__get_default_query_limit',
1260
-            50
1261
-        );
1262
-    }
1263
-
1264
-
1265
-
1266
-    /**
1267
-     *    run - initial module setup
1268
-     *
1269
-     * @access    public
1270
-     * @param  WP $WP
1271
-     * @return    void
1272
-     */
1273
-    public function run($WP)
1274
-    {
1275
-    }
28
+	const ee_api_namespace_for_regex = 'ee\/v([^/]*)\/';
29
+
30
+	const saved_routes_option_names  = 'ee_core_routes';
31
+
32
+	/**
33
+	 * string used in _links response bodies to make them globally unique.
34
+	 *
35
+	 * @see http://v2.wp-api.org/extending/linking/
36
+	 */
37
+	const ee_api_link_namespace = 'https://api.eventespresso.com/';
38
+
39
+	/**
40
+	 * @var CalculatedModelFields
41
+	 */
42
+	protected static $_field_calculator;
43
+
44
+
45
+
46
+	/**
47
+	 * @return EED_Core_Rest_Api|EED_Module
48
+	 */
49
+	public static function instance()
50
+	{
51
+		self::$_field_calculator = new CalculatedModelFields();
52
+		return parent::get_instance(__CLASS__);
53
+	}
54
+
55
+
56
+
57
+	/**
58
+	 *    set_hooks - for hooking into EE Core, other modules, etc
59
+	 *
60
+	 * @access    public
61
+	 * @return    void
62
+	 */
63
+	public static function set_hooks()
64
+	{
65
+		self::set_hooks_both();
66
+	}
67
+
68
+
69
+
70
+	/**
71
+	 *    set_hooks_admin - for hooking into EE Admin Core, other modules, etc
72
+	 *
73
+	 * @access    public
74
+	 * @return    void
75
+	 */
76
+	public static function set_hooks_admin()
77
+	{
78
+		self::set_hooks_both();
79
+	}
80
+
81
+
82
+
83
+	public static function set_hooks_both()
84
+	{
85
+		add_action('rest_api_init', array('EED_Core_Rest_Api', 'register_routes'), 10);
86
+		add_action('rest_api_init', array('EED_Core_Rest_Api', 'set_hooks_rest_api'), 5);
87
+		add_filter('rest_route_data', array('EED_Core_Rest_Api', 'hide_old_endpoints'), 10, 2);
88
+		add_filter('rest_index',
89
+			array('EventEspresso\core\libraries\rest_api\controllers\model\Meta', 'filterEeMetadataIntoIndex'));
90
+		EED_Core_Rest_Api::invalidate_cached_route_data_on_version_change();
91
+	}
92
+
93
+
94
+
95
+	/**
96
+	 * sets up hooks which only need to be included as part of REST API requests;
97
+	 * other requests like to the frontend or admin etc don't need them
98
+	 *
99
+	 * @throws \EE_Error
100
+	 */
101
+	public static function set_hooks_rest_api()
102
+	{
103
+		//set hooks which account for changes made to the API
104
+		EED_Core_Rest_Api::_set_hooks_for_changes();
105
+	}
106
+
107
+
108
+
109
+	/**
110
+	 * public wrapper of _set_hooks_for_changes.
111
+	 * Loads all the hooks which make requests to old versions of the API
112
+	 * appear the same as they always did
113
+	 *
114
+	 * @throws EE_Error
115
+	 */
116
+	public static function set_hooks_for_changes()
117
+	{
118
+		self::_set_hooks_for_changes();
119
+	}
120
+
121
+
122
+
123
+	/**
124
+	 * Loads all the hooks which make requests to old versions of the API
125
+	 * appear the same as they always did
126
+	 *
127
+	 * @throws EE_Error
128
+	 */
129
+	protected static function _set_hooks_for_changes()
130
+	{
131
+		$folder_contents = EEH_File::get_contents_of_folders(array(EE_LIBRARIES . 'rest_api' . DS . 'changes'), false);
132
+		foreach ($folder_contents as $classname_in_namespace => $filepath) {
133
+			//ignore the base parent class
134
+			//and legacy named classes
135
+			if ($classname_in_namespace === 'ChangesInBase'
136
+				|| strpos($classname_in_namespace, 'Changes_In_') === 0
137
+			) {
138
+				continue;
139
+			}
140
+			$full_classname = 'EventEspresso\core\libraries\rest_api\changes\\' . $classname_in_namespace;
141
+			if (class_exists($full_classname)) {
142
+				$instance_of_class = new $full_classname;
143
+				if ($instance_of_class instanceof ChangesInBase) {
144
+					$instance_of_class->setHooks();
145
+				}
146
+			}
147
+		}
148
+	}
149
+
150
+
151
+
152
+	/**
153
+	 * Filters the WP routes to add our EE-related ones. This takes a bit of time
154
+	 * so we actually prefer to only do it when an EE plugin is activated or upgraded
155
+	 *
156
+	 * @throws \EE_Error
157
+	 */
158
+	public static function register_routes()
159
+	{
160
+		foreach (EED_Core_Rest_Api::get_ee_route_data() as $namespace => $relative_routes) {
161
+			foreach ($relative_routes as $relative_route => $data_for_multiple_endpoints) {
162
+				/**
163
+				 * @var array $data_for_multiple_endpoints numerically indexed array
164
+				 *                                         but can also contain route options like {
165
+				 * @type array    $schema                      {
166
+				 * @type callable $schema_callback
167
+				 * @type array    $callback_args               arguments that will be passed to the callback, after the
168
+				 * WP_REST_Request of course
169
+				 * }
170
+				 * }
171
+				 */
172
+				//when registering routes, register all the endpoints' data at the same time
173
+				$multiple_endpoint_args = array();
174
+				foreach ($data_for_multiple_endpoints as $endpoint_key => $data_for_single_endpoint) {
175
+					/**
176
+					 * @var array     $data_for_single_endpoint {
177
+					 * @type callable $callback
178
+					 * @type string methods
179
+					 * @type array args
180
+					 * @type array _links
181
+					 * @type array    $callback_args            arguments that will be passed to the callback, after the
182
+					 * WP_REST_Request of course
183
+					 * }
184
+					 */
185
+					//skip route options
186
+					if (! is_numeric($endpoint_key)) {
187
+						continue;
188
+					}
189
+					if (! isset($data_for_single_endpoint['callback'], $data_for_single_endpoint['methods'])) {
190
+						throw new EE_Error(
191
+							esc_html__(
192
+								// @codingStandardsIgnoreStart
193
+								'Endpoint configuration data needs to have entries "callback" (callable) and "methods" (comma-separated list of accepts HTTP methods).',
194
+								// @codingStandardsIgnoreEnd
195
+								'event_espresso')
196
+						);
197
+					}
198
+					$callback = $data_for_single_endpoint['callback'];
199
+					$single_endpoint_args = array(
200
+						'methods' => $data_for_single_endpoint['methods'],
201
+						'args'    => isset($data_for_single_endpoint['args']) ? $data_for_single_endpoint['args']
202
+							: array(),
203
+					);
204
+					if (isset($data_for_single_endpoint['_links'])) {
205
+						$single_endpoint_args['_links'] = $data_for_single_endpoint['_links'];
206
+					}
207
+					if (isset($data_for_single_endpoint['callback_args'])) {
208
+						$callback_args = $data_for_single_endpoint['callback_args'];
209
+						$single_endpoint_args['callback'] = function (\WP_REST_Request $request) use (
210
+							$callback,
211
+							$callback_args
212
+						) {
213
+							array_unshift($callback_args, $request);
214
+							return call_user_func_array(
215
+								$callback,
216
+								$callback_args
217
+							);
218
+						};
219
+					} else {
220
+						$single_endpoint_args['callback'] = $data_for_single_endpoint['callback'];
221
+					}
222
+					$multiple_endpoint_args[] = $single_endpoint_args;
223
+				}
224
+				if (isset($data_for_multiple_endpoints['schema'])) {
225
+					$schema_route_data = $data_for_multiple_endpoints['schema'];
226
+					$schema_callback = $schema_route_data['schema_callback'];
227
+					$callback_args = $schema_route_data['callback_args'];
228
+					$multiple_endpoint_args['schema'] = function () use ($schema_callback, $callback_args) {
229
+						return call_user_func_array(
230
+							$schema_callback,
231
+							$callback_args
232
+						);
233
+					};
234
+				}
235
+				register_rest_route(
236
+					$namespace,
237
+					$relative_route,
238
+					$multiple_endpoint_args
239
+				);
240
+			}
241
+		}
242
+	}
243
+
244
+
245
+
246
+	/**
247
+	 * Checks if there was a version change or something that merits invalidating the cached
248
+	 * route data. If so, invalidates the cached route data so that it gets refreshed
249
+	 * next time the WP API is used
250
+	 */
251
+	public static function invalidate_cached_route_data_on_version_change()
252
+	{
253
+		if (EE_System::instance()->detect_req_type() !== EE_System::req_type_normal) {
254
+			EED_Core_Rest_Api::invalidate_cached_route_data();
255
+		}
256
+		foreach (EE_Registry::instance()->addons as $addon) {
257
+			if ($addon instanceof EE_Addon && $addon->detect_req_type() !== EE_System::req_type_normal) {
258
+				EED_Core_Rest_Api::invalidate_cached_route_data();
259
+			}
260
+		}
261
+	}
262
+
263
+
264
+
265
+	/**
266
+	 * Removes the cached route data so it will get refreshed next time the WP API is used
267
+	 */
268
+	public static function invalidate_cached_route_data()
269
+	{
270
+		//delete the saved EE REST API routes
271
+		foreach (EED_Core_Rest_Api::versions_served() as $version => $hidden) {
272
+			delete_option(EED_Core_Rest_Api::saved_routes_option_names . $version);
273
+		}
274
+	}
275
+
276
+
277
+
278
+	/**
279
+	 * Gets the EE route data
280
+	 *
281
+	 * @return array top-level key is the namespace, next-level key is the route and its value is array{
282
+	 * @throws \EE_Error
283
+	 * @type string|array $callback
284
+	 * @type string       $methods
285
+	 * @type boolean      $hidden_endpoint
286
+	 * }
287
+	 */
288
+	public static function get_ee_route_data()
289
+	{
290
+		$ee_routes = array();
291
+		foreach (self::versions_served() as $version => $hidden_endpoints) {
292
+			$ee_routes[self::ee_api_namespace . $version] = self::_get_ee_route_data_for_version(
293
+				$version,
294
+				$hidden_endpoints
295
+			);
296
+		}
297
+		return $ee_routes;
298
+	}
299
+
300
+
301
+
302
+	/**
303
+	 * Gets the EE route data from the wp options if it exists already,
304
+	 * otherwise re-generates it and saves it to the option
305
+	 *
306
+	 * @param string  $version
307
+	 * @param boolean $hidden_endpoints
308
+	 * @return array
309
+	 * @throws \EE_Error
310
+	 */
311
+	protected static function _get_ee_route_data_for_version($version, $hidden_endpoints = false)
312
+	{
313
+		$ee_routes = get_option(self::saved_routes_option_names . $version, null);
314
+		if (! $ee_routes || (defined('EE_REST_API_DEBUG_MODE') && EE_REST_API_DEBUG_MODE)) {
315
+			$ee_routes = self::_save_ee_route_data_for_version($version, $hidden_endpoints);
316
+		}
317
+		return $ee_routes;
318
+	}
319
+
320
+
321
+
322
+	/**
323
+	 * Saves the EE REST API route data to a wp option and returns it
324
+	 *
325
+	 * @param string  $version
326
+	 * @param boolean $hidden_endpoints
327
+	 * @return mixed|null
328
+	 * @throws \EE_Error
329
+	 */
330
+	protected static function _save_ee_route_data_for_version($version, $hidden_endpoints = false)
331
+	{
332
+		$instance = self::instance();
333
+		$routes = apply_filters(
334
+			'EED_Core_Rest_Api__save_ee_route_data_for_version__routes',
335
+			array_replace_recursive(
336
+				$instance->_get_config_route_data_for_version($version, $hidden_endpoints),
337
+				$instance->_get_meta_route_data_for_version($version, $hidden_endpoints),
338
+				$instance->_get_model_route_data_for_version($version, $hidden_endpoints),
339
+				$instance->_get_rpc_route_data_for_version($version, $hidden_endpoints)
340
+			)
341
+		);
342
+		$option_name = self::saved_routes_option_names . $version;
343
+		if (get_option($option_name)) {
344
+			update_option($option_name, $routes, true);
345
+		} else {
346
+			add_option($option_name, $routes, null, 'no');
347
+		}
348
+		return $routes;
349
+	}
350
+
351
+
352
+
353
+	/**
354
+	 * Calculates all the EE routes and saves it to a WordPress option so we don't
355
+	 * need to calculate it on every request
356
+	 *
357
+	 * @deprecated since version 4.9.1
358
+	 * @return void
359
+	 */
360
+	public static function save_ee_routes()
361
+	{
362
+		if (EE_Maintenance_Mode::instance()->models_can_query()) {
363
+			$instance = self::instance();
364
+			$routes = apply_filters(
365
+				'EED_Core_Rest_Api__save_ee_routes__routes',
366
+				array_replace_recursive(
367
+					$instance->_register_config_routes(),
368
+					$instance->_register_meta_routes(),
369
+					$instance->_register_model_routes(),
370
+					$instance->_register_rpc_routes()
371
+				)
372
+			);
373
+			update_option(self::saved_routes_option_names, $routes, true);
374
+		}
375
+	}
376
+
377
+
378
+
379
+	/**
380
+	 * Gets all the route information relating to EE models
381
+	 *
382
+	 * @return array @see get_ee_route_data
383
+	 * @deprecated since version 4.9.1
384
+	 */
385
+	protected function _register_model_routes()
386
+	{
387
+		$model_routes = array();
388
+		foreach (self::versions_served() as $version => $hidden_endpoint) {
389
+			$model_routes[EED_Core_Rest_Api::ee_api_namespace
390
+						  . $version] = $this->_get_config_route_data_for_version($version, $hidden_endpoint);
391
+		}
392
+		return $model_routes;
393
+	}
394
+
395
+
396
+
397
+	/**
398
+	 * Decides whether or not to add write endpoints for this model.
399
+	 *
400
+	 * Currently, this defaults to exclude all global tables and models
401
+	 * which would allow inserting WP core data (we don't want to duplicate
402
+	 * what WP API does, as it's unnecessary, extra work, and potentially extra bugs)
403
+	 * @param EEM_Base $model
404
+	 * @return bool
405
+	 */
406
+	public static function should_have_write_endpoints(EEM_Base $model)
407
+	{
408
+		if ($model->is_wp_core_model()){
409
+			return false;
410
+		}
411
+		foreach($model->get_tables() as $table){
412
+			if( $table->is_global()){
413
+				return false;
414
+			}
415
+		}
416
+		return true;
417
+	}
418
+
419
+
420
+
421
+	/**
422
+	 * Gets the names of all models which should have plural routes (eg `ee/v4.8.36/events`)
423
+	 * in this versioned namespace of EE4
424
+	 * @param $version
425
+	 * @return array keys are model names (eg 'Event') and values ar either classnames (eg 'EEM_Event')
426
+	 */
427
+	public static function model_names_with_plural_routes($version){
428
+		$model_version_info = new ModelVersionInfo($version);
429
+		$models_to_register = $model_version_info->modelsForRequestedVersion();
430
+		//let's not bother having endpoints for extra metas
431
+		unset(
432
+			$models_to_register['Extra_Meta'],
433
+			$models_to_register['Extra_Join'],
434
+			$models_to_register['Post_Meta']
435
+		);
436
+		return apply_filters(
437
+			'FHEE__EED_Core_REST_API___register_model_routes',
438
+			$models_to_register
439
+		);
440
+	}
441
+
442
+
443
+
444
+	/**
445
+	 * Gets the route data for EE models in the specified version
446
+	 *
447
+	 * @param string  $version
448
+	 * @param boolean $hidden_endpoint
449
+	 * @return array
450
+	 * @throws EE_Error
451
+	 */
452
+	protected function _get_model_route_data_for_version($version, $hidden_endpoint = false)
453
+	{
454
+		$model_routes = array();
455
+		$model_version_info = new ModelVersionInfo($version);
456
+		foreach (EED_Core_Rest_Api::model_names_with_plural_routes($version) as $model_name => $model_classname) {
457
+			$model = \EE_Registry::instance()->load_model($model_name);
458
+			//if this isn't a valid model then let's skip iterate to the next item in the loop.
459
+			if (! $model instanceof EEM_Base) {
460
+				continue;
461
+			}
462
+			//yes we could just register one route for ALL models, but then they wouldn't show up in the index
463
+			$plural_model_route = EED_Core_Rest_Api::get_collection_route($model);
464
+			$singular_model_route = EED_Core_Rest_Api::get_entity_route($model, '(?P<id>[^\/]+)');
465
+			$model_routes[$plural_model_route] = array(
466
+				array(
467
+					'callback'        => array(
468
+						'EventEspresso\core\libraries\rest_api\controllers\model\Read',
469
+						'handleRequestGetAll',
470
+					),
471
+					'callback_args'   => array($version, $model_name),
472
+					'methods'         => WP_REST_Server::READABLE,
473
+					'hidden_endpoint' => $hidden_endpoint,
474
+					'args'            => $this->_get_read_query_params($model, $version),
475
+					'_links'          => array(
476
+						'self' => rest_url(EED_Core_Rest_Api::ee_api_namespace . $version . $singular_model_route),
477
+					),
478
+				),
479
+				'schema' => array(
480
+					'schema_callback' => array(
481
+						'EventEspresso\core\libraries\rest_api\controllers\model\Read',
482
+						'handleSchemaRequest',
483
+					),
484
+					'callback_args'   => array($version, $model_name),
485
+				),
486
+			);
487
+			$model_routes[$singular_model_route] = array(
488
+				array(
489
+					'callback'        => array(
490
+						'EventEspresso\core\libraries\rest_api\controllers\model\Read',
491
+						'handleRequestGetOne',
492
+					),
493
+					'callback_args'   => array($version, $model_name),
494
+					'methods'         => WP_REST_Server::READABLE,
495
+					'hidden_endpoint' => $hidden_endpoint,
496
+					'args'            => $this->_get_response_selection_query_params($model, $version),
497
+				),
498
+			);
499
+			if( apply_filters(
500
+				'FHEE__EED_Core_Rest_Api___get_model_route_data_for_version__add_write_endpoints',
501
+				EED_Core_Rest_Api::should_have_write_endpoints($model),
502
+				$model
503
+			)){
504
+				$model_routes[$plural_model_route][] = array(
505
+					'callback'        => array(
506
+						'EventEspresso\core\libraries\rest_api\controllers\model\Write',
507
+						'handleRequestInsert',
508
+					),
509
+					'callback_args'   => array($version, $model_name),
510
+					'methods'         => WP_REST_Server::CREATABLE,
511
+					'hidden_endpoint' => $hidden_endpoint,
512
+					'args'            => $this->_get_write_params($model_name, $model_version_info, true),
513
+				);
514
+				$model_routes[$singular_model_route] = array_merge(
515
+					$model_routes[$singular_model_route],
516
+					array(
517
+						array(
518
+							'callback'        => array(
519
+								'EventEspresso\core\libraries\rest_api\controllers\model\Write',
520
+								'handleRequestUpdate',
521
+							),
522
+							'callback_args'   => array($version, $model_name),
523
+							'methods'         => WP_REST_Server::EDITABLE,
524
+							'hidden_endpoint' => $hidden_endpoint,
525
+							'args'            => $this->_get_write_params($model_name, $model_version_info),
526
+						),
527
+						array(
528
+							'callback'        => array(
529
+								'EventEspresso\core\libraries\rest_api\controllers\model\Write',
530
+								'handleRequestDelete',
531
+							),
532
+							'callback_args'   => array($version, $model_name),
533
+							'methods'         => WP_REST_Server::DELETABLE,
534
+							'hidden_endpoint' => $hidden_endpoint,
535
+							'args'            => $this->_get_delete_query_params($model, $version),
536
+						)
537
+					)
538
+				);
539
+			}
540
+			foreach ($model->relation_settings() as $relation_name => $relation_obj) {
541
+
542
+				$related_route = EED_Core_Rest_Api::get_relation_route_via(
543
+					$model,
544
+					'(?P<id>[^\/]+)',
545
+					$relation_obj
546
+				);
547
+				$endpoints = array(
548
+					array(
549
+						'callback'        => array(
550
+							'EventEspresso\core\libraries\rest_api\controllers\model\Read',
551
+							'handleRequestGetRelated',
552
+						),
553
+						'callback_args'   => array($version, $model_name, $relation_name),
554
+						'methods'         => WP_REST_Server::READABLE,
555
+						'hidden_endpoint' => $hidden_endpoint,
556
+						'args'            => $this->_get_read_query_params($relation_obj->get_other_model(), $version),
557
+					),
558
+				);
559
+				$model_routes[$related_route] = $endpoints;
560
+			}
561
+		}
562
+		return $model_routes;
563
+	}
564
+
565
+
566
+
567
+	/**
568
+	 * Gets the relative URI to a model's REST API plural route, after the EE4 versioned namespace,
569
+	 * excluding the preceding slash.
570
+	 * Eg you pass get_plural_route_to('Event') = 'events'
571
+	 *
572
+	 * @param EEM_Base $model
573
+	 * @return string
574
+	 */
575
+	public static function get_collection_route(EEM_Base $model)
576
+	{
577
+		return EEH_Inflector::pluralize_and_lower($model->get_this_model_name());
578
+	}
579
+
580
+
581
+
582
+	/**
583
+	 * Gets the relative URI to a model's REST API singular route, after the EE4 versioned namespace,
584
+	 * excluding the preceding slash.
585
+	 * Eg you pass get_plural_route_to('Event', 12) = 'events/12'
586
+	 *
587
+	 * @param EEM_Base $model eg Event or Venue
588
+	 * @param string $id
589
+	 * @return string
590
+	 */
591
+	public static function get_entity_route($model, $id)
592
+	{
593
+		return EED_Core_Rest_Api::get_collection_route($model). '/' . $id;
594
+	}
595
+
596
+
597
+	/**
598
+	 * Gets the relative URI to a model's REST API singular route, after the EE4 versioned namespace,
599
+	 * excluding the preceding slash.
600
+	 * Eg you pass get_plural_route_to('Event', 12) = 'events/12'
601
+	 *
602
+	 * @param EEM_Base                 $model eg Event or Venue
603
+	 * @param string                 $id
604
+	 * @param EE_Model_Relation_Base $relation_obj
605
+	 * @return string
606
+	 */
607
+	public static function get_relation_route_via(EEM_Base $model, $id, EE_Model_Relation_Base $relation_obj)
608
+	{
609
+		$related_model_name_endpoint_part = ModelRead::getRelatedEntityName(
610
+			$relation_obj->get_other_model()->get_this_model_name(),
611
+			$relation_obj
612
+		);
613
+		return EED_Core_Rest_Api::get_entity_route($model, $id) . '/' . $related_model_name_endpoint_part;
614
+	}
615
+
616
+
617
+
618
+	/**
619
+	 * Adds onto the $relative_route the EE4 REST API versioned namespace.
620
+	 * Eg if given '4.8.36' and 'events', will return 'ee/v4.8.36/events'
621
+	 * @param string $relative_route
622
+	 * @param string $version
623
+	 * @return string
624
+	 */
625
+	public static function get_versioned_route_to($relative_route, $version = '4.8.36'){
626
+		return '/' . EED_Core_Rest_Api::ee_api_namespace . $version . '/' . $relative_route;
627
+	}
628
+
629
+
630
+
631
+	/**
632
+	 * Adds all the RPC-style routes (remote procedure call-like routes, ie
633
+	 * routes that don't conform to the traditional REST CRUD-style).
634
+	 *
635
+	 * @deprecated since 4.9.1
636
+	 */
637
+	protected function _register_rpc_routes()
638
+	{
639
+		$routes = array();
640
+		foreach (self::versions_served() as $version => $hidden_endpoint) {
641
+			$routes[self::ee_api_namespace . $version] = $this->_get_rpc_route_data_for_version(
642
+				$version,
643
+				$hidden_endpoint
644
+			);
645
+		}
646
+		return $routes;
647
+	}
648
+
649
+
650
+
651
+	/**
652
+	 * @param string  $version
653
+	 * @param boolean $hidden_endpoint
654
+	 * @return array
655
+	 */
656
+	protected function _get_rpc_route_data_for_version($version, $hidden_endpoint = false)
657
+	{
658
+		$this_versions_routes = array();
659
+		//checkin endpoint
660
+		$this_versions_routes['registrations/(?P<REG_ID>\d+)/toggle_checkin_for_datetime/(?P<DTT_ID>\d+)'] = array(
661
+			array(
662
+				'callback'        => array(
663
+					'EventEspresso\core\libraries\rest_api\controllers\rpc\Checkin',
664
+					'handleRequestToggleCheckin',
665
+				),
666
+				'methods'         => WP_REST_Server::CREATABLE,
667
+				'hidden_endpoint' => $hidden_endpoint,
668
+				'args'            => array(
669
+					'force' => array(
670
+						'required'    => false,
671
+						'default'     => false,
672
+						'description' => __(
673
+							// @codingStandardsIgnoreStart
674
+							'Whether to force toggle checkin, or to verify the registration status and allowed ticket uses',
675
+							// @codingStandardsIgnoreEnd
676
+							'event_espresso'
677
+						),
678
+					),
679
+				),
680
+				'callback_args'   => array($version),
681
+			),
682
+		);
683
+		return apply_filters(
684
+			'FHEE__EED_Core_Rest_Api___register_rpc_routes__this_versions_routes',
685
+			$this_versions_routes,
686
+			$version,
687
+			$hidden_endpoint
688
+		);
689
+	}
690
+
691
+
692
+
693
+	/**
694
+	 * Gets the query params that can be used when request one or many
695
+	 *
696
+	 * @param EEM_Base $model
697
+	 * @param string   $version
698
+	 * @return array
699
+	 */
700
+	protected function _get_response_selection_query_params(\EEM_Base $model, $version)
701
+	{
702
+		return apply_filters(
703
+			'FHEE__EED_Core_Rest_Api___get_response_selection_query_params',
704
+			array(
705
+				'include'   => array(
706
+					'required' => false,
707
+					'default'  => '*',
708
+					'type'     => 'string',
709
+				),
710
+				'calculate' => array(
711
+					'required'          => false,
712
+					'default'           => '',
713
+					'enum'              => self::$_field_calculator->retrieveCalculatedFieldsForModel($model),
714
+					'type'              => 'string',
715
+					//because we accept a CSV'd list of the enumerated strings, WP core validation and sanitization
716
+					//freaks out. We'll just validate this argument while handling the request
717
+					'validate_callback' => null,
718
+					'sanitize_callback' => null,
719
+				),
720
+			),
721
+			$model,
722
+			$version
723
+		);
724
+	}
725
+
726
+
727
+
728
+	/**
729
+	 * Gets the parameters acceptable for delete requests
730
+	 *
731
+	 * @param \EEM_Base $model
732
+	 * @param string    $version
733
+	 * @return array
734
+	 */
735
+	protected function _get_delete_query_params(\EEM_Base $model, $version)
736
+	{
737
+		$params_for_delete = array(
738
+			'allow_blocking' => array(
739
+				'required' => false,
740
+				'default'  => true,
741
+				'type'     => 'boolean',
742
+			),
743
+		);
744
+		$params_for_delete['force'] = array(
745
+			'required' => false,
746
+			'default'  => false,
747
+			'type'     => 'boolean',
748
+		);
749
+		return apply_filters(
750
+			'FHEE__EED_Core_Rest_Api___get_delete_query_params',
751
+			$params_for_delete,
752
+			$model,
753
+			$version
754
+		);
755
+	}
756
+
757
+
758
+
759
+	/**
760
+	 * Gets info about reading query params that are acceptable
761
+	 *
762
+	 * @param \EEM_Base $model eg 'Event' or 'Venue'
763
+	 * @param  string   $version
764
+	 * @return array    describing the args acceptable when querying this model
765
+	 * @throws EE_Error
766
+	 */
767
+	protected function _get_read_query_params(\EEM_Base $model, $version)
768
+	{
769
+		$default_orderby = array();
770
+		foreach ($model->get_combined_primary_key_fields() as $key_field) {
771
+			$default_orderby[$key_field->get_name()] = 'ASC';
772
+		}
773
+		return array_merge(
774
+			$this->_get_response_selection_query_params($model, $version),
775
+			array(
776
+				'where'    => array(
777
+					'required' => false,
778
+					'default'  => array(),
779
+					'type'     => 'object',
780
+					//because we accept an almost infinite list of possible where conditions, WP
781
+					// core validation and sanitization freaks out. We'll just validate this argument
782
+					// while handling the request
783
+					'validate_callback' => null,
784
+					'sanitize_callback' => null,
785
+				),
786
+				'limit'    => array(
787
+					'required' => false,
788
+					'default'  => EED_Core_Rest_Api::get_default_query_limit(),
789
+					'type'     => array(
790
+						'array',
791
+						'string',
792
+						'integer',
793
+					),
794
+					//because we accept a variety of types, WP core validation and sanitization
795
+					//freaks out. We'll just validate this argument while handling the request
796
+					'validate_callback' => null,
797
+					'sanitize_callback' => null,
798
+				),
799
+				'order_by' => array(
800
+					'required' => false,
801
+					'default'  => $default_orderby,
802
+					'type'     => array(
803
+						'object',
804
+						'string',
805
+					),//because we accept a variety of types, WP core validation and sanitization
806
+					//freaks out. We'll just validate this argument while handling the request
807
+					'validate_callback' => null,
808
+					'sanitize_callback' => null,
809
+				),
810
+				'group_by' => array(
811
+					'required' => false,
812
+					'default'  => null,
813
+					'type'     => array(
814
+						'object',
815
+						'string',
816
+					),
817
+					//because we accept  an almost infinite list of possible groupings,
818
+					// WP core validation and sanitization
819
+					//freaks out. We'll just validate this argument while handling the request
820
+					'validate_callback' => null,
821
+					'sanitize_callback' => null,
822
+				),
823
+				'having'   => array(
824
+					'required' => false,
825
+					'default'  => null,
826
+					'type'     => 'object',
827
+					//because we accept an almost infinite list of possible where conditions, WP
828
+					// core validation and sanitization freaks out. We'll just validate this argument
829
+					// while handling the request
830
+					'validate_callback' => null,
831
+					'sanitize_callback' => null,
832
+				),
833
+				'caps'     => array(
834
+					'required' => false,
835
+					'default'  => EEM_Base::caps_read,
836
+					'type'     => 'string',
837
+					'enum'     => array(
838
+						EEM_Base::caps_read,
839
+						EEM_Base::caps_read_admin,
840
+						EEM_Base::caps_edit,
841
+						EEM_Base::caps_delete
842
+					)
843
+				),
844
+			)
845
+		);
846
+	}
847
+
848
+
849
+
850
+	/**
851
+	 * Gets parameter information for a model regarding writing data
852
+	 *
853
+	 * @param string           $model_name
854
+	 * @param ModelVersionInfo $model_version_info
855
+	 * @param boolean          $create                                       whether this is for request to create (in which case we need
856
+	 *                                                                       all required params) or just to update (in which case we don't need those on every request)
857
+	 * @return array
858
+	 */
859
+	protected function _get_write_params(
860
+		$model_name,
861
+		ModelVersionInfo $model_version_info,
862
+		$create = false
863
+	) {
864
+		$model = EE_Registry::instance()->load_model($model_name);
865
+		$fields = $model_version_info->fieldsOnModelInThisVersion($model);
866
+		$args_info = array();
867
+		foreach ($fields as $field_name => $field_obj) {
868
+			if ($field_obj->is_auto_increment()) {
869
+				//totally ignore auto increment IDs
870
+				continue;
871
+			}
872
+			$arg_info = $field_obj->getSchema();
873
+			$required = $create && ! $field_obj->is_nullable() && $field_obj->get_default_value() === null;
874
+			$arg_info['required'] = $required;
875
+			//remove the read-only flag. If it were read-only we wouldn't list it as an argument while writing, right?
876
+			unset($arg_info['readonly']);
877
+			$schema_properties = $field_obj->getSchemaProperties();
878
+			if (
879
+				isset($schema_properties['raw'])
880
+				&& $field_obj->getSchemaType() === 'object'
881
+			) {
882
+				//if there's a "raw" form of this argument, use those properties instead
883
+				$arg_info = array_replace(
884
+					$arg_info,
885
+					$schema_properties['raw']
886
+				);
887
+			}
888
+			$arg_info['default'] = ModelDataTranslator::prepareFieldValueForJson(
889
+				$field_obj,
890
+				$field_obj->get_default_value(),
891
+				$model_version_info->requestedVersion()
892
+			);
893
+			//we do our own validation and sanitization within the controller
894
+			$arg_info['sanitize_callback'] =
895
+				array(
896
+					'EED_Core_Rest_Api',
897
+					'default_sanitize_callback',
898
+				);
899
+			$args_info[$field_name] = $arg_info;
900
+			if ($field_obj instanceof EE_Datetime_Field) {
901
+				$gmt_arg_info = $arg_info;
902
+				$gmt_arg_info['description'] = sprintf(
903
+					esc_html__(
904
+						'%1$s - the value for this field in UTC. Ignored if %2$s is provided.',
905
+						'event_espresso'
906
+					),
907
+					$field_obj->get_nicename(),
908
+					$field_name
909
+				);
910
+				$args_info[$field_name . '_gmt'] = $gmt_arg_info;
911
+			}
912
+		}
913
+		return $args_info;
914
+	}
915
+
916
+
917
+
918
+	/**
919
+	 * Replacement for WP API's 'rest_parse_request_arg'.
920
+	 * If the value is blank but not required, don't bother validating it.
921
+	 * Also, it uses our email validation instead of WP API's default.
922
+	 *
923
+	 * @param                 $value
924
+	 * @param WP_REST_Request $request
925
+	 * @param                 $param
926
+	 * @return bool|true|WP_Error
927
+	 * @throws InvalidArgumentException
928
+	 * @throws InvalidInterfaceException
929
+	 * @throws InvalidDataTypeException
930
+	 */
931
+	public static function default_sanitize_callback( $value, WP_REST_Request $request, $param)
932
+	{
933
+		$attributes = $request->get_attributes();
934
+		if (! isset($attributes['args'][$param])
935
+			|| ! is_array($attributes['args'][$param])) {
936
+			$validation_result = true;
937
+		} else {
938
+			$args = $attributes['args'][$param];
939
+			if ((
940
+					$value === ''
941
+					|| $value === null
942
+				)
943
+				&& (! isset($args['required'])
944
+					|| $args['required'] === false
945
+				)
946
+			) {
947
+				//not required and not provided? that's cool
948
+				$validation_result = true;
949
+			} elseif (isset($args['format'])
950
+				&& $args['format'] === 'email'
951
+			) {
952
+				$validation_result = true;
953
+				if (! self::_validate_email($value)) {
954
+					$validation_result = new WP_Error(
955
+						'rest_invalid_param',
956
+						esc_html__(
957
+							'The email address is not valid or does not exist.',
958
+							'event_espresso'
959
+						)
960
+					);
961
+				}
962
+			} else {
963
+				$validation_result = rest_validate_value_from_schema($value, $args, $param);
964
+			}
965
+		}
966
+		if (is_wp_error($validation_result)) {
967
+			return $validation_result;
968
+		}
969
+		return rest_sanitize_request_arg($value, $request, $param);
970
+	}
971
+
972
+
973
+
974
+	/**
975
+	 * Returns whether or not this email address is valid. Copied from EE_Email_Validation_Strategy::_validate_email()
976
+	 *
977
+	 * @param $email
978
+	 * @return bool
979
+	 * @throws InvalidArgumentException
980
+	 * @throws InvalidInterfaceException
981
+	 * @throws InvalidDataTypeException
982
+	 */
983
+	protected static function _validate_email($email){
984
+		try {
985
+			EmailAddressFactory::create($email);
986
+			return true;
987
+		} catch (EmailValidationException $e) {
988
+			return false;
989
+		}
990
+	}
991
+
992
+
993
+
994
+	/**
995
+	 * Gets routes for the config
996
+	 *
997
+	 * @return array @see _register_model_routes
998
+	 * @deprecated since version 4.9.1
999
+	 */
1000
+	protected function _register_config_routes()
1001
+	{
1002
+		$config_routes = array();
1003
+		foreach (self::versions_served() as $version => $hidden_endpoint) {
1004
+			$config_routes[self::ee_api_namespace . $version] = $this->_get_config_route_data_for_version(
1005
+				$version,
1006
+				$hidden_endpoint
1007
+			);
1008
+		}
1009
+		return $config_routes;
1010
+	}
1011
+
1012
+
1013
+
1014
+	/**
1015
+	 * Gets routes for the config for the specified version
1016
+	 *
1017
+	 * @param string  $version
1018
+	 * @param boolean $hidden_endpoint
1019
+	 * @return array
1020
+	 */
1021
+	protected function _get_config_route_data_for_version($version, $hidden_endpoint)
1022
+	{
1023
+		return array(
1024
+			'config'    => array(
1025
+				array(
1026
+					'callback'        => array(
1027
+						'EventEspresso\core\libraries\rest_api\controllers\config\Read',
1028
+						'handleRequest',
1029
+					),
1030
+					'methods'         => WP_REST_Server::READABLE,
1031
+					'hidden_endpoint' => $hidden_endpoint,
1032
+					'callback_args'   => array($version),
1033
+				),
1034
+			),
1035
+			'site_info' => array(
1036
+				array(
1037
+					'callback'        => array(
1038
+						'EventEspresso\core\libraries\rest_api\controllers\config\Read',
1039
+						'handleRequestSiteInfo',
1040
+					),
1041
+					'methods'         => WP_REST_Server::READABLE,
1042
+					'hidden_endpoint' => $hidden_endpoint,
1043
+					'callback_args'   => array($version),
1044
+				),
1045
+			),
1046
+		);
1047
+	}
1048
+
1049
+
1050
+
1051
+	/**
1052
+	 * Gets the meta info routes
1053
+	 *
1054
+	 * @return array @see _register_model_routes
1055
+	 * @deprecated since version 4.9.1
1056
+	 */
1057
+	protected function _register_meta_routes()
1058
+	{
1059
+		$meta_routes = array();
1060
+		foreach (self::versions_served() as $version => $hidden_endpoint) {
1061
+			$meta_routes[self::ee_api_namespace . $version] = $this->_get_meta_route_data_for_version(
1062
+				$version,
1063
+				$hidden_endpoint
1064
+			);
1065
+		}
1066
+		return $meta_routes;
1067
+	}
1068
+
1069
+
1070
+
1071
+	/**
1072
+	 * @param string  $version
1073
+	 * @param boolean $hidden_endpoint
1074
+	 * @return array
1075
+	 */
1076
+	protected function _get_meta_route_data_for_version($version, $hidden_endpoint = false)
1077
+	{
1078
+		return array(
1079
+			'resources' => array(
1080
+				array(
1081
+					'callback'        => array(
1082
+						'EventEspresso\core\libraries\rest_api\controllers\model\Meta',
1083
+						'handleRequestModelsMeta',
1084
+					),
1085
+					'methods'         => WP_REST_Server::READABLE,
1086
+					'hidden_endpoint' => $hidden_endpoint,
1087
+					'callback_args'   => array($version),
1088
+				),
1089
+			),
1090
+		);
1091
+	}
1092
+
1093
+
1094
+
1095
+	/**
1096
+	 * Tries to hide old 4.6 endpoints from the
1097
+	 *
1098
+	 * @param array $route_data
1099
+	 * @return array
1100
+	 * @throws \EE_Error
1101
+	 */
1102
+	public static function hide_old_endpoints($route_data)
1103
+	{
1104
+		//allow API clients to override which endpoints get hidden, in case
1105
+		//they want to discover particular endpoints
1106
+		//also, we don't have access to the request so we have to just grab it from the superglobal
1107
+		$force_show_ee_namespace = ltrim(
1108
+			EEH_Array::is_set($_REQUEST, 'force_show_ee_namespace', ''),
1109
+			'/'
1110
+		);
1111
+		foreach (EED_Core_Rest_Api::get_ee_route_data() as $namespace => $relative_urls) {
1112
+			foreach ($relative_urls as $resource_name => $endpoints) {
1113
+				foreach ($endpoints as $key => $endpoint) {
1114
+					//skip schema and other route options
1115
+					if (! is_numeric($key)) {
1116
+						continue;
1117
+					}
1118
+					//by default, hide "hidden_endpoint"s, unless the request indicates
1119
+					//to $force_show_ee_namespace, in which case only show that one
1120
+					//namespace's endpoints (and hide all others)
1121
+					if (
1122
+						($force_show_ee_namespace !== '' && $force_show_ee_namespace !== $namespace)
1123
+						|| ($endpoint['hidden_endpoint'] && $force_show_ee_namespace === '')
1124
+					) {
1125
+						$full_route = '/' . ltrim($namespace, '/');
1126
+						$full_route .= '/' . ltrim($resource_name, '/');
1127
+						unset($route_data[$full_route]);
1128
+					}
1129
+				}
1130
+			}
1131
+		}
1132
+		return $route_data;
1133
+	}
1134
+
1135
+
1136
+
1137
+	/**
1138
+	 * Returns an array describing which versions of core support serving requests for.
1139
+	 * Keys are core versions' major and minor version, and values are the
1140
+	 * LOWEST requested version they can serve. Eg, 4.7 can serve requests for 4.6-like
1141
+	 * data by just removing a few models and fields from the responses. However, 4.15 might remove
1142
+	 * the answers table entirely, in which case it would be very difficult for
1143
+	 * it to serve 4.6-style responses.
1144
+	 * Versions of core that are missing from this array are unknowns.
1145
+	 * previous ver
1146
+	 *
1147
+	 * @return array
1148
+	 */
1149
+	public static function version_compatibilities()
1150
+	{
1151
+		return apply_filters(
1152
+			'FHEE__EED_Core_REST_API__version_compatibilities',
1153
+			array(
1154
+				'4.8.29' => '4.8.29',
1155
+				'4.8.33' => '4.8.29',
1156
+				'4.8.34' => '4.8.29',
1157
+				'4.8.36' => '4.8.29',
1158
+			)
1159
+		);
1160
+	}
1161
+
1162
+
1163
+
1164
+	/**
1165
+	 * Gets the latest API version served. Eg if there
1166
+	 * are two versions served of the API, 4.8.29 and 4.8.32, and
1167
+	 * we are on core version 4.8.34, it will return the string "4.8.32"
1168
+	 *
1169
+	 * @return string
1170
+	 */
1171
+	public static function latest_rest_api_version()
1172
+	{
1173
+		$versions_served = \EED_Core_Rest_Api::versions_served();
1174
+		$versions_served_keys = array_keys($versions_served);
1175
+		return end($versions_served_keys);
1176
+	}
1177
+
1178
+
1179
+
1180
+	/**
1181
+	 * Using EED_Core_Rest_Api::version_compatibilities(), determines what version of
1182
+	 * EE the API can serve requests for. Eg, if we are on 4.15 of core, and
1183
+	 * we can serve requests from 4.12 or later, this will return array( '4.12', '4.13', '4.14', '4.15' ).
1184
+	 * We also indicate whether or not this version should be put in the index or not
1185
+	 *
1186
+	 * @return array keys are API version numbers (just major and minor numbers), and values
1187
+	 * are whether or not they should be hidden
1188
+	 */
1189
+	public static function versions_served()
1190
+	{
1191
+		$versions_served = array();
1192
+		$possibly_served_versions = EED_Core_Rest_Api::version_compatibilities();
1193
+		$lowest_compatible_version = end($possibly_served_versions);
1194
+		reset($possibly_served_versions);
1195
+		$versions_served_historically = array_keys($possibly_served_versions);
1196
+		$latest_version = end($versions_served_historically);
1197
+		reset($versions_served_historically);
1198
+		//for each version of core we have ever served:
1199
+		foreach ($versions_served_historically as $key_versioned_endpoint) {
1200
+			//if it's not above the current core version, and it's compatible with the current version of core
1201
+			if ($key_versioned_endpoint === $latest_version) {
1202
+				//don't hide the latest version in the index
1203
+				$versions_served[$key_versioned_endpoint] = false;
1204
+			} elseif (
1205
+				$key_versioned_endpoint >= $lowest_compatible_version
1206
+				&& $key_versioned_endpoint < EED_Core_Rest_Api::core_version()
1207
+			) {
1208
+				//include, but hide, previous versions which are still supported
1209
+				$versions_served[$key_versioned_endpoint] = true;
1210
+			} elseif (apply_filters(
1211
+				'FHEE__EED_Core_Rest_Api__versions_served__include_incompatible_versions',
1212
+				false,
1213
+				$possibly_served_versions
1214
+			)) {
1215
+				//if a version is no longer supported, don't include it in index or list of versions served
1216
+				$versions_served[$key_versioned_endpoint] = true;
1217
+			}
1218
+		}
1219
+		return $versions_served;
1220
+	}
1221
+
1222
+
1223
+
1224
+	/**
1225
+	 * Gets the major and minor version of EE core's version string
1226
+	 *
1227
+	 * @return string
1228
+	 */
1229
+	public static function core_version()
1230
+	{
1231
+		return apply_filters(
1232
+			'FHEE__EED_Core_REST_API__core_version',
1233
+			implode(
1234
+				'.',
1235
+				array_slice(
1236
+					explode(
1237
+						'.',
1238
+						espresso_version()
1239
+					),
1240
+				0,
1241
+				3
1242
+				)
1243
+			)
1244
+		);
1245
+	}
1246
+
1247
+
1248
+
1249
+	/**
1250
+	 * Gets the default limit that should be used when querying for resources
1251
+	 *
1252
+	 * @return int
1253
+	 */
1254
+	public static function get_default_query_limit()
1255
+	{
1256
+		//we actually don't use a const because we want folks to always use
1257
+		//this method, not the const directly
1258
+		return apply_filters(
1259
+			'FHEE__EED_Core_Rest_Api__get_default_query_limit',
1260
+			50
1261
+		);
1262
+	}
1263
+
1264
+
1265
+
1266
+	/**
1267
+	 *    run - initial module setup
1268
+	 *
1269
+	 * @access    public
1270
+	 * @param  WP $WP
1271
+	 * @return    void
1272
+	 */
1273
+	public function run($WP)
1274
+	{
1275
+	}
1276 1276
 }
1277 1277
 
1278 1278
 // End of file EED_Core_Rest_Api.module.php
Please login to merge, or discard this patch.
Unused Use Statements   -1 removed lines patch added patch discarded remove patch
@@ -1,5 +1,4 @@
 block discarded – undo
1 1
 <?php
2
-use EventEspresso\core\domain\entities\notifications\PersistentAdminNotice;
3 2
 use EventEspresso\core\domain\services\factories\EmailAddressFactory;
4 3
 use EventEspresso\core\domain\services\validation\email\EmailValidationException;
5 4
 use EventEspresso\core\exceptions\InvalidDataTypeException;
Please login to merge, or discard this patch.
messages/data_class/EE_Messages_Registrations_incoming_data.class.php 2 patches
Spacing   +4 added lines, -4 removed lines patch added patch discarded remove patch
@@ -4,7 +4,7 @@  discard block
 block discarded – undo
4 4
 use EventEspresso\core\exceptions\InvalidDataTypeException;
5 5
 use EventEspresso\core\exceptions\InvalidInterfaceException;
6 6
 
7
-if (! defined('EVENT_ESPRESSO_VERSION')) {
7
+if ( ! defined('EVENT_ESPRESSO_VERSION')) {
8 8
     exit('No direct script access allowed');
9 9
 }
10 10
 
@@ -32,7 +32,7 @@  discard block
 block discarded – undo
32 32
     {
33 33
 
34 34
         //validate that the first element in the array is an EE_Registration object.
35
-        if (! reset($data) instanceof EE_Registration) {
35
+        if ( ! reset($data) instanceof EE_Registration) {
36 36
             throw new EE_Error(
37 37
                 esc_html__(
38 38
                     'The EE_Message_Registrations_incoming_data class expects an array of EE_Registration objects.',
@@ -101,7 +101,7 @@  discard block
 block discarded – undo
101 101
      */
102 102
     public static  function convert_data_for_persistent_storage($registrations)
103 103
     {
104
-        if (! self::validateRegistrationsForConversion($registrations)) {
104
+        if ( ! self::validateRegistrationsForConversion($registrations)) {
105 105
             return array();
106 106
         }
107 107
 
@@ -114,7 +114,7 @@  discard block
 block discarded – undo
114 114
         //k nope so let's pull from the registrations
115 115
         $registration_ids = array_filter(
116 116
             array_map(
117
-                function ($registration) {
117
+                function($registration) {
118 118
                     if ($registration instanceof EE_Registration) {
119 119
                         return $registration->ID();
120 120
                     }
Please login to merge, or discard this patch.
Indentation   +169 added lines, -169 removed lines patch added patch discarded remove patch
@@ -5,7 +5,7 @@  discard block
 block discarded – undo
5 5
 use EventEspresso\core\exceptions\InvalidInterfaceException;
6 6
 
7 7
 if (! defined('EVENT_ESPRESSO_VERSION')) {
8
-    exit('No direct script access allowed');
8
+	exit('No direct script access allowed');
9 9
 }
10 10
 
11 11
 /**
@@ -21,172 +21,172 @@  discard block
 block discarded – undo
21 21
 {
22 22
 
23 23
 
24
-    /**
25
-     * Constructor.
26
-     *
27
-     * @param  EE_Registration[] $data expecting an array of EE_Registration objects.
28
-     * @throws EE_Error
29
-     * @access protected
30
-     */
31
-    public function __construct($data = array())
32
-    {
33
-
34
-        //validate that the first element in the array is an EE_Registration object.
35
-        if (! reset($data) instanceof EE_Registration) {
36
-            throw new EE_Error(
37
-                esc_html__(
38
-                    'The EE_Message_Registrations_incoming_data class expects an array of EE_Registration objects.',
39
-                    'event_espresso'
40
-                )
41
-            );
42
-        }
43
-        parent::__construct($data);
44
-    }
45
-
46
-
47
-    /**
48
-     * setup the data.
49
-     * Sets up the expected data object for the messages prep using incoming registration objects.
50
-     *
51
-     * @return void
52
-     * @throws EE_Error
53
-     * @throws EntityNotFoundException
54
-     * @access protected
55
-     */
56
-    protected function _setup_data()
57
-    {
58
-        //we'll loop through each contact and setup the data needed.  Note that many properties will just be set as
59
-        // empty because this data handler is for a very specific set of data (i.e. just what's related to the
60
-        // registration).
61
-
62
-        $this->reg_objs = $this->data();
63
-        $this->txn      = $this->_maybe_get_transaction();
64
-        $this->_assemble_data();
65
-    }
66
-
67
-
68
-    /**
69
-     * If the incoming registrations all share the same transaction then this will return the transaction object shared
70
-     * among the registrations. Otherwise the transaction object is set to null because its intended to only represent
71
-     * one transaction.
72
-     *
73
-     * @return EE_Transaction|null
74
-     * @throws EE_Error
75
-     * @throws EntityNotFoundException
76
-     */
77
-    protected function _maybe_get_transaction()
78
-    {
79
-        $transactions = array();
80
-        foreach ($this->reg_objs as $registration) {
81
-            if ($registration instanceof EE_Registration) {
82
-                $transaction = $registration->transaction();
83
-                if ($transaction instanceof EE_Transaction) {
84
-                    $transactions[$transaction->ID()] = $transaction;
85
-                }
86
-            }
87
-        }
88
-        return count($transactions) === 1 ? reset($transactions) : null;
89
-    }
90
-
91
-
92
-    /**
93
-     * Returns database safe representation of the data later used to when instantiating this object.
94
-     *
95
-     * @param array $registrations The incoming data to be prepped.
96
-     * @return EE_Registration[] The data being prepared for the db
97
-     * @throws EE_Error
98
-     * @throws InvalidArgumentException
99
-     * @throws InvalidDataTypeException
100
-     * @throws InvalidInterfaceException
101
-     */
102
-    public static  function convert_data_for_persistent_storage($registrations)
103
-    {
104
-        if (! self::validateRegistrationsForConversion($registrations)) {
105
-            return array();
106
-        }
107
-
108
-        //is this an array of ints?
109
-        $first_item = reset($registrations);
110
-        if (is_int($first_item)) {
111
-            return $registrations;
112
-        }
113
-
114
-        //k nope so let's pull from the registrations
115
-        $registration_ids = array_filter(
116
-            array_map(
117
-                function ($registration) {
118
-                    if ($registration instanceof EE_Registration) {
119
-                        return $registration->ID();
120
-                    }
121
-                    return false;
122
-                },
123
-                $registrations
124
-            )
125
-        );
126
-
127
-        return $registration_ids;
128
-    }
129
-
130
-
131
-    /**
132
-     * This validates incoming registrations (considers whether they are ids or EE_Registration objects.
133
-     *
134
-     * @param array $registrations Could be EE_Registration[] or int[]
135
-     * @return bool
136
-     * @throws EE_Error
137
-     * @throws InvalidArgumentException
138
-     * @throws InvalidDataTypeException
139
-     * @throws InvalidInterfaceException
140
-     */
141
-    protected static function validateRegistrationsForConversion($registrations)
142
-    {
143
-        if (is_array($registrations)) {
144
-            $first_item = reset($registrations);
145
-            if ($first_item instanceof EE_Registration) {
146
-                return true;
147
-            }
148
-            if (is_int($first_item)) {
149
-                //k let's some basic validation here.  This isn't foolproof but better than nothing.
150
-                //the purpose of this validation is to verify that the ids sent in match valid registrations existing
151
-                //in the db.  If the count is different, then we know they aren't valid.
152
-                $count_for_ids = EEM_Registration::instance()->count(
153
-                    array(
154
-                        array(
155
-                            'REG_ID' => array('IN', $registrations)
156
-                        )
157
-                    )
158
-                );
159
-                return $count_for_ids === count($registrations);
160
-            }
161
-        }
162
-        return false;
163
-    }
164
-
165
-
166
-    /**
167
-     * Data that has been stored in persistent storage that was prepped by _convert_data_for_persistent_storage
168
-     * can be sent into this method and converted back into the format used for instantiating with this data handler.
169
-     *
170
-     * @param array $data
171
-     * @return EE_Registration[]
172
-     * @throws EE_Error
173
-     * @throws InvalidArgumentException
174
-     * @throws InvalidDataTypeException
175
-     * @throws InvalidInterfaceException
176
-     */
177
-    public static function convert_data_from_persistent_storage($data)
178
-    {
179
-        //since this was added later, we need to account of possible back compat issues where data already queued for
180
-        // generation is in the old format, which is an array of EE_Registration objects.  So if that's the case, then
181
-        // let's just return them
182
-        //@see https://events.codebasehq.com/projects/event-espresso/tickets/10127
183
-        if (is_array($data) && reset($data) instanceof EE_Registration) {
184
-            return $data;
185
-        }
186
-
187
-        $registrations = is_array($data)
188
-            ? EEM_Registration::instance()->get_all(array(array('REG_ID' => array('IN', $data))))
189
-            : array();
190
-        return $registrations;
191
-    }
24
+	/**
25
+	 * Constructor.
26
+	 *
27
+	 * @param  EE_Registration[] $data expecting an array of EE_Registration objects.
28
+	 * @throws EE_Error
29
+	 * @access protected
30
+	 */
31
+	public function __construct($data = array())
32
+	{
33
+
34
+		//validate that the first element in the array is an EE_Registration object.
35
+		if (! reset($data) instanceof EE_Registration) {
36
+			throw new EE_Error(
37
+				esc_html__(
38
+					'The EE_Message_Registrations_incoming_data class expects an array of EE_Registration objects.',
39
+					'event_espresso'
40
+				)
41
+			);
42
+		}
43
+		parent::__construct($data);
44
+	}
45
+
46
+
47
+	/**
48
+	 * setup the data.
49
+	 * Sets up the expected data object for the messages prep using incoming registration objects.
50
+	 *
51
+	 * @return void
52
+	 * @throws EE_Error
53
+	 * @throws EntityNotFoundException
54
+	 * @access protected
55
+	 */
56
+	protected function _setup_data()
57
+	{
58
+		//we'll loop through each contact and setup the data needed.  Note that many properties will just be set as
59
+		// empty because this data handler is for a very specific set of data (i.e. just what's related to the
60
+		// registration).
61
+
62
+		$this->reg_objs = $this->data();
63
+		$this->txn      = $this->_maybe_get_transaction();
64
+		$this->_assemble_data();
65
+	}
66
+
67
+
68
+	/**
69
+	 * If the incoming registrations all share the same transaction then this will return the transaction object shared
70
+	 * among the registrations. Otherwise the transaction object is set to null because its intended to only represent
71
+	 * one transaction.
72
+	 *
73
+	 * @return EE_Transaction|null
74
+	 * @throws EE_Error
75
+	 * @throws EntityNotFoundException
76
+	 */
77
+	protected function _maybe_get_transaction()
78
+	{
79
+		$transactions = array();
80
+		foreach ($this->reg_objs as $registration) {
81
+			if ($registration instanceof EE_Registration) {
82
+				$transaction = $registration->transaction();
83
+				if ($transaction instanceof EE_Transaction) {
84
+					$transactions[$transaction->ID()] = $transaction;
85
+				}
86
+			}
87
+		}
88
+		return count($transactions) === 1 ? reset($transactions) : null;
89
+	}
90
+
91
+
92
+	/**
93
+	 * Returns database safe representation of the data later used to when instantiating this object.
94
+	 *
95
+	 * @param array $registrations The incoming data to be prepped.
96
+	 * @return EE_Registration[] The data being prepared for the db
97
+	 * @throws EE_Error
98
+	 * @throws InvalidArgumentException
99
+	 * @throws InvalidDataTypeException
100
+	 * @throws InvalidInterfaceException
101
+	 */
102
+	public static  function convert_data_for_persistent_storage($registrations)
103
+	{
104
+		if (! self::validateRegistrationsForConversion($registrations)) {
105
+			return array();
106
+		}
107
+
108
+		//is this an array of ints?
109
+		$first_item = reset($registrations);
110
+		if (is_int($first_item)) {
111
+			return $registrations;
112
+		}
113
+
114
+		//k nope so let's pull from the registrations
115
+		$registration_ids = array_filter(
116
+			array_map(
117
+				function ($registration) {
118
+					if ($registration instanceof EE_Registration) {
119
+						return $registration->ID();
120
+					}
121
+					return false;
122
+				},
123
+				$registrations
124
+			)
125
+		);
126
+
127
+		return $registration_ids;
128
+	}
129
+
130
+
131
+	/**
132
+	 * This validates incoming registrations (considers whether they are ids or EE_Registration objects.
133
+	 *
134
+	 * @param array $registrations Could be EE_Registration[] or int[]
135
+	 * @return bool
136
+	 * @throws EE_Error
137
+	 * @throws InvalidArgumentException
138
+	 * @throws InvalidDataTypeException
139
+	 * @throws InvalidInterfaceException
140
+	 */
141
+	protected static function validateRegistrationsForConversion($registrations)
142
+	{
143
+		if (is_array($registrations)) {
144
+			$first_item = reset($registrations);
145
+			if ($first_item instanceof EE_Registration) {
146
+				return true;
147
+			}
148
+			if (is_int($first_item)) {
149
+				//k let's some basic validation here.  This isn't foolproof but better than nothing.
150
+				//the purpose of this validation is to verify that the ids sent in match valid registrations existing
151
+				//in the db.  If the count is different, then we know they aren't valid.
152
+				$count_for_ids = EEM_Registration::instance()->count(
153
+					array(
154
+						array(
155
+							'REG_ID' => array('IN', $registrations)
156
+						)
157
+					)
158
+				);
159
+				return $count_for_ids === count($registrations);
160
+			}
161
+		}
162
+		return false;
163
+	}
164
+
165
+
166
+	/**
167
+	 * Data that has been stored in persistent storage that was prepped by _convert_data_for_persistent_storage
168
+	 * can be sent into this method and converted back into the format used for instantiating with this data handler.
169
+	 *
170
+	 * @param array $data
171
+	 * @return EE_Registration[]
172
+	 * @throws EE_Error
173
+	 * @throws InvalidArgumentException
174
+	 * @throws InvalidDataTypeException
175
+	 * @throws InvalidInterfaceException
176
+	 */
177
+	public static function convert_data_from_persistent_storage($data)
178
+	{
179
+		//since this was added later, we need to account of possible back compat issues where data already queued for
180
+		// generation is in the old format, which is an array of EE_Registration objects.  So if that's the case, then
181
+		// let's just return them
182
+		//@see https://events.codebasehq.com/projects/event-espresso/tickets/10127
183
+		if (is_array($data) && reset($data) instanceof EE_Registration) {
184
+			return $data;
185
+		}
186
+
187
+		$registrations = is_array($data)
188
+			? EEM_Registration::instance()->get_all(array(array('REG_ID' => array('IN', $data))))
189
+			: array();
190
+		return $registrations;
191
+	}
192 192
 }
Please login to merge, or discard this patch.
core/services/cache/TransientCacheStorage.php 2 patches
Indentation   +375 added lines, -375 removed lines patch added patch discarded remove patch
@@ -19,381 +19,381 @@
 block discarded – undo
19 19
 class TransientCacheStorage implements CacheStorageInterface
20 20
 {
21 21
 
22
-    /**
23
-     * wp-option option_name for tracking transients
24
-     *
25
-     * @type string
26
-     */
27
-    const TRANSIENT_SCHEDULE_OPTIONS_KEY = 'ee_transient_schedule';
28
-
29
-    /**
30
-     * @var int $current_time
31
-     */
32
-    private $current_time;
33
-
34
-    /**
35
-     * how often to perform transient cleanup
36
-     *
37
-     * @var string $transient_cleanup_frequency
38
-     */
39
-    private $transient_cleanup_frequency;
40
-
41
-    /**
42
-     * options for how often to perform transient cleanup
43
-     *
44
-     * @var array $transient_cleanup_frequency_options
45
-     */
46
-    private $transient_cleanup_frequency_options = array();
47
-
48
-    /**
49
-     * @var array $transients
50
-     */
51
-    private $transients;
52
-
53
-
54
-
55
-    /**
56
-     * TransientCacheStorage constructor.
57
-     */
58
-    public function __construct()
59
-    {
60
-        $this->transient_cleanup_frequency = $this->setTransientCleanupFrequency();
61
-        // round current time down to closest 5 minutes to simplify scheduling
62
-        $this->current_time = $this->roundTimestamp(time(), '5-minutes', false);
63
-        $this->transients = (array)get_option(TransientCacheStorage::TRANSIENT_SCHEDULE_OPTIONS_KEY, array());
64
-        if ( ! (defined('DOING_AJAX') && DOING_AJAX) && $this->transient_cleanup_frequency !== 'off') {
65
-            add_action('shutdown', array($this, 'checkTransientCleanupSchedule'), 999);
66
-        }
67
-    }
68
-
69
-
70
-
71
-    /**
72
-     * Sets how often transient cleanup occurs
73
-     *
74
-     * @return string
75
-     */
76
-    private function setTransientCleanupFrequency()
77
-    {
78
-        // sets how often transients are cleaned up
79
-        $this->transient_cleanup_frequency_options = apply_filters(
80
-            'FHEE__TransientCacheStorage__transient_cleanup_schedule_options',
81
-            array(
82
-                'off',
83
-                '15-minutes',
84
-                'hour',
85
-                '12-hours',
86
-                'day',
87
-            )
88
-        );
89
-        $transient_cleanup_frequency = apply_filters(
90
-            'FHEE__TransientCacheStorage__transient_cleanup_schedule',
91
-            'hour'
92
-        );
93
-        return in_array(
94
-            $transient_cleanup_frequency,
95
-            $this->transient_cleanup_frequency_options,
96
-            true
97
-        )
98
-            ? $transient_cleanup_frequency
99
-            : 'hour';
100
-    }
101
-
102
-
103
-
104
-    /**
105
-     * we need to be able to round timestamps off to match the set transient cleanup frequency
106
-     * so if a transient is set to expire at 1:17 pm for example, and our cleanup schedule is every hour,
107
-     * then that timestamp needs to be rounded up to 2:00 pm so that it is removed
108
-     * during the next scheduled cleanup after its expiration.
109
-     * We also round off the current time timestamp to the closest 5 minutes
110
-     * just to make the timestamps a little easier to round which helps with debugging.
111
-     *
112
-     * @param int    $timestamp [required]
113
-     * @param string $cleanup_frequency
114
-     * @param bool   $round_up
115
-     * @return int
116
-     */
117
-    private function roundTimestamp($timestamp, $cleanup_frequency = 'hour', $round_up = true)
118
-    {
119
-        $cleanup_frequency = $cleanup_frequency ? $cleanup_frequency : $this->transient_cleanup_frequency;
120
-        // in order to round the time to the closest xx minutes (or hours),
121
-        // we take the minutes (or hours) portion of the timestamp and divide it by xx,
122
-        // round down to a whole number, then multiply by xx to bring us almost back up to where we were
123
-        // why round down ? so the minutes (or hours) don't go over 60 (or 24)
124
-        // and bump the hour, which could bump the day, which could bump the month, etc,
125
-        // which would be bad because we don't always want to round up,
126
-        // but when we do we can easily achieve that by simply adding the desired offset,
127
-        $minutes = '00';
128
-        $hours = 'H';
129
-        switch ($cleanup_frequency) {
130
-            case '5-minutes' :
131
-                $minutes = floor((int)date('i', $timestamp) / 5) * 5;
132
-                $minutes = str_pad($minutes, 2, '0', STR_PAD_LEFT);
133
-                $offset = MINUTE_IN_SECONDS * 5;
134
-                break;
135
-            case '15-minutes' :
136
-                $minutes = floor((int)date('i', $timestamp) / 15) * 15;
137
-                $minutes = str_pad($minutes, 2, '0', STR_PAD_LEFT);
138
-                $offset = MINUTE_IN_SECONDS * 15;
139
-                break;
140
-            case '12-hours' :
141
-                $hours = floor((int)date('H', $timestamp) / 12) * 12;
142
-                $hours = str_pad($hours, 2, '0', STR_PAD_LEFT);
143
-                $offset = HOUR_IN_SECONDS * 12;
144
-                break;
145
-            case 'day' :
146
-                $hours = '03'; // run cleanup at 3:00 am (or first site hit after that)
147
-                $offset = DAY_IN_SECONDS;
148
-                break;
149
-            case 'hour' :
150
-            default :
151
-                $offset = HOUR_IN_SECONDS;
152
-                break;
153
-        }
154
-        $rounded_timestamp = (int) strtotime(date("Y-m-d {$hours}:{$minutes}:00", $timestamp));
155
-        $rounded_timestamp += $round_up ? $offset : 0;
156
-        return apply_filters(
157
-            'FHEE__TransientCacheStorage__roundTimestamp__timestamp',
158
-            $rounded_timestamp,
159
-            $timestamp,
160
-            $cleanup_frequency,
161
-            $round_up
162
-        );
163
-    }
164
-
165
-
166
-
167
-    /**
168
-     * Saves supplied data to a transient
169
-     * if an expiration is set, then it automatically schedules the transient for cleanup
170
-     *
171
-     * @param string $transient_key [required]
172
-     * @param string $data          [required]
173
-     * @param int    $expiration    number of seconds until the cache expires
174
-     * @return bool
175
-     */
176
-    public function add($transient_key, $data, $expiration = 0)
177
-    {
178
-        $expiration = (int)abs($expiration);
179
-        $saved = set_transient($transient_key, $data, $expiration);
180
-        if ($saved && $expiration) {
181
-            $this->scheduleTransientCleanup($transient_key, $expiration);
182
-        }
183
-        return $saved;
184
-    }
185
-
186
-
187
-
188
-    /**
189
-     * retrieves transient data
190
-     * automatically triggers early cache refresh for standard cache items
191
-     * in order to avoid cache stampedes on busy sites.
192
-     * For non-standard cache items like PHP Session data where early refreshing is not wanted,
193
-     * the $standard_cache parameter should be set to false when retrieving data
194
-     *
195
-     * @param string $transient_key [required]
196
-     * @param bool   $standard_cache
197
-     * @return mixed|null
198
-     */
199
-    public function get($transient_key, $standard_cache = true)
200
-    {
201
-        if (isset($this->transients[ $transient_key ])) {
202
-            // to avoid cache stampedes (AKA:dogpiles) for standard cache items,
203
-            // check if known cache expires within the next minute,
204
-            // and if so, remove it from our tracking and and return nothing.
205
-            // this should trigger the cache content to be regenerated during this request,
206
-            // while allowing any following requests to still access the existing cache
207
-            // until it gets replaced with the refreshed content
208
-            if (
209
-                $standard_cache
210
-                && $this->transients[$transient_key] - time() <= MINUTE_IN_SECONDS
211
-            ) {
212
-                unset($this->transients[$transient_key]);
213
-                $this->updateTransients();
214
-                return null;
215
-            }
216
-
217
-            // for non standard cache items, remove the key from our tracking,
218
-            // but proceed to retrieve the transient so that it also gets removed from the db
219
-            if ($this->transients[$transient_key] <= time()) {
220
-                unset($this->transients[$transient_key]);
221
-                $this->updateTransients();
222
-            }
223
-        }
224
-
225
-        $content = get_transient($transient_key);
226
-        return $content !== false ? $content : null;
227
-    }
228
-
229
-
230
-
231
-    /**
232
-     * delete a single transient and remove tracking
233
-     *
234
-     * @param string $transient_key [required] full or partial transient key to be deleted
235
-     */
236
-    public function delete($transient_key)
237
-    {
238
-        $this->deleteMany(array($transient_key));
239
-    }
240
-
241
-
242
-
243
-    /**
244
-     * delete multiple transients and remove tracking
245
-     *
246
-     * @param array $transient_keys [required] array of full or partial transient keys to be deleted
247
-     * @param bool  $force_delete   [optional] if true, then will not check incoming keys against those being tracked
248
-     *                              and proceed directly to deleting those entries from the cache storage
249
-     */
250
-    public function deleteMany(array $transient_keys, $force_delete = false)
251
-    {
252
-        $full_transient_keys = $force_delete ? $transient_keys : array();
253
-        if(empty($full_transient_keys)){
254
-            foreach ($this->transients as $transient_key => $expiration) {
255
-                foreach ($transient_keys as $transient_key_to_delete) {
256
-                    if (strpos($transient_key, $transient_key_to_delete) !== false) {
257
-                        $full_transient_keys[] = $transient_key;
258
-                    }
259
-                }
260
-            }
261
-        }
262
-        if ($this->deleteTransientKeys($full_transient_keys)) {
263
-            $this->updateTransients();
264
-        }
265
-    }
266
-
267
-
268
-
269
-    /**
270
-     * sorts transients numerically by timestamp
271
-     * then saves the transient schedule to a WP option
272
-     */
273
-    private function updateTransients()
274
-    {
275
-        asort($this->transients, SORT_NUMERIC);
276
-        update_option(
277
-            TransientCacheStorage::TRANSIENT_SCHEDULE_OPTIONS_KEY,
278
-            $this->transients
279
-        );
280
-    }
281
-
282
-
283
-
284
-    /**
285
-     * schedules a transient for cleanup by adding it to the transient tracking
286
-     *
287
-     * @param string $transient_key [required]
288
-     * @param int    $expiration    [required]
289
-     */
290
-    private function scheduleTransientCleanup($transient_key, $expiration)
291
-    {
292
-        // make sure a valid future timestamp is set
293
-        $expiration += $expiration < time() ? time() : 0;
294
-        // and round to the closest 15 minutes
295
-        $expiration = $this->roundTimestamp($expiration);
296
-        // save transients to clear using their ID as the key to avoid duplicates
297
-        $this->transients[$transient_key] = $expiration;
298
-        $this->updateTransients();
299
-    }
300
-
301
-
302
-
303
-    /**
304
-     * Since our tracked transients are sorted by their timestamps
305
-     * we can grab the first transient and see when it is scheduled for cleanup.
306
-     * If that timestamp is less than or equal to the current time,
307
-     * then cleanup is triggered
308
-     */
309
-    public function checkTransientCleanupSchedule()
310
-    {
311
-        if (empty($this->transients)) {
312
-            return;
313
-        }
314
-        // when do we run the next cleanup job?
315
-        reset($this->transients);
316
-        $next_scheduled_cleanup = current($this->transients);
317
-        // if the next cleanup job is scheduled for the current hour
318
-        if ($next_scheduled_cleanup <= $this->current_time) {
319
-            if ($this->cleanupExpiredTransients()) {
320
-                $this->updateTransients();
321
-            }
322
-        }
323
-    }
324
-
325
-
326
-
327
-    /**
328
-     * loops through the array of tracked transients,
329
-     * compiles a list of those that have expired, and sends that list off for deletion.
330
-     * Also removes any bad records from the transients array
331
-     *
332
-     * @return bool
333
-     */
334
-    private function cleanupExpiredTransients()
335
-    {
336
-        $update = false;
337
-        // filter the query limit. Set to 0 to turn off garbage collection
338
-        $limit = (int)abs(
339
-            apply_filters(
340
-                'FHEE__TransientCacheStorage__clearExpiredTransients__limit',
341
-                50
342
-            )
343
-        );
344
-        // non-zero LIMIT means take out the trash
345
-        if ($limit) {
346
-            $transient_keys = array();
347
-            foreach ($this->transients as $transient_key => $expiration) {
348
-                if ($expiration > $this->current_time) {
349
-                    continue;
350
-                }
351
-                if ( ! $expiration || ! $transient_key) {
352
-                    unset($this->transients[$transient_key]);
353
-                    $update = true;
354
-                    continue;
355
-                }
356
-                $transient_keys[] = $transient_key;
357
-            }
358
-            // delete expired keys, but maintain value of $update if nothing is deleted
359
-            $update = $this->deleteTransientKeys($transient_keys, $limit) ? true : $update;
360
-            do_action( 'FHEE__TransientCacheStorage__clearExpiredTransients__end', $this);
361
-        }
362
-        return $update;
363
-    }
364
-
365
-
366
-
367
-    /**
368
-     * calls delete_transient() on each transient key provided, up to the specified limit
369
-     *
370
-     * @param array $transient_keys [required]
371
-     * @param int   $limit
372
-     * @return bool
373
-     */
374
-    private function deleteTransientKeys(array $transient_keys, $limit = 50)
375
-    {
376
-        if (empty($transient_keys)) {
377
-            return false;
378
-        }
379
-        $counter = 0;
380
-        foreach ($transient_keys as $transient_key) {
381
-            if($counter === $limit){
382
-                break;
383
-            }
384
-            // remove any transient prefixes
385
-            $transient_key = strpos($transient_key,  '_transient_timeout_') === 0
386
-                ? str_replace('_transient_timeout_', '', $transient_key)
387
-                : $transient_key;
388
-            $transient_key = strpos($transient_key,  '_transient_') === 0
389
-                ? str_replace('_transient_', '', $transient_key)
390
-                : $transient_key;
391
-            delete_transient($transient_key);
392
-            unset($this->transients[$transient_key]);
393
-            $counter++;
394
-        }
395
-        return $counter > 0;
396
-    }
22
+	/**
23
+	 * wp-option option_name for tracking transients
24
+	 *
25
+	 * @type string
26
+	 */
27
+	const TRANSIENT_SCHEDULE_OPTIONS_KEY = 'ee_transient_schedule';
28
+
29
+	/**
30
+	 * @var int $current_time
31
+	 */
32
+	private $current_time;
33
+
34
+	/**
35
+	 * how often to perform transient cleanup
36
+	 *
37
+	 * @var string $transient_cleanup_frequency
38
+	 */
39
+	private $transient_cleanup_frequency;
40
+
41
+	/**
42
+	 * options for how often to perform transient cleanup
43
+	 *
44
+	 * @var array $transient_cleanup_frequency_options
45
+	 */
46
+	private $transient_cleanup_frequency_options = array();
47
+
48
+	/**
49
+	 * @var array $transients
50
+	 */
51
+	private $transients;
52
+
53
+
54
+
55
+	/**
56
+	 * TransientCacheStorage constructor.
57
+	 */
58
+	public function __construct()
59
+	{
60
+		$this->transient_cleanup_frequency = $this->setTransientCleanupFrequency();
61
+		// round current time down to closest 5 minutes to simplify scheduling
62
+		$this->current_time = $this->roundTimestamp(time(), '5-minutes', false);
63
+		$this->transients = (array)get_option(TransientCacheStorage::TRANSIENT_SCHEDULE_OPTIONS_KEY, array());
64
+		if ( ! (defined('DOING_AJAX') && DOING_AJAX) && $this->transient_cleanup_frequency !== 'off') {
65
+			add_action('shutdown', array($this, 'checkTransientCleanupSchedule'), 999);
66
+		}
67
+	}
68
+
69
+
70
+
71
+	/**
72
+	 * Sets how often transient cleanup occurs
73
+	 *
74
+	 * @return string
75
+	 */
76
+	private function setTransientCleanupFrequency()
77
+	{
78
+		// sets how often transients are cleaned up
79
+		$this->transient_cleanup_frequency_options = apply_filters(
80
+			'FHEE__TransientCacheStorage__transient_cleanup_schedule_options',
81
+			array(
82
+				'off',
83
+				'15-minutes',
84
+				'hour',
85
+				'12-hours',
86
+				'day',
87
+			)
88
+		);
89
+		$transient_cleanup_frequency = apply_filters(
90
+			'FHEE__TransientCacheStorage__transient_cleanup_schedule',
91
+			'hour'
92
+		);
93
+		return in_array(
94
+			$transient_cleanup_frequency,
95
+			$this->transient_cleanup_frequency_options,
96
+			true
97
+		)
98
+			? $transient_cleanup_frequency
99
+			: 'hour';
100
+	}
101
+
102
+
103
+
104
+	/**
105
+	 * we need to be able to round timestamps off to match the set transient cleanup frequency
106
+	 * so if a transient is set to expire at 1:17 pm for example, and our cleanup schedule is every hour,
107
+	 * then that timestamp needs to be rounded up to 2:00 pm so that it is removed
108
+	 * during the next scheduled cleanup after its expiration.
109
+	 * We also round off the current time timestamp to the closest 5 minutes
110
+	 * just to make the timestamps a little easier to round which helps with debugging.
111
+	 *
112
+	 * @param int    $timestamp [required]
113
+	 * @param string $cleanup_frequency
114
+	 * @param bool   $round_up
115
+	 * @return int
116
+	 */
117
+	private function roundTimestamp($timestamp, $cleanup_frequency = 'hour', $round_up = true)
118
+	{
119
+		$cleanup_frequency = $cleanup_frequency ? $cleanup_frequency : $this->transient_cleanup_frequency;
120
+		// in order to round the time to the closest xx minutes (or hours),
121
+		// we take the minutes (or hours) portion of the timestamp and divide it by xx,
122
+		// round down to a whole number, then multiply by xx to bring us almost back up to where we were
123
+		// why round down ? so the minutes (or hours) don't go over 60 (or 24)
124
+		// and bump the hour, which could bump the day, which could bump the month, etc,
125
+		// which would be bad because we don't always want to round up,
126
+		// but when we do we can easily achieve that by simply adding the desired offset,
127
+		$minutes = '00';
128
+		$hours = 'H';
129
+		switch ($cleanup_frequency) {
130
+			case '5-minutes' :
131
+				$minutes = floor((int)date('i', $timestamp) / 5) * 5;
132
+				$minutes = str_pad($minutes, 2, '0', STR_PAD_LEFT);
133
+				$offset = MINUTE_IN_SECONDS * 5;
134
+				break;
135
+			case '15-minutes' :
136
+				$minutes = floor((int)date('i', $timestamp) / 15) * 15;
137
+				$minutes = str_pad($minutes, 2, '0', STR_PAD_LEFT);
138
+				$offset = MINUTE_IN_SECONDS * 15;
139
+				break;
140
+			case '12-hours' :
141
+				$hours = floor((int)date('H', $timestamp) / 12) * 12;
142
+				$hours = str_pad($hours, 2, '0', STR_PAD_LEFT);
143
+				$offset = HOUR_IN_SECONDS * 12;
144
+				break;
145
+			case 'day' :
146
+				$hours = '03'; // run cleanup at 3:00 am (or first site hit after that)
147
+				$offset = DAY_IN_SECONDS;
148
+				break;
149
+			case 'hour' :
150
+			default :
151
+				$offset = HOUR_IN_SECONDS;
152
+				break;
153
+		}
154
+		$rounded_timestamp = (int) strtotime(date("Y-m-d {$hours}:{$minutes}:00", $timestamp));
155
+		$rounded_timestamp += $round_up ? $offset : 0;
156
+		return apply_filters(
157
+			'FHEE__TransientCacheStorage__roundTimestamp__timestamp',
158
+			$rounded_timestamp,
159
+			$timestamp,
160
+			$cleanup_frequency,
161
+			$round_up
162
+		);
163
+	}
164
+
165
+
166
+
167
+	/**
168
+	 * Saves supplied data to a transient
169
+	 * if an expiration is set, then it automatically schedules the transient for cleanup
170
+	 *
171
+	 * @param string $transient_key [required]
172
+	 * @param string $data          [required]
173
+	 * @param int    $expiration    number of seconds until the cache expires
174
+	 * @return bool
175
+	 */
176
+	public function add($transient_key, $data, $expiration = 0)
177
+	{
178
+		$expiration = (int)abs($expiration);
179
+		$saved = set_transient($transient_key, $data, $expiration);
180
+		if ($saved && $expiration) {
181
+			$this->scheduleTransientCleanup($transient_key, $expiration);
182
+		}
183
+		return $saved;
184
+	}
185
+
186
+
187
+
188
+	/**
189
+	 * retrieves transient data
190
+	 * automatically triggers early cache refresh for standard cache items
191
+	 * in order to avoid cache stampedes on busy sites.
192
+	 * For non-standard cache items like PHP Session data where early refreshing is not wanted,
193
+	 * the $standard_cache parameter should be set to false when retrieving data
194
+	 *
195
+	 * @param string $transient_key [required]
196
+	 * @param bool   $standard_cache
197
+	 * @return mixed|null
198
+	 */
199
+	public function get($transient_key, $standard_cache = true)
200
+	{
201
+		if (isset($this->transients[ $transient_key ])) {
202
+			// to avoid cache stampedes (AKA:dogpiles) for standard cache items,
203
+			// check if known cache expires within the next minute,
204
+			// and if so, remove it from our tracking and and return nothing.
205
+			// this should trigger the cache content to be regenerated during this request,
206
+			// while allowing any following requests to still access the existing cache
207
+			// until it gets replaced with the refreshed content
208
+			if (
209
+				$standard_cache
210
+				&& $this->transients[$transient_key] - time() <= MINUTE_IN_SECONDS
211
+			) {
212
+				unset($this->transients[$transient_key]);
213
+				$this->updateTransients();
214
+				return null;
215
+			}
216
+
217
+			// for non standard cache items, remove the key from our tracking,
218
+			// but proceed to retrieve the transient so that it also gets removed from the db
219
+			if ($this->transients[$transient_key] <= time()) {
220
+				unset($this->transients[$transient_key]);
221
+				$this->updateTransients();
222
+			}
223
+		}
224
+
225
+		$content = get_transient($transient_key);
226
+		return $content !== false ? $content : null;
227
+	}
228
+
229
+
230
+
231
+	/**
232
+	 * delete a single transient and remove tracking
233
+	 *
234
+	 * @param string $transient_key [required] full or partial transient key to be deleted
235
+	 */
236
+	public function delete($transient_key)
237
+	{
238
+		$this->deleteMany(array($transient_key));
239
+	}
240
+
241
+
242
+
243
+	/**
244
+	 * delete multiple transients and remove tracking
245
+	 *
246
+	 * @param array $transient_keys [required] array of full or partial transient keys to be deleted
247
+	 * @param bool  $force_delete   [optional] if true, then will not check incoming keys against those being tracked
248
+	 *                              and proceed directly to deleting those entries from the cache storage
249
+	 */
250
+	public function deleteMany(array $transient_keys, $force_delete = false)
251
+	{
252
+		$full_transient_keys = $force_delete ? $transient_keys : array();
253
+		if(empty($full_transient_keys)){
254
+			foreach ($this->transients as $transient_key => $expiration) {
255
+				foreach ($transient_keys as $transient_key_to_delete) {
256
+					if (strpos($transient_key, $transient_key_to_delete) !== false) {
257
+						$full_transient_keys[] = $transient_key;
258
+					}
259
+				}
260
+			}
261
+		}
262
+		if ($this->deleteTransientKeys($full_transient_keys)) {
263
+			$this->updateTransients();
264
+		}
265
+	}
266
+
267
+
268
+
269
+	/**
270
+	 * sorts transients numerically by timestamp
271
+	 * then saves the transient schedule to a WP option
272
+	 */
273
+	private function updateTransients()
274
+	{
275
+		asort($this->transients, SORT_NUMERIC);
276
+		update_option(
277
+			TransientCacheStorage::TRANSIENT_SCHEDULE_OPTIONS_KEY,
278
+			$this->transients
279
+		);
280
+	}
281
+
282
+
283
+
284
+	/**
285
+	 * schedules a transient for cleanup by adding it to the transient tracking
286
+	 *
287
+	 * @param string $transient_key [required]
288
+	 * @param int    $expiration    [required]
289
+	 */
290
+	private function scheduleTransientCleanup($transient_key, $expiration)
291
+	{
292
+		// make sure a valid future timestamp is set
293
+		$expiration += $expiration < time() ? time() : 0;
294
+		// and round to the closest 15 minutes
295
+		$expiration = $this->roundTimestamp($expiration);
296
+		// save transients to clear using their ID as the key to avoid duplicates
297
+		$this->transients[$transient_key] = $expiration;
298
+		$this->updateTransients();
299
+	}
300
+
301
+
302
+
303
+	/**
304
+	 * Since our tracked transients are sorted by their timestamps
305
+	 * we can grab the first transient and see when it is scheduled for cleanup.
306
+	 * If that timestamp is less than or equal to the current time,
307
+	 * then cleanup is triggered
308
+	 */
309
+	public function checkTransientCleanupSchedule()
310
+	{
311
+		if (empty($this->transients)) {
312
+			return;
313
+		}
314
+		// when do we run the next cleanup job?
315
+		reset($this->transients);
316
+		$next_scheduled_cleanup = current($this->transients);
317
+		// if the next cleanup job is scheduled for the current hour
318
+		if ($next_scheduled_cleanup <= $this->current_time) {
319
+			if ($this->cleanupExpiredTransients()) {
320
+				$this->updateTransients();
321
+			}
322
+		}
323
+	}
324
+
325
+
326
+
327
+	/**
328
+	 * loops through the array of tracked transients,
329
+	 * compiles a list of those that have expired, and sends that list off for deletion.
330
+	 * Also removes any bad records from the transients array
331
+	 *
332
+	 * @return bool
333
+	 */
334
+	private function cleanupExpiredTransients()
335
+	{
336
+		$update = false;
337
+		// filter the query limit. Set to 0 to turn off garbage collection
338
+		$limit = (int)abs(
339
+			apply_filters(
340
+				'FHEE__TransientCacheStorage__clearExpiredTransients__limit',
341
+				50
342
+			)
343
+		);
344
+		// non-zero LIMIT means take out the trash
345
+		if ($limit) {
346
+			$transient_keys = array();
347
+			foreach ($this->transients as $transient_key => $expiration) {
348
+				if ($expiration > $this->current_time) {
349
+					continue;
350
+				}
351
+				if ( ! $expiration || ! $transient_key) {
352
+					unset($this->transients[$transient_key]);
353
+					$update = true;
354
+					continue;
355
+				}
356
+				$transient_keys[] = $transient_key;
357
+			}
358
+			// delete expired keys, but maintain value of $update if nothing is deleted
359
+			$update = $this->deleteTransientKeys($transient_keys, $limit) ? true : $update;
360
+			do_action( 'FHEE__TransientCacheStorage__clearExpiredTransients__end', $this);
361
+		}
362
+		return $update;
363
+	}
364
+
365
+
366
+
367
+	/**
368
+	 * calls delete_transient() on each transient key provided, up to the specified limit
369
+	 *
370
+	 * @param array $transient_keys [required]
371
+	 * @param int   $limit
372
+	 * @return bool
373
+	 */
374
+	private function deleteTransientKeys(array $transient_keys, $limit = 50)
375
+	{
376
+		if (empty($transient_keys)) {
377
+			return false;
378
+		}
379
+		$counter = 0;
380
+		foreach ($transient_keys as $transient_key) {
381
+			if($counter === $limit){
382
+				break;
383
+			}
384
+			// remove any transient prefixes
385
+			$transient_key = strpos($transient_key,  '_transient_timeout_') === 0
386
+				? str_replace('_transient_timeout_', '', $transient_key)
387
+				: $transient_key;
388
+			$transient_key = strpos($transient_key,  '_transient_') === 0
389
+				? str_replace('_transient_', '', $transient_key)
390
+				: $transient_key;
391
+			delete_transient($transient_key);
392
+			unset($this->transients[$transient_key]);
393
+			$counter++;
394
+		}
395
+		return $counter > 0;
396
+	}
397 397
 
398 398
 
399 399
 
Please login to merge, or discard this patch.
Spacing   +12 added lines, -12 removed lines patch added patch discarded remove patch
@@ -60,7 +60,7 @@  discard block
 block discarded – undo
60 60
         $this->transient_cleanup_frequency = $this->setTransientCleanupFrequency();
61 61
         // round current time down to closest 5 minutes to simplify scheduling
62 62
         $this->current_time = $this->roundTimestamp(time(), '5-minutes', false);
63
-        $this->transients = (array)get_option(TransientCacheStorage::TRANSIENT_SCHEDULE_OPTIONS_KEY, array());
63
+        $this->transients = (array) get_option(TransientCacheStorage::TRANSIENT_SCHEDULE_OPTIONS_KEY, array());
64 64
         if ( ! (defined('DOING_AJAX') && DOING_AJAX) && $this->transient_cleanup_frequency !== 'off') {
65 65
             add_action('shutdown', array($this, 'checkTransientCleanupSchedule'), 999);
66 66
         }
@@ -128,17 +128,17 @@  discard block
 block discarded – undo
128 128
         $hours = 'H';
129 129
         switch ($cleanup_frequency) {
130 130
             case '5-minutes' :
131
-                $minutes = floor((int)date('i', $timestamp) / 5) * 5;
131
+                $minutes = floor((int) date('i', $timestamp) / 5) * 5;
132 132
                 $minutes = str_pad($minutes, 2, '0', STR_PAD_LEFT);
133 133
                 $offset = MINUTE_IN_SECONDS * 5;
134 134
                 break;
135 135
             case '15-minutes' :
136
-                $minutes = floor((int)date('i', $timestamp) / 15) * 15;
136
+                $minutes = floor((int) date('i', $timestamp) / 15) * 15;
137 137
                 $minutes = str_pad($minutes, 2, '0', STR_PAD_LEFT);
138 138
                 $offset = MINUTE_IN_SECONDS * 15;
139 139
                 break;
140 140
             case '12-hours' :
141
-                $hours = floor((int)date('H', $timestamp) / 12) * 12;
141
+                $hours = floor((int) date('H', $timestamp) / 12) * 12;
142 142
                 $hours = str_pad($hours, 2, '0', STR_PAD_LEFT);
143 143
                 $offset = HOUR_IN_SECONDS * 12;
144 144
                 break;
@@ -175,7 +175,7 @@  discard block
 block discarded – undo
175 175
      */
176 176
     public function add($transient_key, $data, $expiration = 0)
177 177
     {
178
-        $expiration = (int)abs($expiration);
178
+        $expiration = (int) abs($expiration);
179 179
         $saved = set_transient($transient_key, $data, $expiration);
180 180
         if ($saved && $expiration) {
181 181
             $this->scheduleTransientCleanup($transient_key, $expiration);
@@ -198,7 +198,7 @@  discard block
 block discarded – undo
198 198
      */
199 199
     public function get($transient_key, $standard_cache = true)
200 200
     {
201
-        if (isset($this->transients[ $transient_key ])) {
201
+        if (isset($this->transients[$transient_key])) {
202 202
             // to avoid cache stampedes (AKA:dogpiles) for standard cache items,
203 203
             // check if known cache expires within the next minute,
204 204
             // and if so, remove it from our tracking and and return nothing.
@@ -250,7 +250,7 @@  discard block
 block discarded – undo
250 250
     public function deleteMany(array $transient_keys, $force_delete = false)
251 251
     {
252 252
         $full_transient_keys = $force_delete ? $transient_keys : array();
253
-        if(empty($full_transient_keys)){
253
+        if (empty($full_transient_keys)) {
254 254
             foreach ($this->transients as $transient_key => $expiration) {
255 255
                 foreach ($transient_keys as $transient_key_to_delete) {
256 256
                     if (strpos($transient_key, $transient_key_to_delete) !== false) {
@@ -335,7 +335,7 @@  discard block
 block discarded – undo
335 335
     {
336 336
         $update = false;
337 337
         // filter the query limit. Set to 0 to turn off garbage collection
338
-        $limit = (int)abs(
338
+        $limit = (int) abs(
339 339
             apply_filters(
340 340
                 'FHEE__TransientCacheStorage__clearExpiredTransients__limit',
341 341
                 50
@@ -357,7 +357,7 @@  discard block
 block discarded – undo
357 357
             }
358 358
             // delete expired keys, but maintain value of $update if nothing is deleted
359 359
             $update = $this->deleteTransientKeys($transient_keys, $limit) ? true : $update;
360
-            do_action( 'FHEE__TransientCacheStorage__clearExpiredTransients__end', $this);
360
+            do_action('FHEE__TransientCacheStorage__clearExpiredTransients__end', $this);
361 361
         }
362 362
         return $update;
363 363
     }
@@ -378,14 +378,14 @@  discard block
 block discarded – undo
378 378
         }
379 379
         $counter = 0;
380 380
         foreach ($transient_keys as $transient_key) {
381
-            if($counter === $limit){
381
+            if ($counter === $limit) {
382 382
                 break;
383 383
             }
384 384
             // remove any transient prefixes
385
-            $transient_key = strpos($transient_key,  '_transient_timeout_') === 0
385
+            $transient_key = strpos($transient_key, '_transient_timeout_') === 0
386 386
                 ? str_replace('_transient_timeout_', '', $transient_key)
387 387
                 : $transient_key;
388
-            $transient_key = strpos($transient_key,  '_transient_') === 0
388
+            $transient_key = strpos($transient_key, '_transient_') === 0
389 389
                 ? str_replace('_transient_', '', $transient_key)
390 390
                 : $transient_key;
391 391
             delete_transient($transient_key);
Please login to merge, or discard this patch.
admin_pages/maintenance/Maintenance_Admin_Page.core.php 1 patch
Indentation   +827 added lines, -827 removed lines patch added patch discarded remove patch
@@ -29,843 +29,843 @@
 block discarded – undo
29 29
 {
30 30
 
31 31
 
32
-    /**
33
-     * @var EE_Datetime_Offset_Fix_Form
34
-     */
35
-    protected $datetime_fix_offset_form;
36
-
37
-
38
-
39
-    protected function _init_page_props()
40
-    {
41
-        $this->page_slug = EE_MAINTENANCE_PG_SLUG;
42
-        $this->page_label = EE_MAINTENANCE_LABEL;
43
-        $this->_admin_base_url = EE_MAINTENANCE_ADMIN_URL;
44
-        $this->_admin_base_path = EE_MAINTENANCE_ADMIN;
45
-    }
46
-
47
-
48
-
49
-    protected function _ajax_hooks()
50
-    {
51
-        add_action('wp_ajax_migration_step', array($this, 'migration_step'));
52
-        add_action('wp_ajax_add_error_to_migrations_ran', array($this, 'add_error_to_migrations_ran'));
53
-    }
54
-
55
-
56
-
57
-    protected function _define_page_props()
58
-    {
59
-        $this->_admin_page_title = EE_MAINTENANCE_LABEL;
60
-        $this->_labels = array(
61
-            'buttons' => array(
62
-                'reset_reservations' => esc_html__('Reset Ticket and Datetime Reserved Counts', 'event_espresso'),
63
-                'reset_capabilities' => esc_html__('Reset Event Espresso Capabilities', 'event_espresso'),
64
-            ),
65
-        );
66
-    }
67
-
68
-
69
-
70
-    protected function _set_page_routes()
71
-    {
72
-        $this->_page_routes = array(
73
-            'default'                             => array(
74
-                'func'       => '_maintenance',
75
-                'capability' => 'manage_options',
76
-            ),
77
-            'change_maintenance_level'            => array(
78
-                'func'       => '_change_maintenance_level',
79
-                'capability' => 'manage_options',
80
-                'noheader'   => true,
81
-            ),
82
-            'system_status'                       => array(
83
-                'func'       => '_system_status',
84
-                'capability' => 'manage_options',
85
-            ),
86
-            'download_system_status' => array(
87
-                'func'       => '_download_system_status',
88
-                'capability' => 'manage_options',
89
-                'noheader'   => true,
90
-            ),
91
-            'send_migration_crash_report'         => array(
92
-                'func'       => '_send_migration_crash_report',
93
-                'capability' => 'manage_options',
94
-                'noheader'   => true,
95
-            ),
96
-            'confirm_migration_crash_report_sent' => array(
97
-                'func'       => '_confirm_migration_crash_report_sent',
98
-                'capability' => 'manage_options',
99
-            ),
100
-            'data_reset'                          => array(
101
-                'func'       => '_data_reset_and_delete',
102
-                'capability' => 'manage_options',
103
-            ),
104
-            'reset_db'                            => array(
105
-                'func'       => '_reset_db',
106
-                'capability' => 'manage_options',
107
-                'noheader'   => true,
108
-                'args'       => array('nuke_old_ee4_data' => true),
109
-            ),
110
-            'start_with_fresh_ee4_db'             => array(
111
-                'func'       => '_reset_db',
112
-                'capability' => 'manage_options',
113
-                'noheader'   => true,
114
-                'args'       => array('nuke_old_ee4_data' => false),
115
-            ),
116
-            'delete_db'                           => array(
117
-                'func'       => '_delete_db',
118
-                'capability' => 'manage_options',
119
-                'noheader'   => true,
120
-            ),
121
-            'rerun_migration_from_ee3'            => array(
122
-                'func'       => '_rerun_migration_from_ee3',
123
-                'capability' => 'manage_options',
124
-                'noheader'   => true,
125
-            ),
126
-            'reset_reservations'                  => array(
127
-                'func'       => '_reset_reservations',
128
-                'capability' => 'manage_options',
129
-                'noheader'   => true,
130
-            ),
131
-            'reset_capabilities'                  => array(
132
-                'func'       => '_reset_capabilities',
133
-                'capability' => 'manage_options',
134
-                'noheader'   => true,
135
-            ),
136
-            'reattempt_migration'                 => array(
137
-                'func'       => '_reattempt_migration',
138
-                'capability' => 'manage_options',
139
-                'noheader'   => true,
140
-            ),
141
-            'datetime_tools' => array(
142
-                'func' => '_datetime_tools',
143
-                'capability' => 'manage_options'
144
-            ),
145
-            'run_datetime_offset_fix' => array(
146
-                'func' => '_apply_datetime_offset',
147
-                'noheader' => true,
148
-                'headers_sent_route' => 'datetime_tools',
149
-                'capability' => 'manage_options'
150
-            )
151
-        );
152
-    }
153
-
154
-
155
-
156
-    protected function _set_page_config()
157
-    {
158
-        $this->_page_config = array(
159
-            'default'       => array(
160
-                'nav'           => array(
161
-                    'label' => esc_html__('Maintenance', 'event_espresso'),
162
-                    'order' => 10,
163
-                ),
164
-                'require_nonce' => false,
165
-            ),
166
-            'data_reset'    => array(
167
-                'nav'           => array(
168
-                    'label' => esc_html__('Reset/Delete Data', 'event_espresso'),
169
-                    'order' => 20,
170
-                ),
171
-                'require_nonce' => false,
172
-            ),
173
-            'datetime_tools' => array(
174
-                'nav' => array(
175
-                    'label' => esc_html__('Datetime Utilities', 'event_espresso'),
176
-                    'order' => 25
177
-                ),
178
-                'require_nonce' => false,
179
-            ),
180
-            'system_status' => array(
181
-                'nav'           => array(
182
-                    'label' => esc_html__("System Information", "event_espresso"),
183
-                    'order' => 30,
184
-                ),
185
-                'require_nonce' => false,
186
-            ),
187
-        );
188
-    }
189
-
190
-
191
-
192
-    /**
193
-     * default maintenance page. If we're in maintenance mode level 2, then we need to show
194
-     * the migration scripts and all that UI.
195
-     */
196
-    public function _maintenance()
197
-    {
198
-        //it all depends if we're in maintenance model level 1 (frontend-only) or
199
-        //level 2 (everything except maintenance page)
200
-        try {
201
-            //get the current maintenance level and check if
202
-            //we are removed
203
-            $mm = EE_Maintenance_Mode::instance()->level();
204
-            $placed_in_mm = EE_Maintenance_Mode::instance()->set_maintenance_mode_if_db_old();
205
-            if ($mm == EE_Maintenance_Mode::level_2_complete_maintenance && ! $placed_in_mm) {
206
-                //we just took the site out of maintenance mode, so notify the user.
207
-                //unfortunately this message appears to be echoed on the NEXT page load...
208
-                //oh well, we should really be checking for this on addon deactivation anyways
209
-                EE_Error::add_attention(__('Site taken out of maintenance mode because no data migration scripts are required',
210
-                    'event_espresso'));
211
-                $this->_process_notices(array('page' => 'espresso_maintenance_settings'), false);
212
-            }
213
-            //in case an exception is thrown while trying to handle migrations
214
-            switch (EE_Maintenance_Mode::instance()->level()) {
215
-                case EE_Maintenance_Mode::level_0_not_in_maintenance:
216
-                case EE_Maintenance_Mode::level_1_frontend_only_maintenance:
217
-                    $show_maintenance_switch = true;
218
-                    $show_backup_db_text = false;
219
-                    $show_migration_progress = false;
220
-                    $script_names = array();
221
-                    $addons_should_be_upgraded_first = false;
222
-                    break;
223
-                case EE_Maintenance_Mode::level_2_complete_maintenance:
224
-                    $show_maintenance_switch = false;
225
-                    $show_migration_progress = true;
226
-                    if (isset($this->_req_data['continue_migration'])) {
227
-                        $show_backup_db_text = false;
228
-                    } else {
229
-                        $show_backup_db_text = true;
230
-                    }
231
-                    $scripts_needing_to_run = EE_Data_Migration_Manager::instance()
232
-                                                                       ->check_for_applicable_data_migration_scripts();
233
-                    $addons_should_be_upgraded_first = EE_Data_Migration_Manager::instance()->addons_need_updating();
234
-                    $script_names = array();
235
-                    $current_script = null;
236
-                    foreach ($scripts_needing_to_run as $script) {
237
-                        if ($script instanceof EE_Data_Migration_Script_Base) {
238
-                            if ( ! $current_script) {
239
-                                $current_script = $script;
240
-                                $current_script->migration_page_hooks();
241
-                            }
242
-                            $script_names[] = $script->pretty_name();
243
-                        }
244
-                    }
245
-                    break;
246
-            }
247
-            $most_recent_migration = EE_Data_Migration_Manager::instance()->get_last_ran_script(true);
248
-            $exception_thrown = false;
249
-        } catch (EE_Error $e) {
250
-            EE_Data_Migration_Manager::instance()->add_error_to_migrations_ran($e->getMessage());
251
-            //now, just so we can display the page correctly, make a error migration script stage object
252
-            //and also put the error on it. It only persists for the duration of this request
253
-            $most_recent_migration = new EE_DMS_Unknown_1_0_0();
254
-            $most_recent_migration->add_error($e->getMessage());
255
-            $exception_thrown = true;
256
-        }
257
-        $current_db_state = EE_Data_Migration_Manager::instance()->ensure_current_database_state_is_set();
258
-        $current_db_state = str_replace('.decaf', '', $current_db_state);
259
-        if ($exception_thrown
260
-            || ($most_recent_migration
261
-                && $most_recent_migration instanceof EE_Data_Migration_Script_Base
262
-                && $most_recent_migration->is_broken()
263
-            )
264
-        ) {
265
-            $this->_template_path = EE_MAINTENANCE_TEMPLATE_PATH . 'ee_migration_was_borked_page.template.php';
266
-            $this->_template_args['support_url'] = 'http://eventespresso.com/support/forums/';
267
-            $this->_template_args['next_url'] = EEH_URL::add_query_args_and_nonce(array('action'  => 'confirm_migration_crash_report_sent',
268
-                                                                                        'success' => '0',
269
-            ), EE_MAINTENANCE_ADMIN_URL);
270
-        } elseif ($addons_should_be_upgraded_first) {
271
-            $this->_template_path = EE_MAINTENANCE_TEMPLATE_PATH . 'ee_upgrade_addons_before_migrating.template.php';
272
-        } else {
273
-            if ($most_recent_migration
274
-                && $most_recent_migration instanceof EE_Data_Migration_Script_Base
275
-                && $most_recent_migration->can_continue()
276
-            ) {
277
-                $show_backup_db_text = false;
278
-                $show_continue_current_migration_script = true;
279
-                $show_most_recent_migration = true;
280
-            } elseif (isset($this->_req_data['continue_migration'])) {
281
-                $show_most_recent_migration = true;
282
-                $show_continue_current_migration_script = false;
283
-            } else {
284
-                $show_most_recent_migration = false;
285
-                $show_continue_current_migration_script = false;
286
-            }
287
-            if (isset($current_script)) {
288
-                $migrates_to = $current_script->migrates_to_version();
289
-                $plugin_slug = $migrates_to['slug'];
290
-                $new_version = $migrates_to['version'];
291
-                $this->_template_args = array_merge($this->_template_args, array(
292
-                    'current_db_state' => sprintf(__("EE%s (%s)", "event_espresso"),
293
-                        isset($current_db_state[$plugin_slug]) ? $current_db_state[$plugin_slug] : 3, $plugin_slug),
294
-                    'next_db_state'    => isset($current_script) ? sprintf(__("EE%s (%s)", 'event_espresso'),
295
-                        $new_version, $plugin_slug) : null,
296
-                ));
297
-            } else {
298
-                $this->_template_args['current_db_state'] = null;
299
-                $this->_template_args['next_db_state'] = null;
300
-            }
301
-            $this->_template_path = EE_MAINTENANCE_TEMPLATE_PATH . 'ee_migration_page.template.php';
302
-            $this->_template_args = array_merge(
303
-                $this->_template_args,
304
-                array(
305
-                    'show_most_recent_migration'             => $show_most_recent_migration,
306
-                    //flag for showing the most recent migration's status and/or errors
307
-                    'show_migration_progress'                => $show_migration_progress,
308
-                    //flag for showing the option to run migrations and see their progress
309
-                    'show_backup_db_text'                    => $show_backup_db_text,
310
-                    //flag for showing text telling the user to backup their DB
311
-                    'show_maintenance_switch'                => $show_maintenance_switch,
312
-                    //flag for showing the option to change maintenance mode between levels 0 and 1
313
-                    'script_names'                           => $script_names,
314
-                    //array of names of scripts that have run
315
-                    'show_continue_current_migration_script' => $show_continue_current_migration_script,
316
-                    //flag to change wording to indicating that we're only CONTINUING a migration script (somehow it got interrupted0
317
-                    'reset_db_page_link'                     => EE_Admin_Page::add_query_args_and_nonce(array('action' => 'reset_db'),
318
-                        EE_MAINTENANCE_ADMIN_URL),
319
-                    'data_reset_page'                        => EE_Admin_Page::add_query_args_and_nonce(array('action' => 'data_reset'),
320
-                        EE_MAINTENANCE_ADMIN_URL),
321
-                    'update_migration_script_page_link'      => EE_Admin_Page::add_query_args_and_nonce(array('action' => 'change_maintenance_level'),
322
-                        EE_MAINTENANCE_ADMIN_URL),
323
-                    'ultimate_db_state'                      => sprintf(__("EE%s", 'event_espresso'),
324
-                        espresso_version()),
325
-                )
326
-            );
327
-            //make sure we have the form fields helper available. It usually is, but sometimes it isn't
328
-        }
329
-        $this->_template_args['most_recent_migration'] = $most_recent_migration;//the actual most recently ran migration
330
-        //now render the migration options part, and put it in a variable
331
-        $migration_options_template_file = apply_filters(
332
-            'FHEE__ee_migration_page__migration_options_template',
333
-            EE_MAINTENANCE_TEMPLATE_PATH . 'migration_options_from_ee4.template.php'
334
-        );
335
-        $migration_options_html = EEH_Template::display_template($migration_options_template_file, $this->_template_args,true);
336
-        $this->_template_args['migration_options_html'] = $migration_options_html;
337
-        $this->_template_args['admin_page_content'] = EEH_Template::display_template($this->_template_path,
338
-            $this->_template_args, true);
339
-        $this->display_admin_page_with_sidebar();
340
-    }
341
-
342
-
343
-
344
-    /**
345
-     * returns JSON and executes another step of the currently-executing data migration (called via ajax)
346
-     */
347
-    public function migration_step()
348
-    {
349
-        $this->_template_args['data'] = EE_Data_Migration_Manager::instance()->response_to_migration_ajax_request();
350
-        $this->_return_json();
351
-    }
352
-
353
-
354
-
355
-    /**
356
-     * Can be used by js when it notices a response with HTML in it in order
357
-     * to log the malformed response
358
-     */
359
-    public function add_error_to_migrations_ran()
360
-    {
361
-        EE_Data_Migration_Manager::instance()->add_error_to_migrations_ran($this->_req_data['message']);
362
-        $this->_template_args['data'] = array('ok' => true);
363
-        $this->_return_json();
364
-    }
365
-
366
-
367
-
368
-    /**
369
-     * changes the maintenance level, provided there are still no migration scripts that should run
370
-     */
371
-    public function _change_maintenance_level()
372
-    {
373
-        $new_level = absint($this->_req_data['maintenance_mode_level']);
374
-        if ( ! EE_Data_Migration_Manager::instance()->check_for_applicable_data_migration_scripts()) {
375
-            EE_Maintenance_Mode::instance()->set_maintenance_level($new_level);
376
-            $success = true;
377
-        } else {
378
-            EE_Maintenance_Mode::instance()->set_maintenance_mode_if_db_old();
379
-            $success = false;
380
-        }
381
-        $this->_redirect_after_action($success, 'Maintenance Mode', esc_html__("Updated", "event_espresso"));
382
-    }
383
-
384
-
385
-
386
-    /**
387
-     * a tab with options for resetting and/or deleting EE data
388
-     *
389
-     * @throws \EE_Error
390
-     * @throws \DomainException
391
-     */
392
-    public function _data_reset_and_delete()
393
-    {
394
-        $this->_template_path = EE_MAINTENANCE_TEMPLATE_PATH . 'ee_data_reset_and_delete.template.php';
395
-        $this->_template_args['reset_reservations_button'] = $this->get_action_link_or_button(
396
-            'reset_reservations',
397
-            'reset_reservations',
398
-            array(),
399
-            'button button-primary ee-confirm',
400
-            '',
401
-            false
402
-        );
403
-        $this->_template_args['reset_capabilities_button'] = $this->get_action_link_or_button(
404
-            'reset_capabilities',
405
-            'reset_capabilities',
406
-            array(),
407
-            'button button-primary ee-confirm',
408
-            '',
409
-            false
410
-        );
411
-        $this->_template_args['delete_db_url'] = EE_Admin_Page::add_query_args_and_nonce(
412
-            array('action' => 'delete_db'),
413
-            EE_MAINTENANCE_ADMIN_URL
414
-        );
415
-        $this->_template_args['reset_db_url'] = EE_Admin_Page::add_query_args_and_nonce(
416
-            array('action' => 'reset_db'),
417
-            EE_MAINTENANCE_ADMIN_URL
418
-        );
419
-        $this->_template_args['admin_page_content'] = EEH_Template::display_template(
420
-            $this->_template_path,
421
-            $this->_template_args,
422
-            true
423
-        );
424
-        $this->display_admin_page_with_sidebar();
425
-    }
426
-
427
-
428
-
429
-    protected function _reset_reservations()
430
-    {
431
-        if(\EED_Ticket_Sales_Monitor::reset_reservation_counts()) {
432
-            EE_Error::add_success(
433
-                __(
434
-                    'Ticket and datetime reserved counts have been successfully reset.',
435
-                    'event_espresso'
436
-                )
437
-            );
438
-        } else {
439
-            EE_Error::add_success(
440
-                __(
441
-                    'Ticket and datetime reserved counts were correct and did not need resetting.',
442
-                    'event_espresso'
443
-                )
444
-            );
445
-        }
446
-        $this->_redirect_after_action(true, '', '', array('action' => 'data_reset'), true);
447
-    }
448
-
449
-
450
-
451
-    protected function _reset_capabilities()
452
-    {
453
-        EE_Registry::instance()->CAP->init_caps(true);
454
-        EE_Error::add_success(__('Default Event Espresso capabilities have been restored for all current roles.',
455
-            'event_espresso'));
456
-        $this->_redirect_after_action(false, '', '', array('action' => 'data_reset'), true);
457
-    }
458
-
459
-
460
-
461
-    /**
462
-     * resets the DMSs so we can attempt to continue migrating after a fatal error
463
-     * (only a good idea when someone has somehow tried ot fix whatever caused
464
-     * the fatal error in teh first place)
465
-     */
466
-    protected function _reattempt_migration()
467
-    {
468
-        EE_Data_Migration_Manager::instance()->reattempt();
469
-        $this->_redirect_after_action(false, '', '', array('action' => 'default'), true);
470
-    }
471
-
472
-
473
-
474
-    /**
475
-     * shows the big ol' System Information page
476
-     */
477
-    public function _system_status()
478
-    {
479
-        $this->_template_path = EE_MAINTENANCE_TEMPLATE_PATH . 'ee_system_stati_page.template.php';
480
-        $this->_template_args['system_stati'] = EEM_System_Status::instance()->get_system_stati();
481
-        $this->_template_args['download_system_status_url'] = EE_Admin_Page::add_query_args_and_nonce(
482
-            array(
483
-                'action' => 'download_system_status',
484
-            ),
485
-            EE_MAINTENANCE_ADMIN_URL
486
-        );
487
-        $this->_template_args['admin_page_content'] = EEH_Template::display_template($this->_template_path,
488
-            $this->_template_args, true);
489
-        $this->display_admin_page_with_sidebar();
490
-    }
491
-
492
-    /**
493
-     * Downloads an HTML file of the system status that can be easily stored or emailed
494
-     */
495
-    public function _download_system_status()
496
-    {
497
-        $status_info = EEM_System_Status::instance()->get_system_stati();
498
-        header( 'Content-Disposition: attachment' );
499
-        header( "Content-Disposition: attachment; filename=system_status_" . sanitize_key( site_url() ) . ".html" );
500
-        echo "<style>table{border:1px solid darkgrey;}td{vertical-align:top}</style>";
501
-        echo "<h1>System Information for " . site_url() . "</h1>";
502
-        echo EEH_Template::layout_array_as_table( $status_info );
503
-        die;
504
-    }
505
-
506
-
507
-
508
-    public function _send_migration_crash_report()
509
-    {
510
-        $from = $this->_req_data['from'];
511
-        $from_name = $this->_req_data['from_name'];
512
-        $body = $this->_req_data['body'];
513
-        try {
514
-            $success = wp_mail(EE_SUPPORT_EMAIL,
515
-                'Migration Crash Report',
516
-                $body . "/r/n<br>" . print_r(EEM_System_Status::instance()->get_system_stati(), true),
517
-                array(
518
-                    "from:$from_name<$from>",
519
-                    //					'content-type:text/html charset=UTF-8'
520
-                ));
521
-        } catch (Exception $e) {
522
-            $success = false;
523
-        }
524
-        $this->_redirect_after_action($success, esc_html__("Migration Crash Report", "event_espresso"),
525
-            esc_html__("sent", "event_espresso"),
526
-            array('success' => $success, 'action' => 'confirm_migration_crash_report_sent'));
527
-    }
528
-
529
-
530
-
531
-    public function _confirm_migration_crash_report_sent()
532
-    {
533
-        try {
534
-            $most_recent_migration = EE_Data_Migration_Manager::instance()->get_last_ran_script(true);
535
-        } catch (EE_Error $e) {
536
-            EE_Data_Migration_Manager::instance()->add_error_to_migrations_ran($e->getMessage());
537
-            //now, just so we can display the page correctly, make a error migration script stage object
538
-            //and also put the error on it. It only persists for the duration of this request
539
-            $most_recent_migration = new EE_DMS_Unknown_1_0_0();
540
-            $most_recent_migration->add_error($e->getMessage());
541
-        }
542
-        $success = $this->_req_data['success'] == '1' ? true : false;
543
-        $this->_template_args['success'] = $success;
544
-        $this->_template_args['most_recent_migration'] = $most_recent_migration;
545
-        $this->_template_args['reset_db_action_url'] = EE_Admin_Page::add_query_args_and_nonce(array('action' => 'reset_db'),
546
-            EE_MAINTENANCE_ADMIN_URL);
547
-        $this->_template_args['reset_db_page_url'] = EE_Admin_Page::add_query_args_and_nonce(array('action' => 'data_reset'),
548
-            EE_MAINTENANCE_ADMIN_URL);
549
-        $this->_template_args['reattempt_action_url'] = EE_Admin_Page::add_query_args_and_nonce(array('action' => 'reattempt_migration'),
550
-            EE_MAINTENANCE_ADMIN_URL);
551
-        $this->_template_path = EE_MAINTENANCE_TEMPLATE_PATH . 'ee_confirm_migration_crash_report_sent.template.php';
552
-        $this->_template_args['admin_page_content'] = EEH_Template::display_template($this->_template_path,
553
-            $this->_template_args, true);
554
-        $this->display_admin_page_with_sidebar();
555
-    }
556
-
557
-
558
-
559
-    /**
560
-     * Resets the entire EE4 database.
561
-     * Currently basically only sets up ee4 database for a fresh install- doesn't
562
-     * actually clean out the old wp options, or cpts (although does erase old ee table data)
563
-     *
564
-     * @param boolean $nuke_old_ee4_data controls whether or not we
565
-     *                                   destroy the old ee4 data, or just try initializing ee4 default data
566
-     */
567
-    public function _reset_db($nuke_old_ee4_data = true)
568
-    {
569
-        EE_Maintenance_Mode::instance()->set_maintenance_level(EE_Maintenance_Mode::level_0_not_in_maintenance);
570
-        if ($nuke_old_ee4_data) {
571
-            EEH_Activation::delete_all_espresso_cpt_data();
572
-            EEH_Activation::delete_all_espresso_tables_and_data(false);
573
-            EEH_Activation::remove_cron_tasks();
574
-        }
575
-        //make sure when we reset the registry's config that it
576
-        //switches to using the new singleton
577
-        EE_Registry::instance()->CFG = EE_Registry::instance()->CFG->reset(true);
578
-        EE_System::instance()->initialize_db_if_no_migrations_required(true);
579
-        EE_System::instance()->redirect_to_about_ee();
580
-    }
581
-
582
-
583
-
584
-    /**
585
-     * Deletes ALL EE tables, Records, and Options from the database.
586
-     */
587
-    public function _delete_db()
588
-    {
589
-        EE_Maintenance_Mode::instance()->set_maintenance_level(EE_Maintenance_Mode::level_0_not_in_maintenance);
590
-        EEH_Activation::delete_all_espresso_cpt_data();
591
-        EEH_Activation::delete_all_espresso_tables_and_data();
592
-        EEH_Activation::remove_cron_tasks();
593
-        EEH_Activation::deactivate_event_espresso();
594
-        wp_safe_redirect(admin_url('plugins.php'));
595
-        exit;
596
-    }
597
-
598
-
599
-
600
-    /**
601
-     * sets up EE4 to rerun the migrations from ee3 to ee4
602
-     */
603
-    public function _rerun_migration_from_ee3()
604
-    {
605
-        EE_Maintenance_Mode::instance()->set_maintenance_level(EE_Maintenance_Mode::level_0_not_in_maintenance);
606
-        EEH_Activation::delete_all_espresso_cpt_data();
607
-        EEH_Activation::delete_all_espresso_tables_and_data(false);
608
-        //set the db state to something that will require migrations
609
-        update_option(EE_Data_Migration_Manager::current_database_state, '3.1.36.0');
610
-        EE_Maintenance_Mode::instance()->set_maintenance_level(EE_Maintenance_Mode::level_2_complete_maintenance);
611
-        $this->_redirect_after_action(true, esc_html__("Database", 'event_espresso'), esc_html__("reset", 'event_espresso'));
612
-    }
613
-
614
-
615
-
616
-    //none of the below group are currently used for Gateway Settings
617
-    protected function _add_screen_options()
618
-    {
619
-    }
620
-
621
-
622
-
623
-    protected function _add_feature_pointers()
624
-    {
625
-    }
626
-
32
+	/**
33
+	 * @var EE_Datetime_Offset_Fix_Form
34
+	 */
35
+	protected $datetime_fix_offset_form;
36
+
37
+
38
+
39
+	protected function _init_page_props()
40
+	{
41
+		$this->page_slug = EE_MAINTENANCE_PG_SLUG;
42
+		$this->page_label = EE_MAINTENANCE_LABEL;
43
+		$this->_admin_base_url = EE_MAINTENANCE_ADMIN_URL;
44
+		$this->_admin_base_path = EE_MAINTENANCE_ADMIN;
45
+	}
46
+
47
+
48
+
49
+	protected function _ajax_hooks()
50
+	{
51
+		add_action('wp_ajax_migration_step', array($this, 'migration_step'));
52
+		add_action('wp_ajax_add_error_to_migrations_ran', array($this, 'add_error_to_migrations_ran'));
53
+	}
54
+
55
+
56
+
57
+	protected function _define_page_props()
58
+	{
59
+		$this->_admin_page_title = EE_MAINTENANCE_LABEL;
60
+		$this->_labels = array(
61
+			'buttons' => array(
62
+				'reset_reservations' => esc_html__('Reset Ticket and Datetime Reserved Counts', 'event_espresso'),
63
+				'reset_capabilities' => esc_html__('Reset Event Espresso Capabilities', 'event_espresso'),
64
+			),
65
+		);
66
+	}
67
+
68
+
69
+
70
+	protected function _set_page_routes()
71
+	{
72
+		$this->_page_routes = array(
73
+			'default'                             => array(
74
+				'func'       => '_maintenance',
75
+				'capability' => 'manage_options',
76
+			),
77
+			'change_maintenance_level'            => array(
78
+				'func'       => '_change_maintenance_level',
79
+				'capability' => 'manage_options',
80
+				'noheader'   => true,
81
+			),
82
+			'system_status'                       => array(
83
+				'func'       => '_system_status',
84
+				'capability' => 'manage_options',
85
+			),
86
+			'download_system_status' => array(
87
+				'func'       => '_download_system_status',
88
+				'capability' => 'manage_options',
89
+				'noheader'   => true,
90
+			),
91
+			'send_migration_crash_report'         => array(
92
+				'func'       => '_send_migration_crash_report',
93
+				'capability' => 'manage_options',
94
+				'noheader'   => true,
95
+			),
96
+			'confirm_migration_crash_report_sent' => array(
97
+				'func'       => '_confirm_migration_crash_report_sent',
98
+				'capability' => 'manage_options',
99
+			),
100
+			'data_reset'                          => array(
101
+				'func'       => '_data_reset_and_delete',
102
+				'capability' => 'manage_options',
103
+			),
104
+			'reset_db'                            => array(
105
+				'func'       => '_reset_db',
106
+				'capability' => 'manage_options',
107
+				'noheader'   => true,
108
+				'args'       => array('nuke_old_ee4_data' => true),
109
+			),
110
+			'start_with_fresh_ee4_db'             => array(
111
+				'func'       => '_reset_db',
112
+				'capability' => 'manage_options',
113
+				'noheader'   => true,
114
+				'args'       => array('nuke_old_ee4_data' => false),
115
+			),
116
+			'delete_db'                           => array(
117
+				'func'       => '_delete_db',
118
+				'capability' => 'manage_options',
119
+				'noheader'   => true,
120
+			),
121
+			'rerun_migration_from_ee3'            => array(
122
+				'func'       => '_rerun_migration_from_ee3',
123
+				'capability' => 'manage_options',
124
+				'noheader'   => true,
125
+			),
126
+			'reset_reservations'                  => array(
127
+				'func'       => '_reset_reservations',
128
+				'capability' => 'manage_options',
129
+				'noheader'   => true,
130
+			),
131
+			'reset_capabilities'                  => array(
132
+				'func'       => '_reset_capabilities',
133
+				'capability' => 'manage_options',
134
+				'noheader'   => true,
135
+			),
136
+			'reattempt_migration'                 => array(
137
+				'func'       => '_reattempt_migration',
138
+				'capability' => 'manage_options',
139
+				'noheader'   => true,
140
+			),
141
+			'datetime_tools' => array(
142
+				'func' => '_datetime_tools',
143
+				'capability' => 'manage_options'
144
+			),
145
+			'run_datetime_offset_fix' => array(
146
+				'func' => '_apply_datetime_offset',
147
+				'noheader' => true,
148
+				'headers_sent_route' => 'datetime_tools',
149
+				'capability' => 'manage_options'
150
+			)
151
+		);
152
+	}
153
+
154
+
155
+
156
+	protected function _set_page_config()
157
+	{
158
+		$this->_page_config = array(
159
+			'default'       => array(
160
+				'nav'           => array(
161
+					'label' => esc_html__('Maintenance', 'event_espresso'),
162
+					'order' => 10,
163
+				),
164
+				'require_nonce' => false,
165
+			),
166
+			'data_reset'    => array(
167
+				'nav'           => array(
168
+					'label' => esc_html__('Reset/Delete Data', 'event_espresso'),
169
+					'order' => 20,
170
+				),
171
+				'require_nonce' => false,
172
+			),
173
+			'datetime_tools' => array(
174
+				'nav' => array(
175
+					'label' => esc_html__('Datetime Utilities', 'event_espresso'),
176
+					'order' => 25
177
+				),
178
+				'require_nonce' => false,
179
+			),
180
+			'system_status' => array(
181
+				'nav'           => array(
182
+					'label' => esc_html__("System Information", "event_espresso"),
183
+					'order' => 30,
184
+				),
185
+				'require_nonce' => false,
186
+			),
187
+		);
188
+	}
189
+
190
+
191
+
192
+	/**
193
+	 * default maintenance page. If we're in maintenance mode level 2, then we need to show
194
+	 * the migration scripts and all that UI.
195
+	 */
196
+	public function _maintenance()
197
+	{
198
+		//it all depends if we're in maintenance model level 1 (frontend-only) or
199
+		//level 2 (everything except maintenance page)
200
+		try {
201
+			//get the current maintenance level and check if
202
+			//we are removed
203
+			$mm = EE_Maintenance_Mode::instance()->level();
204
+			$placed_in_mm = EE_Maintenance_Mode::instance()->set_maintenance_mode_if_db_old();
205
+			if ($mm == EE_Maintenance_Mode::level_2_complete_maintenance && ! $placed_in_mm) {
206
+				//we just took the site out of maintenance mode, so notify the user.
207
+				//unfortunately this message appears to be echoed on the NEXT page load...
208
+				//oh well, we should really be checking for this on addon deactivation anyways
209
+				EE_Error::add_attention(__('Site taken out of maintenance mode because no data migration scripts are required',
210
+					'event_espresso'));
211
+				$this->_process_notices(array('page' => 'espresso_maintenance_settings'), false);
212
+			}
213
+			//in case an exception is thrown while trying to handle migrations
214
+			switch (EE_Maintenance_Mode::instance()->level()) {
215
+				case EE_Maintenance_Mode::level_0_not_in_maintenance:
216
+				case EE_Maintenance_Mode::level_1_frontend_only_maintenance:
217
+					$show_maintenance_switch = true;
218
+					$show_backup_db_text = false;
219
+					$show_migration_progress = false;
220
+					$script_names = array();
221
+					$addons_should_be_upgraded_first = false;
222
+					break;
223
+				case EE_Maintenance_Mode::level_2_complete_maintenance:
224
+					$show_maintenance_switch = false;
225
+					$show_migration_progress = true;
226
+					if (isset($this->_req_data['continue_migration'])) {
227
+						$show_backup_db_text = false;
228
+					} else {
229
+						$show_backup_db_text = true;
230
+					}
231
+					$scripts_needing_to_run = EE_Data_Migration_Manager::instance()
232
+																	   ->check_for_applicable_data_migration_scripts();
233
+					$addons_should_be_upgraded_first = EE_Data_Migration_Manager::instance()->addons_need_updating();
234
+					$script_names = array();
235
+					$current_script = null;
236
+					foreach ($scripts_needing_to_run as $script) {
237
+						if ($script instanceof EE_Data_Migration_Script_Base) {
238
+							if ( ! $current_script) {
239
+								$current_script = $script;
240
+								$current_script->migration_page_hooks();
241
+							}
242
+							$script_names[] = $script->pretty_name();
243
+						}
244
+					}
245
+					break;
246
+			}
247
+			$most_recent_migration = EE_Data_Migration_Manager::instance()->get_last_ran_script(true);
248
+			$exception_thrown = false;
249
+		} catch (EE_Error $e) {
250
+			EE_Data_Migration_Manager::instance()->add_error_to_migrations_ran($e->getMessage());
251
+			//now, just so we can display the page correctly, make a error migration script stage object
252
+			//and also put the error on it. It only persists for the duration of this request
253
+			$most_recent_migration = new EE_DMS_Unknown_1_0_0();
254
+			$most_recent_migration->add_error($e->getMessage());
255
+			$exception_thrown = true;
256
+		}
257
+		$current_db_state = EE_Data_Migration_Manager::instance()->ensure_current_database_state_is_set();
258
+		$current_db_state = str_replace('.decaf', '', $current_db_state);
259
+		if ($exception_thrown
260
+			|| ($most_recent_migration
261
+				&& $most_recent_migration instanceof EE_Data_Migration_Script_Base
262
+				&& $most_recent_migration->is_broken()
263
+			)
264
+		) {
265
+			$this->_template_path = EE_MAINTENANCE_TEMPLATE_PATH . 'ee_migration_was_borked_page.template.php';
266
+			$this->_template_args['support_url'] = 'http://eventespresso.com/support/forums/';
267
+			$this->_template_args['next_url'] = EEH_URL::add_query_args_and_nonce(array('action'  => 'confirm_migration_crash_report_sent',
268
+																						'success' => '0',
269
+			), EE_MAINTENANCE_ADMIN_URL);
270
+		} elseif ($addons_should_be_upgraded_first) {
271
+			$this->_template_path = EE_MAINTENANCE_TEMPLATE_PATH . 'ee_upgrade_addons_before_migrating.template.php';
272
+		} else {
273
+			if ($most_recent_migration
274
+				&& $most_recent_migration instanceof EE_Data_Migration_Script_Base
275
+				&& $most_recent_migration->can_continue()
276
+			) {
277
+				$show_backup_db_text = false;
278
+				$show_continue_current_migration_script = true;
279
+				$show_most_recent_migration = true;
280
+			} elseif (isset($this->_req_data['continue_migration'])) {
281
+				$show_most_recent_migration = true;
282
+				$show_continue_current_migration_script = false;
283
+			} else {
284
+				$show_most_recent_migration = false;
285
+				$show_continue_current_migration_script = false;
286
+			}
287
+			if (isset($current_script)) {
288
+				$migrates_to = $current_script->migrates_to_version();
289
+				$plugin_slug = $migrates_to['slug'];
290
+				$new_version = $migrates_to['version'];
291
+				$this->_template_args = array_merge($this->_template_args, array(
292
+					'current_db_state' => sprintf(__("EE%s (%s)", "event_espresso"),
293
+						isset($current_db_state[$plugin_slug]) ? $current_db_state[$plugin_slug] : 3, $plugin_slug),
294
+					'next_db_state'    => isset($current_script) ? sprintf(__("EE%s (%s)", 'event_espresso'),
295
+						$new_version, $plugin_slug) : null,
296
+				));
297
+			} else {
298
+				$this->_template_args['current_db_state'] = null;
299
+				$this->_template_args['next_db_state'] = null;
300
+			}
301
+			$this->_template_path = EE_MAINTENANCE_TEMPLATE_PATH . 'ee_migration_page.template.php';
302
+			$this->_template_args = array_merge(
303
+				$this->_template_args,
304
+				array(
305
+					'show_most_recent_migration'             => $show_most_recent_migration,
306
+					//flag for showing the most recent migration's status and/or errors
307
+					'show_migration_progress'                => $show_migration_progress,
308
+					//flag for showing the option to run migrations and see their progress
309
+					'show_backup_db_text'                    => $show_backup_db_text,
310
+					//flag for showing text telling the user to backup their DB
311
+					'show_maintenance_switch'                => $show_maintenance_switch,
312
+					//flag for showing the option to change maintenance mode between levels 0 and 1
313
+					'script_names'                           => $script_names,
314
+					//array of names of scripts that have run
315
+					'show_continue_current_migration_script' => $show_continue_current_migration_script,
316
+					//flag to change wording to indicating that we're only CONTINUING a migration script (somehow it got interrupted0
317
+					'reset_db_page_link'                     => EE_Admin_Page::add_query_args_and_nonce(array('action' => 'reset_db'),
318
+						EE_MAINTENANCE_ADMIN_URL),
319
+					'data_reset_page'                        => EE_Admin_Page::add_query_args_and_nonce(array('action' => 'data_reset'),
320
+						EE_MAINTENANCE_ADMIN_URL),
321
+					'update_migration_script_page_link'      => EE_Admin_Page::add_query_args_and_nonce(array('action' => 'change_maintenance_level'),
322
+						EE_MAINTENANCE_ADMIN_URL),
323
+					'ultimate_db_state'                      => sprintf(__("EE%s", 'event_espresso'),
324
+						espresso_version()),
325
+				)
326
+			);
327
+			//make sure we have the form fields helper available. It usually is, but sometimes it isn't
328
+		}
329
+		$this->_template_args['most_recent_migration'] = $most_recent_migration;//the actual most recently ran migration
330
+		//now render the migration options part, and put it in a variable
331
+		$migration_options_template_file = apply_filters(
332
+			'FHEE__ee_migration_page__migration_options_template',
333
+			EE_MAINTENANCE_TEMPLATE_PATH . 'migration_options_from_ee4.template.php'
334
+		);
335
+		$migration_options_html = EEH_Template::display_template($migration_options_template_file, $this->_template_args,true);
336
+		$this->_template_args['migration_options_html'] = $migration_options_html;
337
+		$this->_template_args['admin_page_content'] = EEH_Template::display_template($this->_template_path,
338
+			$this->_template_args, true);
339
+		$this->display_admin_page_with_sidebar();
340
+	}
341
+
342
+
343
+
344
+	/**
345
+	 * returns JSON and executes another step of the currently-executing data migration (called via ajax)
346
+	 */
347
+	public function migration_step()
348
+	{
349
+		$this->_template_args['data'] = EE_Data_Migration_Manager::instance()->response_to_migration_ajax_request();
350
+		$this->_return_json();
351
+	}
352
+
353
+
354
+
355
+	/**
356
+	 * Can be used by js when it notices a response with HTML in it in order
357
+	 * to log the malformed response
358
+	 */
359
+	public function add_error_to_migrations_ran()
360
+	{
361
+		EE_Data_Migration_Manager::instance()->add_error_to_migrations_ran($this->_req_data['message']);
362
+		$this->_template_args['data'] = array('ok' => true);
363
+		$this->_return_json();
364
+	}
365
+
366
+
367
+
368
+	/**
369
+	 * changes the maintenance level, provided there are still no migration scripts that should run
370
+	 */
371
+	public function _change_maintenance_level()
372
+	{
373
+		$new_level = absint($this->_req_data['maintenance_mode_level']);
374
+		if ( ! EE_Data_Migration_Manager::instance()->check_for_applicable_data_migration_scripts()) {
375
+			EE_Maintenance_Mode::instance()->set_maintenance_level($new_level);
376
+			$success = true;
377
+		} else {
378
+			EE_Maintenance_Mode::instance()->set_maintenance_mode_if_db_old();
379
+			$success = false;
380
+		}
381
+		$this->_redirect_after_action($success, 'Maintenance Mode', esc_html__("Updated", "event_espresso"));
382
+	}
383
+
384
+
385
+
386
+	/**
387
+	 * a tab with options for resetting and/or deleting EE data
388
+	 *
389
+	 * @throws \EE_Error
390
+	 * @throws \DomainException
391
+	 */
392
+	public function _data_reset_and_delete()
393
+	{
394
+		$this->_template_path = EE_MAINTENANCE_TEMPLATE_PATH . 'ee_data_reset_and_delete.template.php';
395
+		$this->_template_args['reset_reservations_button'] = $this->get_action_link_or_button(
396
+			'reset_reservations',
397
+			'reset_reservations',
398
+			array(),
399
+			'button button-primary ee-confirm',
400
+			'',
401
+			false
402
+		);
403
+		$this->_template_args['reset_capabilities_button'] = $this->get_action_link_or_button(
404
+			'reset_capabilities',
405
+			'reset_capabilities',
406
+			array(),
407
+			'button button-primary ee-confirm',
408
+			'',
409
+			false
410
+		);
411
+		$this->_template_args['delete_db_url'] = EE_Admin_Page::add_query_args_and_nonce(
412
+			array('action' => 'delete_db'),
413
+			EE_MAINTENANCE_ADMIN_URL
414
+		);
415
+		$this->_template_args['reset_db_url'] = EE_Admin_Page::add_query_args_and_nonce(
416
+			array('action' => 'reset_db'),
417
+			EE_MAINTENANCE_ADMIN_URL
418
+		);
419
+		$this->_template_args['admin_page_content'] = EEH_Template::display_template(
420
+			$this->_template_path,
421
+			$this->_template_args,
422
+			true
423
+		);
424
+		$this->display_admin_page_with_sidebar();
425
+	}
426
+
427
+
428
+
429
+	protected function _reset_reservations()
430
+	{
431
+		if(\EED_Ticket_Sales_Monitor::reset_reservation_counts()) {
432
+			EE_Error::add_success(
433
+				__(
434
+					'Ticket and datetime reserved counts have been successfully reset.',
435
+					'event_espresso'
436
+				)
437
+			);
438
+		} else {
439
+			EE_Error::add_success(
440
+				__(
441
+					'Ticket and datetime reserved counts were correct and did not need resetting.',
442
+					'event_espresso'
443
+				)
444
+			);
445
+		}
446
+		$this->_redirect_after_action(true, '', '', array('action' => 'data_reset'), true);
447
+	}
448
+
449
+
450
+
451
+	protected function _reset_capabilities()
452
+	{
453
+		EE_Registry::instance()->CAP->init_caps(true);
454
+		EE_Error::add_success(__('Default Event Espresso capabilities have been restored for all current roles.',
455
+			'event_espresso'));
456
+		$this->_redirect_after_action(false, '', '', array('action' => 'data_reset'), true);
457
+	}
458
+
459
+
460
+
461
+	/**
462
+	 * resets the DMSs so we can attempt to continue migrating after a fatal error
463
+	 * (only a good idea when someone has somehow tried ot fix whatever caused
464
+	 * the fatal error in teh first place)
465
+	 */
466
+	protected function _reattempt_migration()
467
+	{
468
+		EE_Data_Migration_Manager::instance()->reattempt();
469
+		$this->_redirect_after_action(false, '', '', array('action' => 'default'), true);
470
+	}
471
+
472
+
473
+
474
+	/**
475
+	 * shows the big ol' System Information page
476
+	 */
477
+	public function _system_status()
478
+	{
479
+		$this->_template_path = EE_MAINTENANCE_TEMPLATE_PATH . 'ee_system_stati_page.template.php';
480
+		$this->_template_args['system_stati'] = EEM_System_Status::instance()->get_system_stati();
481
+		$this->_template_args['download_system_status_url'] = EE_Admin_Page::add_query_args_and_nonce(
482
+			array(
483
+				'action' => 'download_system_status',
484
+			),
485
+			EE_MAINTENANCE_ADMIN_URL
486
+		);
487
+		$this->_template_args['admin_page_content'] = EEH_Template::display_template($this->_template_path,
488
+			$this->_template_args, true);
489
+		$this->display_admin_page_with_sidebar();
490
+	}
491
+
492
+	/**
493
+	 * Downloads an HTML file of the system status that can be easily stored or emailed
494
+	 */
495
+	public function _download_system_status()
496
+	{
497
+		$status_info = EEM_System_Status::instance()->get_system_stati();
498
+		header( 'Content-Disposition: attachment' );
499
+		header( "Content-Disposition: attachment; filename=system_status_" . sanitize_key( site_url() ) . ".html" );
500
+		echo "<style>table{border:1px solid darkgrey;}td{vertical-align:top}</style>";
501
+		echo "<h1>System Information for " . site_url() . "</h1>";
502
+		echo EEH_Template::layout_array_as_table( $status_info );
503
+		die;
504
+	}
505
+
506
+
507
+
508
+	public function _send_migration_crash_report()
509
+	{
510
+		$from = $this->_req_data['from'];
511
+		$from_name = $this->_req_data['from_name'];
512
+		$body = $this->_req_data['body'];
513
+		try {
514
+			$success = wp_mail(EE_SUPPORT_EMAIL,
515
+				'Migration Crash Report',
516
+				$body . "/r/n<br>" . print_r(EEM_System_Status::instance()->get_system_stati(), true),
517
+				array(
518
+					"from:$from_name<$from>",
519
+					//					'content-type:text/html charset=UTF-8'
520
+				));
521
+		} catch (Exception $e) {
522
+			$success = false;
523
+		}
524
+		$this->_redirect_after_action($success, esc_html__("Migration Crash Report", "event_espresso"),
525
+			esc_html__("sent", "event_espresso"),
526
+			array('success' => $success, 'action' => 'confirm_migration_crash_report_sent'));
527
+	}
528
+
529
+
530
+
531
+	public function _confirm_migration_crash_report_sent()
532
+	{
533
+		try {
534
+			$most_recent_migration = EE_Data_Migration_Manager::instance()->get_last_ran_script(true);
535
+		} catch (EE_Error $e) {
536
+			EE_Data_Migration_Manager::instance()->add_error_to_migrations_ran($e->getMessage());
537
+			//now, just so we can display the page correctly, make a error migration script stage object
538
+			//and also put the error on it. It only persists for the duration of this request
539
+			$most_recent_migration = new EE_DMS_Unknown_1_0_0();
540
+			$most_recent_migration->add_error($e->getMessage());
541
+		}
542
+		$success = $this->_req_data['success'] == '1' ? true : false;
543
+		$this->_template_args['success'] = $success;
544
+		$this->_template_args['most_recent_migration'] = $most_recent_migration;
545
+		$this->_template_args['reset_db_action_url'] = EE_Admin_Page::add_query_args_and_nonce(array('action' => 'reset_db'),
546
+			EE_MAINTENANCE_ADMIN_URL);
547
+		$this->_template_args['reset_db_page_url'] = EE_Admin_Page::add_query_args_and_nonce(array('action' => 'data_reset'),
548
+			EE_MAINTENANCE_ADMIN_URL);
549
+		$this->_template_args['reattempt_action_url'] = EE_Admin_Page::add_query_args_and_nonce(array('action' => 'reattempt_migration'),
550
+			EE_MAINTENANCE_ADMIN_URL);
551
+		$this->_template_path = EE_MAINTENANCE_TEMPLATE_PATH . 'ee_confirm_migration_crash_report_sent.template.php';
552
+		$this->_template_args['admin_page_content'] = EEH_Template::display_template($this->_template_path,
553
+			$this->_template_args, true);
554
+		$this->display_admin_page_with_sidebar();
555
+	}
556
+
557
+
558
+
559
+	/**
560
+	 * Resets the entire EE4 database.
561
+	 * Currently basically only sets up ee4 database for a fresh install- doesn't
562
+	 * actually clean out the old wp options, or cpts (although does erase old ee table data)
563
+	 *
564
+	 * @param boolean $nuke_old_ee4_data controls whether or not we
565
+	 *                                   destroy the old ee4 data, or just try initializing ee4 default data
566
+	 */
567
+	public function _reset_db($nuke_old_ee4_data = true)
568
+	{
569
+		EE_Maintenance_Mode::instance()->set_maintenance_level(EE_Maintenance_Mode::level_0_not_in_maintenance);
570
+		if ($nuke_old_ee4_data) {
571
+			EEH_Activation::delete_all_espresso_cpt_data();
572
+			EEH_Activation::delete_all_espresso_tables_and_data(false);
573
+			EEH_Activation::remove_cron_tasks();
574
+		}
575
+		//make sure when we reset the registry's config that it
576
+		//switches to using the new singleton
577
+		EE_Registry::instance()->CFG = EE_Registry::instance()->CFG->reset(true);
578
+		EE_System::instance()->initialize_db_if_no_migrations_required(true);
579
+		EE_System::instance()->redirect_to_about_ee();
580
+	}
581
+
582
+
583
+
584
+	/**
585
+	 * Deletes ALL EE tables, Records, and Options from the database.
586
+	 */
587
+	public function _delete_db()
588
+	{
589
+		EE_Maintenance_Mode::instance()->set_maintenance_level(EE_Maintenance_Mode::level_0_not_in_maintenance);
590
+		EEH_Activation::delete_all_espresso_cpt_data();
591
+		EEH_Activation::delete_all_espresso_tables_and_data();
592
+		EEH_Activation::remove_cron_tasks();
593
+		EEH_Activation::deactivate_event_espresso();
594
+		wp_safe_redirect(admin_url('plugins.php'));
595
+		exit;
596
+	}
597
+
598
+
599
+
600
+	/**
601
+	 * sets up EE4 to rerun the migrations from ee3 to ee4
602
+	 */
603
+	public function _rerun_migration_from_ee3()
604
+	{
605
+		EE_Maintenance_Mode::instance()->set_maintenance_level(EE_Maintenance_Mode::level_0_not_in_maintenance);
606
+		EEH_Activation::delete_all_espresso_cpt_data();
607
+		EEH_Activation::delete_all_espresso_tables_and_data(false);
608
+		//set the db state to something that will require migrations
609
+		update_option(EE_Data_Migration_Manager::current_database_state, '3.1.36.0');
610
+		EE_Maintenance_Mode::instance()->set_maintenance_level(EE_Maintenance_Mode::level_2_complete_maintenance);
611
+		$this->_redirect_after_action(true, esc_html__("Database", 'event_espresso'), esc_html__("reset", 'event_espresso'));
612
+	}
613
+
614
+
615
+
616
+	//none of the below group are currently used for Gateway Settings
617
+	protected function _add_screen_options()
618
+	{
619
+	}
620
+
621
+
622
+
623
+	protected function _add_feature_pointers()
624
+	{
625
+	}
626
+
627 627
 
628 628
 
629
-    public function admin_init()
630
-    {
631
-    }
632
-
633
-
634
-
635
-    public function admin_notices()
636
-    {
637
-    }
638
-
629
+	public function admin_init()
630
+	{
631
+	}
632
+
633
+
634
+
635
+	public function admin_notices()
636
+	{
637
+	}
638
+
639 639
 
640 640
 
641
-    public function admin_footer_scripts()
642
-    {
643
-    }
641
+	public function admin_footer_scripts()
642
+	{
643
+	}
644 644
 
645 645
 
646 646
 
647
-    public function load_scripts_styles()
648
-    {
649
-        wp_enqueue_script('ee_admin_js');
647
+	public function load_scripts_styles()
648
+	{
649
+		wp_enqueue_script('ee_admin_js');
650 650
 //		wp_enqueue_media();
651 651
 //		wp_enqueue_script('media-upload');
652
-        wp_enqueue_script('ee-maintenance', EE_MAINTENANCE_ASSETS_URL . 'ee-maintenance.js', array('jquery'),
653
-            EVENT_ESPRESSO_VERSION, true);
654
-        wp_register_style('espresso_maintenance', EE_MAINTENANCE_ASSETS_URL . 'ee-maintenance.css', array(),
655
-            EVENT_ESPRESSO_VERSION);
656
-        wp_enqueue_style('espresso_maintenance');
657
-        //localize script stuff
658
-        wp_localize_script('ee-maintenance', 'ee_maintenance', array(
659
-            'migrating'                        => esc_html__("Updating Database...", "event_espresso"),
660
-            'next'                             => esc_html__("Next", "event_espresso"),
661
-            'fatal_error'                      => esc_html__("A Fatal Error Has Occurred", "event_espresso"),
662
-            'click_next_when_ready'            => esc_html__(
663
-                "The current Database Update has ended. Click 'next' when ready to proceed",
664
-                "event_espresso"
665
-            ),
666
-            'status_no_more_migration_scripts' => EE_Data_Migration_Manager::status_no_more_migration_scripts,
667
-            'status_fatal_error'               => EE_Data_Migration_Manager::status_fatal_error,
668
-            'status_completed'                 => EE_Data_Migration_Manager::status_completed,
669
-            'confirm'                          => esc_html__(
670
-                'Are you sure you want to do this? It CANNOT be undone!',
671
-                'event_espresso'
672
-            ),
673
-            'confirm_skip_migration' => esc_html__(
674
-                'You have chosen to NOT migrate your existing data. Are you sure you want to continue?',
675
-                'event_espresso'
676
-            )
677
-        ));
678
-    }
679
-
680
-
681
-
682
-    public function load_scripts_styles_default()
683
-    {
684
-        //styles
652
+		wp_enqueue_script('ee-maintenance', EE_MAINTENANCE_ASSETS_URL . 'ee-maintenance.js', array('jquery'),
653
+			EVENT_ESPRESSO_VERSION, true);
654
+		wp_register_style('espresso_maintenance', EE_MAINTENANCE_ASSETS_URL . 'ee-maintenance.css', array(),
655
+			EVENT_ESPRESSO_VERSION);
656
+		wp_enqueue_style('espresso_maintenance');
657
+		//localize script stuff
658
+		wp_localize_script('ee-maintenance', 'ee_maintenance', array(
659
+			'migrating'                        => esc_html__("Updating Database...", "event_espresso"),
660
+			'next'                             => esc_html__("Next", "event_espresso"),
661
+			'fatal_error'                      => esc_html__("A Fatal Error Has Occurred", "event_espresso"),
662
+			'click_next_when_ready'            => esc_html__(
663
+				"The current Database Update has ended. Click 'next' when ready to proceed",
664
+				"event_espresso"
665
+			),
666
+			'status_no_more_migration_scripts' => EE_Data_Migration_Manager::status_no_more_migration_scripts,
667
+			'status_fatal_error'               => EE_Data_Migration_Manager::status_fatal_error,
668
+			'status_completed'                 => EE_Data_Migration_Manager::status_completed,
669
+			'confirm'                          => esc_html__(
670
+				'Are you sure you want to do this? It CANNOT be undone!',
671
+				'event_espresso'
672
+			),
673
+			'confirm_skip_migration' => esc_html__(
674
+				'You have chosen to NOT migrate your existing data. Are you sure you want to continue?',
675
+				'event_espresso'
676
+			)
677
+		));
678
+	}
679
+
680
+
681
+
682
+	public function load_scripts_styles_default()
683
+	{
684
+		//styles
685 685
 //		wp_enqueue_style('ee-text-links');
686 686
 //		//scripts
687 687
 //		wp_enqueue_script('ee-text-links');
688
-    }
689
-
690
-
691
-    /**
692
-     * Enqueue scripts and styles for the datetime tools page.
693
-     */
694
-    public function load_scripts_styles_datetime_tools()
695
-    {
696
-        EE_Datepicker_Input::enqueue_styles_and_scripts();
697
-    }
698
-
699
-
700
-    protected function _datetime_tools()
701
-    {
702
-        $form_action = EE_Admin_Page::add_query_args_and_nonce(
703
-            array(
704
-                'action' => 'run_datetime_offset_fix',
705
-                'return_action' => $this->_req_action
706
-            ),
707
-            EE_MAINTENANCE_ADMIN_URL
708
-        );
709
-        $form = $this->_get_datetime_offset_fix_form();
710
-        $this->_admin_page_title = esc_html__('Datetime Utilities', 'event_espresso');
711
-        $this->_template_args['admin_page_content'] = $form->form_open($form_action, 'post')
712
-                                                      . $form->get_html_and_js()
713
-                                                      . $form->form_close();
714
-        $this->display_admin_page_with_no_sidebar();
715
-    }
716
-
717
-
718
-
719
-    protected function _get_datetime_offset_fix_form()
720
-    {
721
-        if (! $this->datetime_fix_offset_form instanceof EE_Form_Section_Proper) {
722
-            $this->datetime_fix_offset_form =  new EE_Form_Section_Proper(
723
-                array(
724
-                    'name' => 'datetime_offset_fix_option',
725
-                    'layout_strategy' => new EE_Admin_Two_Column_Layout(),
726
-                    'subsections' => array(
727
-                        'title' => new EE_Form_Section_HTML(
728
-                            EEH_HTML::h2(
729
-                                esc_html__('Datetime Offset Tool', 'event_espresso')
730
-                            )
731
-                        ),
732
-                        'explanation' => new EE_Form_Section_HTML(
733
-                            EEH_HTML::p(
734
-                                esc_html__(
735
-                                    'Use this tool to automatically apply the provided offset to all Event Espresso records in your database that involve dates and times.',
736
-                                    'event_espresso'
737
-                                )
738
-                            )
739
-                            . EEH_HTML::p(
740
-                                esc_html__(
741
-                                    'Note: If you enter 1.25, that will result in the offset of 1 hour 15 minutes being applied.  Decimals represent the fraction of hours, not minutes.',
742
-                                    'event_espresso'
743
-                                )
744
-                            )
745
-                        ),
746
-                        'offset_input' => new EE_Float_Input(
747
-                            array(
748
-                                'html_name' => 'offset_for_datetimes',
749
-                                'html_label_text' => esc_html__(
750
-                                    'Offset to apply (in hours):',
751
-                                    'event_espresso'
752
-                                ),
753
-                                'min_value' => '-12',
754
-                                'max_value' => '14',
755
-                                'step_value' => '.25',
756
-                                'default' => DatetimeOffsetFix::getOffset()
757
-                            )
758
-                        ),
759
-                        'date_range_explanation' => new EE_Form_Section_HTML(
760
-                            EEH_HTML::p(
761
-                                esc_html__(
762
-                                    'Leave the following fields blank if you want the offset to be applied to all dates. If however, you want to just apply the offset to a specific range of dates you can restrict the offset application using these fields.',
763
-                                    'event_espresso'
764
-                                )
765
-                            )
766
-                            . EEH_HTML::p(
767
-                                EEH_HTML::strong(
768
-                                    sprintf(
769
-                                        esc_html__(
770
-                                            'Note: please enter the dates in UTC (You can use %1$sthis online tool%2$s to assist with conversions).',
771
-                                            'event_espresso'
772
-                                        ),
773
-                                        '<a href="https://www.timeanddate.com/worldclock/converter.html">',
774
-                                        '</a>'
775
-                                    )
776
-                                )
777
-                            )
778
-                        ),
779
-                        'date_range_start_date' => new EE_Datepicker_Input(
780
-                            array(
781
-                                'html_name' => 'offset_date_start_range',
782
-                                'html_label_text' => esc_html__(
783
-                                    'Start Date for dates the offset applied to:',
784
-                                    'event_espresso'
785
-                                )
786
-                            )
787
-                        ),
788
-                        'date_range_end_date' => new EE_Datepicker_Input(
789
-                            array(
790
-                                'html_name' => 'offset_date_end_range',
791
-                                'html_label_text' => esc_html(
792
-                                    'End Date for dates the offset is applied to:',
793
-                                    'event_espresso'
794
-                                )
795
-                            )
796
-                        ),
797
-                        'submit' => new EE_Submit_Input(
798
-                            array(
799
-                                'html_label_text' => '',
800
-                                'default' => esc_html__('Apply Offset', 'event_espresso')
801
-                            )
802
-                        ),
803
-                    )
804
-                )
805
-            );
806
-        }
807
-        return $this->datetime_fix_offset_form;
808
-    }
809
-
810
-
811
-    /**
812
-     * Callback for the run_datetime_offset_fix route.
813
-     * @throws EE_Error
814
-     */
815
-    protected function _apply_datetime_offset()
816
-    {
817
-        if ($_SERVER['REQUEST_METHOD'] === 'POST') {
818
-            $form = $this->_get_datetime_offset_fix_form();
819
-            $form->receive_form_submission($this->_req_data);
820
-            if ($form->is_valid()) {
821
-                //save offset data so batch processor can get it.
822
-                DatetimeOffsetFix::updateOffset($form->get_input_value('offset_input'));
823
-                $utc_timezone = new DateTimeZone('UTC');
824
-                $date_range_start_date = DateTime::createFromFormat(
825
-                    'm/d/Y H:i:s',
826
-                    $form->get_input_value('date_range_start_date') . ' 00:00:00',
827
-                    $utc_timezone
828
-                );
829
-                $date_range_end_date = DateTime::createFromFormat(
830
-                        'm/d/Y H:i:s',
831
-                        $form->get_input_value('date_range_end_date') . ' 23:59:59',
832
-                        $utc_timezone
833
-                );
834
-                if ($date_range_start_date instanceof DateTime) {
835
-                    DatetimeOffsetFix::updateStartDateRange(DbSafeDateTime::createFromDateTime($date_range_start_date));
836
-                }
837
-                if ($date_range_end_date instanceof DateTime) {
838
-                    DatetimeOffsetFix::updateEndDateRange(DbSafeDateTime::createFromDateTime($date_range_end_date));
839
-                }
840
-                //redirect to batch tool
841
-                wp_redirect(
842
-                    EE_Admin_Page::add_query_args_and_nonce(
843
-                        array(
844
-                            'page' => 'espresso_batch',
845
-                            'batch' => 'job',
846
-                            'label' => esc_html__('Applying Offset', 'event_espresso'),
847
-                            'job_handler' => urlencode('EventEspressoBatchRequest\JobHandlers\DatetimeOffsetFix'),
848
-                            'return_url' => urlencode(
849
-                                add_query_arg(
850
-                                    array(
851
-                                        'action' => 'datetime_tools',
852
-                                    ),
853
-                                    EEH_URL::current_url_without_query_paramaters(
854
-                                        array(
855
-                                            'return_action',
856
-                                            'run_datetime_offset_fix_nonce',
857
-                                            'return',
858
-                                            'datetime_tools_nonce'
859
-                                        )
860
-                                    )
861
-                                )
862
-                            )
863
-                        ),
864
-                        admin_url()
865
-                    )
866
-                );
867
-                exit;
868
-            }
869
-        }
870
-    }
688
+	}
689
+
690
+
691
+	/**
692
+	 * Enqueue scripts and styles for the datetime tools page.
693
+	 */
694
+	public function load_scripts_styles_datetime_tools()
695
+	{
696
+		EE_Datepicker_Input::enqueue_styles_and_scripts();
697
+	}
698
+
699
+
700
+	protected function _datetime_tools()
701
+	{
702
+		$form_action = EE_Admin_Page::add_query_args_and_nonce(
703
+			array(
704
+				'action' => 'run_datetime_offset_fix',
705
+				'return_action' => $this->_req_action
706
+			),
707
+			EE_MAINTENANCE_ADMIN_URL
708
+		);
709
+		$form = $this->_get_datetime_offset_fix_form();
710
+		$this->_admin_page_title = esc_html__('Datetime Utilities', 'event_espresso');
711
+		$this->_template_args['admin_page_content'] = $form->form_open($form_action, 'post')
712
+													  . $form->get_html_and_js()
713
+													  . $form->form_close();
714
+		$this->display_admin_page_with_no_sidebar();
715
+	}
716
+
717
+
718
+
719
+	protected function _get_datetime_offset_fix_form()
720
+	{
721
+		if (! $this->datetime_fix_offset_form instanceof EE_Form_Section_Proper) {
722
+			$this->datetime_fix_offset_form =  new EE_Form_Section_Proper(
723
+				array(
724
+					'name' => 'datetime_offset_fix_option',
725
+					'layout_strategy' => new EE_Admin_Two_Column_Layout(),
726
+					'subsections' => array(
727
+						'title' => new EE_Form_Section_HTML(
728
+							EEH_HTML::h2(
729
+								esc_html__('Datetime Offset Tool', 'event_espresso')
730
+							)
731
+						),
732
+						'explanation' => new EE_Form_Section_HTML(
733
+							EEH_HTML::p(
734
+								esc_html__(
735
+									'Use this tool to automatically apply the provided offset to all Event Espresso records in your database that involve dates and times.',
736
+									'event_espresso'
737
+								)
738
+							)
739
+							. EEH_HTML::p(
740
+								esc_html__(
741
+									'Note: If you enter 1.25, that will result in the offset of 1 hour 15 minutes being applied.  Decimals represent the fraction of hours, not minutes.',
742
+									'event_espresso'
743
+								)
744
+							)
745
+						),
746
+						'offset_input' => new EE_Float_Input(
747
+							array(
748
+								'html_name' => 'offset_for_datetimes',
749
+								'html_label_text' => esc_html__(
750
+									'Offset to apply (in hours):',
751
+									'event_espresso'
752
+								),
753
+								'min_value' => '-12',
754
+								'max_value' => '14',
755
+								'step_value' => '.25',
756
+								'default' => DatetimeOffsetFix::getOffset()
757
+							)
758
+						),
759
+						'date_range_explanation' => new EE_Form_Section_HTML(
760
+							EEH_HTML::p(
761
+								esc_html__(
762
+									'Leave the following fields blank if you want the offset to be applied to all dates. If however, you want to just apply the offset to a specific range of dates you can restrict the offset application using these fields.',
763
+									'event_espresso'
764
+								)
765
+							)
766
+							. EEH_HTML::p(
767
+								EEH_HTML::strong(
768
+									sprintf(
769
+										esc_html__(
770
+											'Note: please enter the dates in UTC (You can use %1$sthis online tool%2$s to assist with conversions).',
771
+											'event_espresso'
772
+										),
773
+										'<a href="https://www.timeanddate.com/worldclock/converter.html">',
774
+										'</a>'
775
+									)
776
+								)
777
+							)
778
+						),
779
+						'date_range_start_date' => new EE_Datepicker_Input(
780
+							array(
781
+								'html_name' => 'offset_date_start_range',
782
+								'html_label_text' => esc_html__(
783
+									'Start Date for dates the offset applied to:',
784
+									'event_espresso'
785
+								)
786
+							)
787
+						),
788
+						'date_range_end_date' => new EE_Datepicker_Input(
789
+							array(
790
+								'html_name' => 'offset_date_end_range',
791
+								'html_label_text' => esc_html(
792
+									'End Date for dates the offset is applied to:',
793
+									'event_espresso'
794
+								)
795
+							)
796
+						),
797
+						'submit' => new EE_Submit_Input(
798
+							array(
799
+								'html_label_text' => '',
800
+								'default' => esc_html__('Apply Offset', 'event_espresso')
801
+							)
802
+						),
803
+					)
804
+				)
805
+			);
806
+		}
807
+		return $this->datetime_fix_offset_form;
808
+	}
809
+
810
+
811
+	/**
812
+	 * Callback for the run_datetime_offset_fix route.
813
+	 * @throws EE_Error
814
+	 */
815
+	protected function _apply_datetime_offset()
816
+	{
817
+		if ($_SERVER['REQUEST_METHOD'] === 'POST') {
818
+			$form = $this->_get_datetime_offset_fix_form();
819
+			$form->receive_form_submission($this->_req_data);
820
+			if ($form->is_valid()) {
821
+				//save offset data so batch processor can get it.
822
+				DatetimeOffsetFix::updateOffset($form->get_input_value('offset_input'));
823
+				$utc_timezone = new DateTimeZone('UTC');
824
+				$date_range_start_date = DateTime::createFromFormat(
825
+					'm/d/Y H:i:s',
826
+					$form->get_input_value('date_range_start_date') . ' 00:00:00',
827
+					$utc_timezone
828
+				);
829
+				$date_range_end_date = DateTime::createFromFormat(
830
+						'm/d/Y H:i:s',
831
+						$form->get_input_value('date_range_end_date') . ' 23:59:59',
832
+						$utc_timezone
833
+				);
834
+				if ($date_range_start_date instanceof DateTime) {
835
+					DatetimeOffsetFix::updateStartDateRange(DbSafeDateTime::createFromDateTime($date_range_start_date));
836
+				}
837
+				if ($date_range_end_date instanceof DateTime) {
838
+					DatetimeOffsetFix::updateEndDateRange(DbSafeDateTime::createFromDateTime($date_range_end_date));
839
+				}
840
+				//redirect to batch tool
841
+				wp_redirect(
842
+					EE_Admin_Page::add_query_args_and_nonce(
843
+						array(
844
+							'page' => 'espresso_batch',
845
+							'batch' => 'job',
846
+							'label' => esc_html__('Applying Offset', 'event_espresso'),
847
+							'job_handler' => urlencode('EventEspressoBatchRequest\JobHandlers\DatetimeOffsetFix'),
848
+							'return_url' => urlencode(
849
+								add_query_arg(
850
+									array(
851
+										'action' => 'datetime_tools',
852
+									),
853
+									EEH_URL::current_url_without_query_paramaters(
854
+										array(
855
+											'return_action',
856
+											'run_datetime_offset_fix_nonce',
857
+											'return',
858
+											'datetime_tools_nonce'
859
+										)
860
+									)
861
+								)
862
+							)
863
+						),
864
+						admin_url()
865
+					)
866
+				);
867
+				exit;
868
+			}
869
+		}
870
+	}
871 871
 } //end Maintenance_Admin_Page class
Please login to merge, or discard this patch.
core/admin/EE_Admin.core.php 2 patches
Indentation   +896 added lines, -896 removed lines patch added patch discarded remove patch
@@ -22,454 +22,454 @@  discard block
 block discarded – undo
22 22
 final class EE_Admin implements InterminableInterface
23 23
 {
24 24
 
25
-    /**
26
-     * @var EE_Admin $_instance
27
-     */
28
-    private static $_instance;
29
-
30
-    /**
31
-     * @var PersistentAdminNoticeManager $persistent_admin_notice_manager
32
-     */
33
-    private $persistent_admin_notice_manager;
34
-
35
-    /**
36
-     * @singleton method used to instantiate class object
37
-     * @return EE_Admin
38
-     * @throws EE_Error
39
-     */
40
-    public static function instance()
41
-    {
42
-        // check if class object is instantiated
43
-        if (! self::$_instance instanceof EE_Admin) {
44
-            self::$_instance = new self();
45
-        }
46
-        return self::$_instance;
47
-    }
48
-
49
-
50
-    /**
51
-     * @return EE_Admin
52
-     * @throws EE_Error
53
-     */
54
-    public static function reset()
55
-    {
56
-        self::$_instance = null;
57
-        return self::instance();
58
-    }
59
-
60
-
61
-    /**
62
-     * class constructor
63
-     *
64
-     * @throws EE_Error
65
-     * @throws InvalidDataTypeException
66
-     * @throws InvalidInterfaceException
67
-     * @throws InvalidArgumentException
68
-     */
69
-    protected function __construct()
70
-    {
71
-        // define global EE_Admin constants
72
-        $this->_define_all_constants();
73
-        // set autoloaders for our admin page classes based on included path information
74
-        EEH_Autoloader::instance()->register_autoloaders_for_each_file_in_folder(EE_ADMIN);
75
-        // admin hooks
76
-        add_filter('plugin_action_links', array($this, 'filter_plugin_actions'), 10, 2);
77
-        // load EE_Request_Handler early
78
-        add_action('AHEE__EE_System__core_loaded_and_ready', array($this, 'get_request'));
79
-        add_action('AHEE__EE_System__initialize_last', array($this, 'init'));
80
-        add_action('AHEE__EE_Admin_Page__route_admin_request', array($this, 'route_admin_request'), 100, 2);
81
-        add_action('wp_loaded', array($this, 'wp_loaded'), 100);
82
-        add_action('admin_init', array($this, 'admin_init'), 100);
83
-        add_action('admin_enqueue_scripts', array($this, 'enqueue_admin_scripts'), 20);
84
-        add_action('admin_notices', array($this, 'display_admin_notices'), 10);
85
-        add_action('network_admin_notices', array($this, 'display_admin_notices'), 10);
86
-        add_filter('pre_update_option', array($this, 'check_for_invalid_datetime_formats'), 100, 2);
87
-        add_filter('admin_footer_text', array($this, 'espresso_admin_footer'));
88
-        //reset Environment config (we only do this on admin page loads);
89
-        EE_Registry::instance()->CFG->environment->recheck_values();
90
-        do_action('AHEE__EE_Admin__loaded');
91
-    }
92
-
93
-
94
-
95
-    /**
96
-     * _define_all_constants
97
-     * define constants that are set globally for all admin pages
98
-     *
99
-     * @return void
100
-     */
101
-    private function _define_all_constants()
102
-    {
103
-        if (! defined('EE_ADMIN_URL')) {
104
-            define('EE_ADMIN_URL', EE_PLUGIN_DIR_URL . 'core/admin/');
105
-            define('EE_ADMIN_PAGES_URL', EE_PLUGIN_DIR_URL . 'admin_pages/');
106
-            define('EE_ADMIN_TEMPLATE', EE_ADMIN . 'templates' . DS);
107
-            define('WP_ADMIN_PATH', ABSPATH . 'wp-admin/');
108
-            define('WP_AJAX_URL', admin_url('admin-ajax.php'));
109
-        }
110
-    }
111
-
112
-
113
-    /**
114
-     * filter_plugin_actions - adds links to the Plugins page listing
115
-     *
116
-     * @param    array  $links
117
-     * @param    string $plugin
118
-     * @return    array
119
-     */
120
-    public function filter_plugin_actions($links, $plugin)
121
-    {
122
-        // set $main_file in stone
123
-        static $main_file;
124
-        // if $main_file is not set yet
125
-        if (! $main_file) {
126
-            $main_file = plugin_basename(EVENT_ESPRESSO_MAIN_FILE);
127
-        }
128
-        if ($plugin === $main_file) {
129
-            // compare current plugin to this one
130
-            if (EE_Maintenance_Mode::instance()->level() === EE_Maintenance_Mode::level_2_complete_maintenance) {
131
-                $maintenance_link = '<a href="admin.php?page=espresso_maintenance_settings"'
132
-                                    . ' title="Event Espresso is in maintenance mode.  Click this link to learn why.">'
133
-                                    . esc_html__('Maintenance Mode Active', 'event_espresso')
134
-                                    . '</a>';
135
-                array_unshift($links, $maintenance_link);
136
-            } else {
137
-                $org_settings_link = '<a href="admin.php?page=espresso_general_settings">'
138
-                                     . esc_html__('Settings', 'event_espresso')
139
-                                     . '</a>';
140
-                $events_link       = '<a href="admin.php?page=espresso_events">'
141
-                                     . esc_html__('Events', 'event_espresso')
142
-                                     . '</a>';
143
-                // add before other links
144
-                array_unshift($links, $org_settings_link, $events_link);
145
-            }
146
-        }
147
-        return $links;
148
-    }
149
-
150
-
151
-    /**
152
-     * _get_request
153
-     *
154
-     * @return void
155
-     * @throws EE_Error
156
-     * @throws InvalidArgumentException
157
-     * @throws InvalidDataTypeException
158
-     * @throws InvalidInterfaceException
159
-     * @throws ReflectionException
160
-     */
161
-    public function get_request()
162
-    {
163
-        EE_Registry::instance()->load_core('Request_Handler');
164
-        EE_Registry::instance()->load_core('CPT_Strategy');
165
-    }
166
-
167
-
168
-
169
-    /**
170
-     * hide_admin_pages_except_maintenance_mode
171
-     *
172
-     * @param array $admin_page_folder_names
173
-     * @return array
174
-     */
175
-    public function hide_admin_pages_except_maintenance_mode($admin_page_folder_names = array())
176
-    {
177
-        return array(
178
-            'maintenance' => EE_ADMIN_PAGES . 'maintenance' . DS,
179
-            'about'       => EE_ADMIN_PAGES . 'about' . DS,
180
-            'support'     => EE_ADMIN_PAGES . 'support' . DS,
181
-        );
182
-    }
183
-
184
-
185
-
186
-    /**
187
-     * init- should fire after shortcode, module,  addon, other plugin (default priority), and even
188
-     * EE_Front_Controller's init phases have run
189
-     *
190
-     * @return void
191
-     * @throws EE_Error
192
-     * @throws InvalidArgumentException
193
-     * @throws InvalidDataTypeException
194
-     * @throws InvalidInterfaceException
195
-     * @throws ReflectionException
196
-     * @throws ServiceNotFoundException
197
-     */
198
-    public function init()
199
-    {
200
-        //only enable most of the EE_Admin IF we're not in full maintenance mode
201
-        if (EE_Maintenance_Mode::instance()->models_can_query()) {
202
-            //ok so we want to enable the entire admin
203
-            $this->persistent_admin_notice_manager = LoaderFactory::getLoader()->getShared(
204
-                'EventEspresso\core\services\notifications\PersistentAdminNoticeManager',
205
-                array(
206
-                    EE_Admin_Page::add_query_args_and_nonce(
207
-                        array(
208
-                            'page'   => EE_Registry::instance()->REQ->get('page', ''),
209
-                            'action' => EE_Registry::instance()->REQ->get('action', ''),
210
-                        ),
211
-                        EE_ADMIN_URL
212
-                    ),
213
-                )
214
-            );
215
-            $this->maybeSetDatetimeWarningNotice();
216
-            //at a glance dashboard widget
217
-            add_filter('dashboard_glance_items', array($this, 'dashboard_glance_items'), 10);
218
-            //filter for get_edit_post_link used on comments for custom post types
219
-            add_filter('get_edit_post_link', array($this, 'modify_edit_post_link'), 10, 2);
220
-        }
221
-        // run the admin page factory but ONLY if we are doing an ee admin ajax request
222
-        if (! defined('DOING_AJAX') || EE_ADMIN_AJAX) {
223
-            try {
224
-                //this loads the controller for the admin pages which will setup routing etc
225
-                EE_Registry::instance()->load_core('Admin_Page_Loader');
226
-            } catch (EE_Error $e) {
227
-                $e->get_error();
228
-            }
229
-        }
230
-        add_filter('content_save_pre', array($this, 'its_eSpresso'), 10, 1);
231
-        //make sure our CPTs and custom taxonomy metaboxes get shown for first time users
232
-        add_action('admin_head', array($this, 'enable_hidden_ee_nav_menu_metaboxes'), 10);
233
-        add_action('admin_head', array($this, 'register_custom_nav_menu_boxes'), 10);
234
-        //exclude EE critical pages from all nav menus and wp_list_pages
235
-        add_filter('nav_menu_meta_box_object', array($this, 'remove_pages_from_nav_menu'), 10);
236
-    }
237
-
238
-
239
-    /**
240
-     *    get_persistent_admin_notices
241
-     *
242
-     * @access    public
243
-     * @return void
244
-     * @throws EE_Error
245
-     * @throws InvalidArgumentException
246
-     * @throws InvalidDataTypeException
247
-     * @throws InvalidInterfaceException
248
-     */
249
-    public function maybeSetDatetimeWarningNotice()
250
-    {
251
-        //add dismissable notice for datetime changes.  Only valid if site does not have a timezone_string set.
252
-        //@todo This needs to stay in core for a bit to catch anyone upgrading from a version without this to a version
253
-        //with this.  But after enough time (indeterminate at this point) we can just remove this notice.
254
-        //this was added with https://events.codebasehq.com/projects/event-espresso/tickets/10626
255
-        if (! get_option('timezone_string') && EEM_Event::instance()->count() > 0) {
256
-            new PersistentAdminNotice(
257
-                'datetime_fix_notice',
258
-                sprintf(
259
-                    esc_html__(
260
-                        '%1$sImportant announcement related to your install of Event Espresso%2$s: There are some changes made to your site that could affect how dates display for your events and other related items with dates and times.  Read more about it %3$shere%4$s. If your dates and times are displaying incorrectly (incorrect offset), you can fix it using the tool on %5$sthis page%4$s.',
261
-                        'event_espresso'
262
-                    ),
263
-                    '<strong>',
264
-                    '</strong>',
265
-                    '<a href="https://eventespresso.com/2017/08/important-upcoming-changes-dates-times">',
266
-                    '</a>',
267
-                    '<a href="' . EE_Admin_Page::add_query_args_and_nonce(
268
-                        array(
269
-                            'page' => 'espresso_maintenance_settings',
270
-                            'action' => 'datetime_tools'
271
-                        ),
272
-                        admin_url('admin.php')
273
-                    ) . '">'
274
-                ),
275
-                false,
276
-                'manage_options',
277
-                'datetime_fix_persistent_notice'
278
-            );
279
-        }
280
-    }
281
-
282
-
283
-
284
-    /**
285
-     * this simply hooks into the nav menu setup of pages metabox and makes sure that we remove EE critical pages from
286
-     * the list of options. the wp function "wp_nav_menu_item_post_type_meta_box" found in
287
-     * wp-admin/includes/nav-menu.php looks for the "_default_query" property on the post_type object and it uses that
288
-     * to override any queries found in the existing query for the given post type.  Note that _default_query is not a
289
-     * normal property on the post_type object.  It's found ONLY in this particular context.
290
-     *
291
-     * @param WP_Post $post_type WP post type object
292
-     * @return WP_Post
293
-     * @throws InvalidArgumentException
294
-     * @throws InvalidDataTypeException
295
-     * @throws InvalidInterfaceException
296
-     */
297
-    public function remove_pages_from_nav_menu($post_type)
298
-    {
299
-        //if this isn't the "pages" post type let's get out
300
-        if ($post_type->name !== 'page') {
301
-            return $post_type;
302
-        }
303
-        $critical_pages = EE_Registry::instance()->CFG->core->get_critical_pages_array();
304
-        $post_type->_default_query = array(
305
-            'post__not_in' => $critical_pages,
306
-        );
307
-        return $post_type;
308
-    }
309
-
310
-
311
-
312
-    /**
313
-     * WP by default only shows three metaboxes in "nav-menus.php" for first times users.  We want to make sure our
314
-     * metaboxes get shown as well
315
-     *
316
-     * @return void
317
-     */
318
-    public function enable_hidden_ee_nav_menu_metaboxes()
319
-    {
320
-        global $wp_meta_boxes, $pagenow;
321
-        if (! is_array($wp_meta_boxes) || $pagenow !== 'nav-menus.php') {
322
-            return;
323
-        }
324
-        $user = wp_get_current_user();
325
-        //has this been done yet?
326
-        if (get_user_option('ee_nav_menu_initialized', $user->ID)) {
327
-            return;
328
-        }
329
-
330
-        $hidden_meta_boxes  = get_user_option('metaboxhidden_nav-menus', $user->ID);
331
-        $initial_meta_boxes = apply_filters(
332
-            'FHEE__EE_Admin__enable_hidden_ee_nav_menu_boxes__initial_meta_boxes',
333
-            array(
334
-                'nav-menu-theme-locations',
335
-                'add-page',
336
-                'add-custom-links',
337
-                'add-category',
338
-                'add-espresso_events',
339
-                'add-espresso_venues',
340
-                'add-espresso_event_categories',
341
-                'add-espresso_venue_categories',
342
-                'add-post-type-post',
343
-                'add-post-type-page',
344
-            )
345
-        );
346
-
347
-        if (is_array($hidden_meta_boxes)) {
348
-            foreach ($hidden_meta_boxes as $key => $meta_box_id) {
349
-                if (in_array($meta_box_id, $initial_meta_boxes, true)) {
350
-                    unset($hidden_meta_boxes[$key]);
351
-                }
352
-            }
353
-        }
354
-        update_user_option($user->ID, 'metaboxhidden_nav-menus', $hidden_meta_boxes, true);
355
-        update_user_option($user->ID, 'ee_nav_menu_initialized', 1, true);
356
-    }
357
-
358
-
359
-
360
-    /**
361
-     * This method simply registers custom nav menu boxes for "nav_menus.php route"
362
-     * Currently EE is using this to make sure there are menu options for our CPT archive page routes.
363
-     *
364
-     * @todo   modify this so its more dynamic and automatic for all ee CPTs and setups and can also be hooked into by
365
-     *         addons etc.
366
-     * @return void
367
-     */
368
-    public function register_custom_nav_menu_boxes()
369
-    {
370
-        add_meta_box(
371
-            'add-extra-nav-menu-pages',
372
-            esc_html__('Event Espresso Pages', 'event_espresso'),
373
-            array($this, 'ee_cpt_archive_pages'),
374
-            'nav-menus',
375
-            'side',
376
-            'core'
377
-        );
378
-    }
379
-
380
-
381
-
382
-    /**
383
-     * Use this to edit the post link for our cpts so that the edit link points to the correct page.
384
-     *
385
-     * @since   4.3.0
386
-     * @param string $link the original link generated by wp
387
-     * @param int    $id   post id
388
-     * @return string  the (maybe) modified link
389
-     */
390
-    public function modify_edit_post_link($link, $id)
391
-    {
392
-        if (! $post = get_post($id)) {
393
-            return $link;
394
-        }
395
-        if ($post->post_type === 'espresso_attendees') {
396
-            $query_args = array(
397
-                'action' => 'edit_attendee',
398
-                'post'   => $id,
399
-            );
400
-            return EEH_URL::add_query_args_and_nonce(
401
-                $query_args,
402
-                admin_url('admin.php?page=espresso_registrations')
403
-            );
404
-        }
405
-        return $link;
406
-    }
407
-
408
-
409
-
410
-    public function ee_cpt_archive_pages()
411
-    {
412
-        global $nav_menu_selected_id;
413
-        $db_fields   = false;
414
-        $walker      = new Walker_Nav_Menu_Checklist($db_fields);
415
-        $current_tab = 'event-archives';
416
-        $removed_args = array(
417
-            'action',
418
-            'customlink-tab',
419
-            'edit-menu-item',
420
-            'menu-item',
421
-            'page-tab',
422
-            '_wpnonce',
423
-        );
424
-        ?>
25
+	/**
26
+	 * @var EE_Admin $_instance
27
+	 */
28
+	private static $_instance;
29
+
30
+	/**
31
+	 * @var PersistentAdminNoticeManager $persistent_admin_notice_manager
32
+	 */
33
+	private $persistent_admin_notice_manager;
34
+
35
+	/**
36
+	 * @singleton method used to instantiate class object
37
+	 * @return EE_Admin
38
+	 * @throws EE_Error
39
+	 */
40
+	public static function instance()
41
+	{
42
+		// check if class object is instantiated
43
+		if (! self::$_instance instanceof EE_Admin) {
44
+			self::$_instance = new self();
45
+		}
46
+		return self::$_instance;
47
+	}
48
+
49
+
50
+	/**
51
+	 * @return EE_Admin
52
+	 * @throws EE_Error
53
+	 */
54
+	public static function reset()
55
+	{
56
+		self::$_instance = null;
57
+		return self::instance();
58
+	}
59
+
60
+
61
+	/**
62
+	 * class constructor
63
+	 *
64
+	 * @throws EE_Error
65
+	 * @throws InvalidDataTypeException
66
+	 * @throws InvalidInterfaceException
67
+	 * @throws InvalidArgumentException
68
+	 */
69
+	protected function __construct()
70
+	{
71
+		// define global EE_Admin constants
72
+		$this->_define_all_constants();
73
+		// set autoloaders for our admin page classes based on included path information
74
+		EEH_Autoloader::instance()->register_autoloaders_for_each_file_in_folder(EE_ADMIN);
75
+		// admin hooks
76
+		add_filter('plugin_action_links', array($this, 'filter_plugin_actions'), 10, 2);
77
+		// load EE_Request_Handler early
78
+		add_action('AHEE__EE_System__core_loaded_and_ready', array($this, 'get_request'));
79
+		add_action('AHEE__EE_System__initialize_last', array($this, 'init'));
80
+		add_action('AHEE__EE_Admin_Page__route_admin_request', array($this, 'route_admin_request'), 100, 2);
81
+		add_action('wp_loaded', array($this, 'wp_loaded'), 100);
82
+		add_action('admin_init', array($this, 'admin_init'), 100);
83
+		add_action('admin_enqueue_scripts', array($this, 'enqueue_admin_scripts'), 20);
84
+		add_action('admin_notices', array($this, 'display_admin_notices'), 10);
85
+		add_action('network_admin_notices', array($this, 'display_admin_notices'), 10);
86
+		add_filter('pre_update_option', array($this, 'check_for_invalid_datetime_formats'), 100, 2);
87
+		add_filter('admin_footer_text', array($this, 'espresso_admin_footer'));
88
+		//reset Environment config (we only do this on admin page loads);
89
+		EE_Registry::instance()->CFG->environment->recheck_values();
90
+		do_action('AHEE__EE_Admin__loaded');
91
+	}
92
+
93
+
94
+
95
+	/**
96
+	 * _define_all_constants
97
+	 * define constants that are set globally for all admin pages
98
+	 *
99
+	 * @return void
100
+	 */
101
+	private function _define_all_constants()
102
+	{
103
+		if (! defined('EE_ADMIN_URL')) {
104
+			define('EE_ADMIN_URL', EE_PLUGIN_DIR_URL . 'core/admin/');
105
+			define('EE_ADMIN_PAGES_URL', EE_PLUGIN_DIR_URL . 'admin_pages/');
106
+			define('EE_ADMIN_TEMPLATE', EE_ADMIN . 'templates' . DS);
107
+			define('WP_ADMIN_PATH', ABSPATH . 'wp-admin/');
108
+			define('WP_AJAX_URL', admin_url('admin-ajax.php'));
109
+		}
110
+	}
111
+
112
+
113
+	/**
114
+	 * filter_plugin_actions - adds links to the Plugins page listing
115
+	 *
116
+	 * @param    array  $links
117
+	 * @param    string $plugin
118
+	 * @return    array
119
+	 */
120
+	public function filter_plugin_actions($links, $plugin)
121
+	{
122
+		// set $main_file in stone
123
+		static $main_file;
124
+		// if $main_file is not set yet
125
+		if (! $main_file) {
126
+			$main_file = plugin_basename(EVENT_ESPRESSO_MAIN_FILE);
127
+		}
128
+		if ($plugin === $main_file) {
129
+			// compare current plugin to this one
130
+			if (EE_Maintenance_Mode::instance()->level() === EE_Maintenance_Mode::level_2_complete_maintenance) {
131
+				$maintenance_link = '<a href="admin.php?page=espresso_maintenance_settings"'
132
+									. ' title="Event Espresso is in maintenance mode.  Click this link to learn why.">'
133
+									. esc_html__('Maintenance Mode Active', 'event_espresso')
134
+									. '</a>';
135
+				array_unshift($links, $maintenance_link);
136
+			} else {
137
+				$org_settings_link = '<a href="admin.php?page=espresso_general_settings">'
138
+									 . esc_html__('Settings', 'event_espresso')
139
+									 . '</a>';
140
+				$events_link       = '<a href="admin.php?page=espresso_events">'
141
+									 . esc_html__('Events', 'event_espresso')
142
+									 . '</a>';
143
+				// add before other links
144
+				array_unshift($links, $org_settings_link, $events_link);
145
+			}
146
+		}
147
+		return $links;
148
+	}
149
+
150
+
151
+	/**
152
+	 * _get_request
153
+	 *
154
+	 * @return void
155
+	 * @throws EE_Error
156
+	 * @throws InvalidArgumentException
157
+	 * @throws InvalidDataTypeException
158
+	 * @throws InvalidInterfaceException
159
+	 * @throws ReflectionException
160
+	 */
161
+	public function get_request()
162
+	{
163
+		EE_Registry::instance()->load_core('Request_Handler');
164
+		EE_Registry::instance()->load_core('CPT_Strategy');
165
+	}
166
+
167
+
168
+
169
+	/**
170
+	 * hide_admin_pages_except_maintenance_mode
171
+	 *
172
+	 * @param array $admin_page_folder_names
173
+	 * @return array
174
+	 */
175
+	public function hide_admin_pages_except_maintenance_mode($admin_page_folder_names = array())
176
+	{
177
+		return array(
178
+			'maintenance' => EE_ADMIN_PAGES . 'maintenance' . DS,
179
+			'about'       => EE_ADMIN_PAGES . 'about' . DS,
180
+			'support'     => EE_ADMIN_PAGES . 'support' . DS,
181
+		);
182
+	}
183
+
184
+
185
+
186
+	/**
187
+	 * init- should fire after shortcode, module,  addon, other plugin (default priority), and even
188
+	 * EE_Front_Controller's init phases have run
189
+	 *
190
+	 * @return void
191
+	 * @throws EE_Error
192
+	 * @throws InvalidArgumentException
193
+	 * @throws InvalidDataTypeException
194
+	 * @throws InvalidInterfaceException
195
+	 * @throws ReflectionException
196
+	 * @throws ServiceNotFoundException
197
+	 */
198
+	public function init()
199
+	{
200
+		//only enable most of the EE_Admin IF we're not in full maintenance mode
201
+		if (EE_Maintenance_Mode::instance()->models_can_query()) {
202
+			//ok so we want to enable the entire admin
203
+			$this->persistent_admin_notice_manager = LoaderFactory::getLoader()->getShared(
204
+				'EventEspresso\core\services\notifications\PersistentAdminNoticeManager',
205
+				array(
206
+					EE_Admin_Page::add_query_args_and_nonce(
207
+						array(
208
+							'page'   => EE_Registry::instance()->REQ->get('page', ''),
209
+							'action' => EE_Registry::instance()->REQ->get('action', ''),
210
+						),
211
+						EE_ADMIN_URL
212
+					),
213
+				)
214
+			);
215
+			$this->maybeSetDatetimeWarningNotice();
216
+			//at a glance dashboard widget
217
+			add_filter('dashboard_glance_items', array($this, 'dashboard_glance_items'), 10);
218
+			//filter for get_edit_post_link used on comments for custom post types
219
+			add_filter('get_edit_post_link', array($this, 'modify_edit_post_link'), 10, 2);
220
+		}
221
+		// run the admin page factory but ONLY if we are doing an ee admin ajax request
222
+		if (! defined('DOING_AJAX') || EE_ADMIN_AJAX) {
223
+			try {
224
+				//this loads the controller for the admin pages which will setup routing etc
225
+				EE_Registry::instance()->load_core('Admin_Page_Loader');
226
+			} catch (EE_Error $e) {
227
+				$e->get_error();
228
+			}
229
+		}
230
+		add_filter('content_save_pre', array($this, 'its_eSpresso'), 10, 1);
231
+		//make sure our CPTs and custom taxonomy metaboxes get shown for first time users
232
+		add_action('admin_head', array($this, 'enable_hidden_ee_nav_menu_metaboxes'), 10);
233
+		add_action('admin_head', array($this, 'register_custom_nav_menu_boxes'), 10);
234
+		//exclude EE critical pages from all nav menus and wp_list_pages
235
+		add_filter('nav_menu_meta_box_object', array($this, 'remove_pages_from_nav_menu'), 10);
236
+	}
237
+
238
+
239
+	/**
240
+	 *    get_persistent_admin_notices
241
+	 *
242
+	 * @access    public
243
+	 * @return void
244
+	 * @throws EE_Error
245
+	 * @throws InvalidArgumentException
246
+	 * @throws InvalidDataTypeException
247
+	 * @throws InvalidInterfaceException
248
+	 */
249
+	public function maybeSetDatetimeWarningNotice()
250
+	{
251
+		//add dismissable notice for datetime changes.  Only valid if site does not have a timezone_string set.
252
+		//@todo This needs to stay in core for a bit to catch anyone upgrading from a version without this to a version
253
+		//with this.  But after enough time (indeterminate at this point) we can just remove this notice.
254
+		//this was added with https://events.codebasehq.com/projects/event-espresso/tickets/10626
255
+		if (! get_option('timezone_string') && EEM_Event::instance()->count() > 0) {
256
+			new PersistentAdminNotice(
257
+				'datetime_fix_notice',
258
+				sprintf(
259
+					esc_html__(
260
+						'%1$sImportant announcement related to your install of Event Espresso%2$s: There are some changes made to your site that could affect how dates display for your events and other related items with dates and times.  Read more about it %3$shere%4$s. If your dates and times are displaying incorrectly (incorrect offset), you can fix it using the tool on %5$sthis page%4$s.',
261
+						'event_espresso'
262
+					),
263
+					'<strong>',
264
+					'</strong>',
265
+					'<a href="https://eventespresso.com/2017/08/important-upcoming-changes-dates-times">',
266
+					'</a>',
267
+					'<a href="' . EE_Admin_Page::add_query_args_and_nonce(
268
+						array(
269
+							'page' => 'espresso_maintenance_settings',
270
+							'action' => 'datetime_tools'
271
+						),
272
+						admin_url('admin.php')
273
+					) . '">'
274
+				),
275
+				false,
276
+				'manage_options',
277
+				'datetime_fix_persistent_notice'
278
+			);
279
+		}
280
+	}
281
+
282
+
283
+
284
+	/**
285
+	 * this simply hooks into the nav menu setup of pages metabox and makes sure that we remove EE critical pages from
286
+	 * the list of options. the wp function "wp_nav_menu_item_post_type_meta_box" found in
287
+	 * wp-admin/includes/nav-menu.php looks for the "_default_query" property on the post_type object and it uses that
288
+	 * to override any queries found in the existing query for the given post type.  Note that _default_query is not a
289
+	 * normal property on the post_type object.  It's found ONLY in this particular context.
290
+	 *
291
+	 * @param WP_Post $post_type WP post type object
292
+	 * @return WP_Post
293
+	 * @throws InvalidArgumentException
294
+	 * @throws InvalidDataTypeException
295
+	 * @throws InvalidInterfaceException
296
+	 */
297
+	public function remove_pages_from_nav_menu($post_type)
298
+	{
299
+		//if this isn't the "pages" post type let's get out
300
+		if ($post_type->name !== 'page') {
301
+			return $post_type;
302
+		}
303
+		$critical_pages = EE_Registry::instance()->CFG->core->get_critical_pages_array();
304
+		$post_type->_default_query = array(
305
+			'post__not_in' => $critical_pages,
306
+		);
307
+		return $post_type;
308
+	}
309
+
310
+
311
+
312
+	/**
313
+	 * WP by default only shows three metaboxes in "nav-menus.php" for first times users.  We want to make sure our
314
+	 * metaboxes get shown as well
315
+	 *
316
+	 * @return void
317
+	 */
318
+	public function enable_hidden_ee_nav_menu_metaboxes()
319
+	{
320
+		global $wp_meta_boxes, $pagenow;
321
+		if (! is_array($wp_meta_boxes) || $pagenow !== 'nav-menus.php') {
322
+			return;
323
+		}
324
+		$user = wp_get_current_user();
325
+		//has this been done yet?
326
+		if (get_user_option('ee_nav_menu_initialized', $user->ID)) {
327
+			return;
328
+		}
329
+
330
+		$hidden_meta_boxes  = get_user_option('metaboxhidden_nav-menus', $user->ID);
331
+		$initial_meta_boxes = apply_filters(
332
+			'FHEE__EE_Admin__enable_hidden_ee_nav_menu_boxes__initial_meta_boxes',
333
+			array(
334
+				'nav-menu-theme-locations',
335
+				'add-page',
336
+				'add-custom-links',
337
+				'add-category',
338
+				'add-espresso_events',
339
+				'add-espresso_venues',
340
+				'add-espresso_event_categories',
341
+				'add-espresso_venue_categories',
342
+				'add-post-type-post',
343
+				'add-post-type-page',
344
+			)
345
+		);
346
+
347
+		if (is_array($hidden_meta_boxes)) {
348
+			foreach ($hidden_meta_boxes as $key => $meta_box_id) {
349
+				if (in_array($meta_box_id, $initial_meta_boxes, true)) {
350
+					unset($hidden_meta_boxes[$key]);
351
+				}
352
+			}
353
+		}
354
+		update_user_option($user->ID, 'metaboxhidden_nav-menus', $hidden_meta_boxes, true);
355
+		update_user_option($user->ID, 'ee_nav_menu_initialized', 1, true);
356
+	}
357
+
358
+
359
+
360
+	/**
361
+	 * This method simply registers custom nav menu boxes for "nav_menus.php route"
362
+	 * Currently EE is using this to make sure there are menu options for our CPT archive page routes.
363
+	 *
364
+	 * @todo   modify this so its more dynamic and automatic for all ee CPTs and setups and can also be hooked into by
365
+	 *         addons etc.
366
+	 * @return void
367
+	 */
368
+	public function register_custom_nav_menu_boxes()
369
+	{
370
+		add_meta_box(
371
+			'add-extra-nav-menu-pages',
372
+			esc_html__('Event Espresso Pages', 'event_espresso'),
373
+			array($this, 'ee_cpt_archive_pages'),
374
+			'nav-menus',
375
+			'side',
376
+			'core'
377
+		);
378
+	}
379
+
380
+
381
+
382
+	/**
383
+	 * Use this to edit the post link for our cpts so that the edit link points to the correct page.
384
+	 *
385
+	 * @since   4.3.0
386
+	 * @param string $link the original link generated by wp
387
+	 * @param int    $id   post id
388
+	 * @return string  the (maybe) modified link
389
+	 */
390
+	public function modify_edit_post_link($link, $id)
391
+	{
392
+		if (! $post = get_post($id)) {
393
+			return $link;
394
+		}
395
+		if ($post->post_type === 'espresso_attendees') {
396
+			$query_args = array(
397
+				'action' => 'edit_attendee',
398
+				'post'   => $id,
399
+			);
400
+			return EEH_URL::add_query_args_and_nonce(
401
+				$query_args,
402
+				admin_url('admin.php?page=espresso_registrations')
403
+			);
404
+		}
405
+		return $link;
406
+	}
407
+
408
+
409
+
410
+	public function ee_cpt_archive_pages()
411
+	{
412
+		global $nav_menu_selected_id;
413
+		$db_fields   = false;
414
+		$walker      = new Walker_Nav_Menu_Checklist($db_fields);
415
+		$current_tab = 'event-archives';
416
+		$removed_args = array(
417
+			'action',
418
+			'customlink-tab',
419
+			'edit-menu-item',
420
+			'menu-item',
421
+			'page-tab',
422
+			'_wpnonce',
423
+		);
424
+		?>
425 425
         <div id="posttype-extra-nav-menu-pages" class="posttypediv">
426 426
             <ul id="posttype-extra-nav-menu-pages-tabs" class="posttype-tabs add-menu-item-tabs">
427 427
                 <li <?php echo('event-archives' === $current_tab ? ' class="tabs"' : ''); ?>>
428 428
                     <a class="nav-tab-link" data-type="tabs-panel-posttype-extra-nav-menu-pages-event-archives"
429 429
                        href="<?php if ($nav_menu_selected_id) {
430
-                            echo esc_url(
431
-                                add_query_arg(
432
-                                    'extra-nav-menu-pages-tab',
433
-                                    'event-archives',
434
-                                    remove_query_arg($removed_args)
435
-                                )
436
-                            );
437
-                       } ?>#tabs-panel-posttype-extra-nav-menu-pages-event-archives">
430
+							echo esc_url(
431
+								add_query_arg(
432
+									'extra-nav-menu-pages-tab',
433
+									'event-archives',
434
+									remove_query_arg($removed_args)
435
+								)
436
+							);
437
+					   } ?>#tabs-panel-posttype-extra-nav-menu-pages-event-archives">
438 438
                         <?php _e('Event Archive Pages', 'event_espresso'); ?>
439 439
                     </a>
440 440
                 </li>
441 441
             </ul><!-- .posttype-tabs -->
442 442
 
443 443
             <div id="tabs-panel-posttype-extra-nav-menu-pages-event-archives" class="tabs-panel <?php
444
-                echo('event-archives' === $current_tab ? 'tabs-panel-active' : 'tabs-panel-inactive');
445
-                ?>">
444
+				echo('event-archives' === $current_tab ? 'tabs-panel-active' : 'tabs-panel-inactive');
445
+				?>">
446 446
                     <ul id="extra-nav-menu-pageschecklist-event-archives" class="categorychecklist form-no-clear">
447 447
                         <?php
448
-                        $pages          = $this->_get_extra_nav_menu_pages_items();
449
-                        $args['walker'] = $walker;
450
-                        echo walk_nav_menu_tree(
451
-                            array_map(
452
-                                array($this, '_setup_extra_nav_menu_pages_items'),
453
-                                $pages
454
-                            ),
455
-                            0,
456
-                            (object) $args
457
-                        );
458
-                        ?>
448
+						$pages          = $this->_get_extra_nav_menu_pages_items();
449
+						$args['walker'] = $walker;
450
+						echo walk_nav_menu_tree(
451
+							array_map(
452
+								array($this, '_setup_extra_nav_menu_pages_items'),
453
+								$pages
454
+							),
455
+							0,
456
+							(object) $args
457
+						);
458
+						?>
459 459
                     </ul>
460 460
                 </div><!-- /.tabs-panel -->
461 461
 
462 462
                 <p class="button-controls">
463 463
                 <span class="list-controls">
464 464
                     <a href="<?php
465
-                    echo esc_url(add_query_arg(
466
-                        array(
467
-                            'extra-nav-menu-pages-tab' => 'event-archives',
468
-                            'selectall'                => 1,
469
-                        ),
470
-                        remove_query_arg($removed_args)
471
-                    ));
472
-                    ?>#posttype-extra-nav-menu-pages>" class="select-all"><?php _e('Select All'); ?></a>
465
+					echo esc_url(add_query_arg(
466
+						array(
467
+							'extra-nav-menu-pages-tab' => 'event-archives',
468
+							'selectall'                => 1,
469
+						),
470
+						remove_query_arg($removed_args)
471
+					));
472
+					?>#posttype-extra-nav-menu-pages>" class="select-all"><?php _e('Select All'); ?></a>
473 473
                 </span>
474 474
                 <span class="add-to-menu">
475 475
                     <input type="submit"<?php wp_nav_menu_disabled_check($nav_menu_selected_id); ?>
@@ -482,471 +482,471 @@  discard block
 block discarded – undo
482 482
 
483 483
         </div><!-- /.posttypediv -->
484 484
         <?php
485
-    }
486
-
487
-
488
-    /**
489
-     * Returns an array of event archive nav items.
490
-     *
491
-     * @todo  for now this method is just in place so when it gets abstracted further we can substitute in whatever
492
-     *        method we use for getting the extra nav menu items
493
-     * @return array
494
-     */
495
-    private function _get_extra_nav_menu_pages_items()
496
-    {
497
-        $menuitems[] = array(
498
-            'title'       => esc_html__('Event List', 'event_espresso'),
499
-            'url'         => get_post_type_archive_link('espresso_events'),
500
-            'description' => esc_html__('Archive page for all events.', 'event_espresso'),
501
-        );
502
-        return apply_filters('FHEE__EE_Admin__get_extra_nav_menu_pages_items', $menuitems);
503
-    }
504
-
505
-
506
-    /**
507
-     * Setup nav menu walker item for usage in the event archive nav menu metabox.  It receives a menu_item array with
508
-     * the properties and converts it to the menu item object.
509
-     *
510
-     * @see wp_setup_nav_menu_item() in wp-includes/nav-menu.php
511
-     * @param $menu_item_values
512
-     * @return stdClass
513
-     */
514
-    private function _setup_extra_nav_menu_pages_items($menu_item_values)
515
-    {
516
-        $menu_item = new stdClass();
517
-        $keys      = array(
518
-            'ID'               => 0,
519
-            'db_id'            => 0,
520
-            'menu_item_parent' => 0,
521
-            'object_id'        => -1,
522
-            'post_parent'      => 0,
523
-            'type'             => 'custom',
524
-            'object'           => '',
525
-            'type_label'       => esc_html__('Extra Nav Menu Item', 'event_espresso'),
526
-            'title'            => '',
527
-            'url'              => '',
528
-            'target'           => '',
529
-            'attr_title'       => '',
530
-            'description'      => '',
531
-            'classes'          => array(),
532
-            'xfn'              => '',
533
-        );
534
-
535
-        foreach ($keys as $key => $value) {
536
-            $menu_item->{$key} = isset($menu_item_values[$key]) ? $menu_item_values[$key] : $value;
537
-        }
538
-        return $menu_item;
539
-    }
540
-
541
-
542
-    /**
543
-     * This is the action hook for the AHEE__EE_Admin_Page__route_admin_request hook that fires off right before an
544
-     * EE_Admin_Page route is called.
545
-     *
546
-     * @return void
547
-     */
548
-    public function route_admin_request()
549
-    {
550
-    }
551
-
552
-
553
-    /**
554
-     * wp_loaded should fire on the WordPress wp_loaded hook.  This fires on a VERY late priority.
555
-     *
556
-     * @return void
557
-     */
558
-    public function wp_loaded()
559
-    {
560
-    }
561
-
562
-
563
-    /**
564
-     * admin_init
565
-     *
566
-     * @return void
567
-     * @throws EE_Error
568
-     * @throws InvalidArgumentException
569
-     * @throws InvalidDataTypeException
570
-     * @throws InvalidInterfaceException
571
-     * @throws ReflectionException
572
-     */
573
-    public function admin_init()
574
-    {
575
-
576
-        /**
577
-         * our cpt models must be instantiated on WordPress post processing routes (wp-admin/post.php),
578
-         * so any hooking into core WP routes is taken care of.  So in this next few lines of code:
579
-         * - check if doing post processing.
580
-         * - check if doing post processing of one of EE CPTs
581
-         * - instantiate the corresponding EE CPT model for the post_type being processed.
582
-         */
583
-        if (isset($_POST['action'], $_POST['post_type']) && $_POST['action'] === 'editpost') {
584
-            EE_Registry::instance()->load_core('Register_CPTs');
585
-            EE_Register_CPTs::instantiate_cpt_models($_POST['post_type']);
586
-        }
587
-
588
-
589
-        /**
590
-         * This code excludes EE critical pages anywhere `wp_dropdown_pages` is used to create a dropdown for selecting
591
-         * critical pages.  The only place critical pages need included in a generated dropdown is on the "Critical
592
-         * Pages" tab in the EE General Settings Admin page.
593
-         * This is for user-proofing.
594
-         */
595
-        add_filter('wp_dropdown_pages', array($this, 'modify_dropdown_pages'));
596
-    }
597
-
598
-
599
-    /**
600
-     * Callback for wp_dropdown_pages hook to remove ee critical pages from the dropdown selection.
601
-     *
602
-     * @param string $output Current output.
603
-     * @return string
604
-     * @throws InvalidArgumentException
605
-     * @throws InvalidDataTypeException
606
-     * @throws InvalidInterfaceException
607
-     */
608
-    public function modify_dropdown_pages($output)
609
-    {
610
-        //get critical pages
611
-        $critical_pages = EE_Registry::instance()->CFG->core->get_critical_pages_array();
612
-
613
-        //split current output by line break for easier parsing.
614
-        $split_output = explode("\n", $output);
615
-
616
-        //loop through to remove any critical pages from the array.
617
-        foreach ($critical_pages as $page_id) {
618
-            $needle = 'value="' . $page_id . '"';
619
-            foreach ($split_output as $key => $haystack) {
620
-                if (strpos($haystack, $needle) !== false) {
621
-                    unset($split_output[$key]);
622
-                }
623
-            }
624
-        }
625
-        //replace output with the new contents
626
-        return implode("\n", $split_output);
627
-    }
628
-
629
-
630
-    /**
631
-     * enqueue all admin scripts that need loaded for admin pages
632
-     *
633
-     * @return void
634
-     */
635
-    public function enqueue_admin_scripts()
636
-    {
637
-        // this javascript is loaded on every admin page to catch any injections ee needs to add to wp run js.
638
-        // Note: the intention of this script is to only do TARGETED injections.  I.E, only injecting on certain script
639
-        // calls.
640
-        wp_enqueue_script(
641
-            'ee-inject-wp',
642
-            EE_ADMIN_URL . 'assets/ee-cpt-wp-injects.js',
643
-            array('jquery'),
644
-            EVENT_ESPRESSO_VERSION,
645
-            true
646
-        );
647
-        // register cookie script for future dependencies
648
-        wp_register_script(
649
-            'jquery-cookie',
650
-            EE_THIRD_PARTY_URL . 'joyride/jquery.cookie.js',
651
-            array('jquery'),
652
-            '2.1',
653
-            true
654
-        );
655
-        //joyride is turned OFF by default, but prior to the admin_enqueue_scripts hook, can be turned back on again
656
-        // via: add_filter('FHEE_load_joyride', '__return_true' );
657
-        if (apply_filters('FHEE_load_joyride', false)) {
658
-            //joyride style
659
-            wp_register_style('joyride-css', EE_THIRD_PARTY_URL . 'joyride/joyride-2.1.css', array(), '2.1');
660
-            wp_register_style(
661
-                'ee-joyride-css',
662
-                EE_GLOBAL_ASSETS_URL . 'css/ee-joyride-styles.css',
663
-                array('joyride-css'),
664
-                EVENT_ESPRESSO_VERSION
665
-            );
666
-            wp_register_script(
667
-                'joyride-modernizr',
668
-                EE_THIRD_PARTY_URL . 'joyride/modernizr.mq.js',
669
-                array(),
670
-                '2.1',
671
-                true
672
-            );
673
-            //joyride JS
674
-            wp_register_script(
675
-                'jquery-joyride',
676
-                EE_THIRD_PARTY_URL . 'joyride/jquery.joyride-2.1.js',
677
-                array('jquery-cookie', 'joyride-modernizr'),
678
-                '2.1',
679
-                true
680
-            );
681
-            // wanna go for a joyride?
682
-            wp_enqueue_style('ee-joyride-css');
683
-            wp_enqueue_script('jquery-joyride');
684
-        }
685
-    }
686
-
687
-
688
-    /**
689
-     * display_admin_notices
690
-     *
691
-     * @return void
692
-     */
693
-    public function display_admin_notices()
694
-    {
695
-        echo EE_Error::get_notices();
696
-    }
697
-
698
-
699
-
700
-    /**
701
-     * @param array $elements
702
-     * @return array
703
-     * @throws EE_Error
704
-     * @throws InvalidArgumentException
705
-     * @throws InvalidDataTypeException
706
-     * @throws InvalidInterfaceException
707
-     */
708
-    public function dashboard_glance_items($elements)
709
-    {
710
-        $elements                        = is_array($elements) ? $elements : array($elements);
711
-        $events                          = EEM_Event::instance()->count();
712
-        $items['events']['url']          = EE_Admin_Page::add_query_args_and_nonce(
713
-            array('page' => 'espresso_events'),
714
-            admin_url('admin.php')
715
-        );
716
-        $items['events']['text']         = sprintf(_n('%s Event', '%s Events', $events), number_format_i18n($events));
717
-        $items['events']['title']        = esc_html__('Click to view all Events', 'event_espresso');
718
-        $registrations                   = EEM_Registration::instance()->count(
719
-            array(
720
-                array(
721
-                    'STS_ID' => array('!=', EEM_Registration::status_id_incomplete),
722
-                ),
723
-            )
724
-        );
725
-        $items['registrations']['url']   = EE_Admin_Page::add_query_args_and_nonce(
726
-            array('page' => 'espresso_registrations'),
727
-            admin_url('admin.php')
728
-        );
729
-        $items['registrations']['text']  = sprintf(
730
-            _n('%s Registration', '%s Registrations', $registrations),
731
-            number_format_i18n($registrations)
732
-        );
733
-        $items['registrations']['title'] = esc_html__('Click to view all registrations', 'event_espresso');
734
-
735
-        $items = (array)apply_filters('FHEE__EE_Admin__dashboard_glance_items__items', $items);
736
-
737
-        foreach ($items as $type => $item_properties) {
738
-            $elements[] = sprintf(
739
-                '<a class="ee-dashboard-link-' . $type . '" href="%s" title="%s">%s</a>',
740
-                $item_properties['url'],
741
-                $item_properties['title'],
742
-                $item_properties['text']
743
-            );
744
-        }
745
-        return $elements;
746
-    }
747
-
748
-
749
-    /**
750
-     * check_for_invalid_datetime_formats
751
-     * if an admin changes their date or time format settings on the WP General Settings admin page, verify that
752
-     * their selected format can be parsed by PHP
753
-     *
754
-     * @param    $value
755
-     * @param    $option
756
-     * @throws EE_Error
757
-     * @return    string
758
-     */
759
-    public function check_for_invalid_datetime_formats($value, $option)
760
-    {
761
-        // check for date_format or time_format
762
-        switch ($option) {
763
-            case 'date_format':
764
-                $date_time_format = $value . ' ' . get_option('time_format');
765
-                break;
766
-            case 'time_format':
767
-                $date_time_format = get_option('date_format') . ' ' . $value;
768
-                break;
769
-            default:
770
-                $date_time_format = false;
771
-        }
772
-        // do we have a date_time format to check ?
773
-        if ($date_time_format) {
774
-            $error_msg = EEH_DTT_Helper::validate_format_string($date_time_format);
775
-
776
-            if (is_array($error_msg)) {
777
-                $msg = '<p>'
778
-                       . sprintf(
779
-                           esc_html__(
780
-                               'The following date time "%s" ( %s ) is difficult to be properly parsed by PHP for the following reasons:',
781
-                               'event_espresso'
782
-                           ),
783
-                           date($date_time_format),
784
-                           $date_time_format
785
-                       )
786
-                       . '</p><p><ul>';
787
-
788
-
789
-                foreach ($error_msg as $error) {
790
-                    $msg .= '<li>' . $error . '</li>';
791
-                }
792
-
793
-                $msg .= '</ul></p><p>'
794
-                        . sprintf(
795
-                            esc_html__(
796
-                                '%sPlease note that your date and time formats have been reset to "F j, Y" and "g:i a" respectively.%s',
797
-                                'event_espresso'
798
-                            ),
799
-                            '<span style="color:#D54E21;">',
800
-                            '</span>'
801
-                        )
802
-                        . '</p>';
803
-
804
-                // trigger WP settings error
805
-                add_settings_error(
806
-                    'date_format',
807
-                    'date_format',
808
-                    $msg
809
-                );
810
-
811
-                // set format to something valid
812
-                switch ($option) {
813
-                    case 'date_format':
814
-                        $value = 'F j, Y';
815
-                        break;
816
-                    case 'time_format':
817
-                        $value = 'g:i a';
818
-                        break;
819
-                }
820
-            }
821
-        }
822
-        return $value;
823
-    }
824
-
825
-
826
-    /**
827
-     * its_eSpresso - converts the less commonly used spelling of "Expresso" to "Espresso"
828
-     *
829
-     * @param $content
830
-     * @return    string
831
-     */
832
-    public function its_eSpresso($content)
833
-    {
834
-        return str_replace('[EXPRESSO_', '[ESPRESSO_', $content);
835
-    }
836
-
837
-
838
-    /**
839
-     * espresso_admin_footer
840
-     *
841
-     * @return    string
842
-     */
843
-    public function espresso_admin_footer()
844
-    {
845
-        return \EEH_Template::powered_by_event_espresso('aln-cntr', '', array('utm_content' => 'admin_footer'));
846
-    }
847
-
848
-
849
-    /**
850
-     * static method for registering ee admin page.
851
-     * This method is deprecated in favor of the new location in EE_Register_Admin_Page::register.
852
-     *
853
-     * @since      4.3.0
854
-     * @deprecated 4.3.0    Use EE_Register_Admin_Page::register() instead
855
-     * @see        EE_Register_Admin_Page::register()
856
-     * @param       $page_basename
857
-     * @param       $page_path
858
-     * @param array $config
859
-     * @return void
860
-     * @throws EE_Error
861
-     */
862
-    public static function register_ee_admin_page($page_basename, $page_path, $config = array())
863
-    {
864
-        EE_Error::doing_it_wrong(
865
-            __METHOD__,
866
-            sprintf(
867
-                esc_html__(
868
-                    'Usage is deprecated.  Use EE_Register_Admin_Page::register() for registering the %s admin page.',
869
-                    'event_espresso'
870
-                ),
871
-                $page_basename
872
-            ),
873
-            '4.3'
874
-        );
875
-        if (class_exists('EE_Register_Admin_Page')) {
876
-            $config['page_path'] = $page_path;
877
-        }
878
-        EE_Register_Admin_Page::register($page_basename, $config);
879
-    }
880
-
881
-
882
-    /**
883
-     * @deprecated 4.8.41
884
-     * @param  int      $post_ID
885
-     * @param  \WP_Post $post
886
-     * @return void
887
-     */
888
-    public static function parse_post_content_on_save($post_ID, $post)
889
-    {
890
-        EE_Error::doing_it_wrong(
891
-            __METHOD__,
892
-            esc_html__('Usage is deprecated', 'event_espresso'),
893
-            '4.8.41'
894
-        );
895
-    }
896
-
897
-
898
-    /**
899
-     * @deprecated 4.8.41
900
-     * @param  $option
901
-     * @param  $old_value
902
-     * @param  $value
903
-     * @return void
904
-     */
905
-    public function reset_page_for_posts_on_change($option, $old_value, $value)
906
-    {
907
-        EE_Error::doing_it_wrong(
908
-            __METHOD__,
909
-            esc_html__('Usage is deprecated', 'event_espresso'),
910
-            '4.8.41'
911
-        );
912
-    }
913
-
914
-
915
-
916
-    /**
917
-     * @deprecated 4.9.27
918
-     * @return void
919
-     */
920
-    public function get_persistent_admin_notices()
921
-    {
922
-        EE_Error::doing_it_wrong(
923
-            __METHOD__,
924
-            sprintf(
925
-                __('Usage is deprecated. Use "%1$s" instead.', 'event_espresso'),
926
-                '\EventEspresso\core\services\notifications\PersistentAdminNoticeManager'
927
-            ),
928
-            '4.9.27'
929
-        );
930
-    }
931
-
932
-
933
-
934
-    /**
935
-     * @deprecated 4.9.27
936
-     * @throws InvalidInterfaceException
937
-     * @throws InvalidDataTypeException
938
-     * @throws DomainException
939
-     */
940
-    public function dismiss_ee_nag_notice_callback()
941
-    {
942
-        EE_Error::doing_it_wrong(
943
-            __METHOD__,
944
-            sprintf(
945
-                __('Usage is deprecated. Use "%1$s" instead.', 'event_espresso'),
946
-                '\EventEspresso\core\services\notifications\PersistentAdminNoticeManager'
947
-            ),
948
-            '4.9.27'
949
-        );
950
-        $this->persistent_admin_notice_manager->dismissNotice();
951
-    }
485
+	}
486
+
487
+
488
+	/**
489
+	 * Returns an array of event archive nav items.
490
+	 *
491
+	 * @todo  for now this method is just in place so when it gets abstracted further we can substitute in whatever
492
+	 *        method we use for getting the extra nav menu items
493
+	 * @return array
494
+	 */
495
+	private function _get_extra_nav_menu_pages_items()
496
+	{
497
+		$menuitems[] = array(
498
+			'title'       => esc_html__('Event List', 'event_espresso'),
499
+			'url'         => get_post_type_archive_link('espresso_events'),
500
+			'description' => esc_html__('Archive page for all events.', 'event_espresso'),
501
+		);
502
+		return apply_filters('FHEE__EE_Admin__get_extra_nav_menu_pages_items', $menuitems);
503
+	}
504
+
505
+
506
+	/**
507
+	 * Setup nav menu walker item for usage in the event archive nav menu metabox.  It receives a menu_item array with
508
+	 * the properties and converts it to the menu item object.
509
+	 *
510
+	 * @see wp_setup_nav_menu_item() in wp-includes/nav-menu.php
511
+	 * @param $menu_item_values
512
+	 * @return stdClass
513
+	 */
514
+	private function _setup_extra_nav_menu_pages_items($menu_item_values)
515
+	{
516
+		$menu_item = new stdClass();
517
+		$keys      = array(
518
+			'ID'               => 0,
519
+			'db_id'            => 0,
520
+			'menu_item_parent' => 0,
521
+			'object_id'        => -1,
522
+			'post_parent'      => 0,
523
+			'type'             => 'custom',
524
+			'object'           => '',
525
+			'type_label'       => esc_html__('Extra Nav Menu Item', 'event_espresso'),
526
+			'title'            => '',
527
+			'url'              => '',
528
+			'target'           => '',
529
+			'attr_title'       => '',
530
+			'description'      => '',
531
+			'classes'          => array(),
532
+			'xfn'              => '',
533
+		);
534
+
535
+		foreach ($keys as $key => $value) {
536
+			$menu_item->{$key} = isset($menu_item_values[$key]) ? $menu_item_values[$key] : $value;
537
+		}
538
+		return $menu_item;
539
+	}
540
+
541
+
542
+	/**
543
+	 * This is the action hook for the AHEE__EE_Admin_Page__route_admin_request hook that fires off right before an
544
+	 * EE_Admin_Page route is called.
545
+	 *
546
+	 * @return void
547
+	 */
548
+	public function route_admin_request()
549
+	{
550
+	}
551
+
552
+
553
+	/**
554
+	 * wp_loaded should fire on the WordPress wp_loaded hook.  This fires on a VERY late priority.
555
+	 *
556
+	 * @return void
557
+	 */
558
+	public function wp_loaded()
559
+	{
560
+	}
561
+
562
+
563
+	/**
564
+	 * admin_init
565
+	 *
566
+	 * @return void
567
+	 * @throws EE_Error
568
+	 * @throws InvalidArgumentException
569
+	 * @throws InvalidDataTypeException
570
+	 * @throws InvalidInterfaceException
571
+	 * @throws ReflectionException
572
+	 */
573
+	public function admin_init()
574
+	{
575
+
576
+		/**
577
+		 * our cpt models must be instantiated on WordPress post processing routes (wp-admin/post.php),
578
+		 * so any hooking into core WP routes is taken care of.  So in this next few lines of code:
579
+		 * - check if doing post processing.
580
+		 * - check if doing post processing of one of EE CPTs
581
+		 * - instantiate the corresponding EE CPT model for the post_type being processed.
582
+		 */
583
+		if (isset($_POST['action'], $_POST['post_type']) && $_POST['action'] === 'editpost') {
584
+			EE_Registry::instance()->load_core('Register_CPTs');
585
+			EE_Register_CPTs::instantiate_cpt_models($_POST['post_type']);
586
+		}
587
+
588
+
589
+		/**
590
+		 * This code excludes EE critical pages anywhere `wp_dropdown_pages` is used to create a dropdown for selecting
591
+		 * critical pages.  The only place critical pages need included in a generated dropdown is on the "Critical
592
+		 * Pages" tab in the EE General Settings Admin page.
593
+		 * This is for user-proofing.
594
+		 */
595
+		add_filter('wp_dropdown_pages', array($this, 'modify_dropdown_pages'));
596
+	}
597
+
598
+
599
+	/**
600
+	 * Callback for wp_dropdown_pages hook to remove ee critical pages from the dropdown selection.
601
+	 *
602
+	 * @param string $output Current output.
603
+	 * @return string
604
+	 * @throws InvalidArgumentException
605
+	 * @throws InvalidDataTypeException
606
+	 * @throws InvalidInterfaceException
607
+	 */
608
+	public function modify_dropdown_pages($output)
609
+	{
610
+		//get critical pages
611
+		$critical_pages = EE_Registry::instance()->CFG->core->get_critical_pages_array();
612
+
613
+		//split current output by line break for easier parsing.
614
+		$split_output = explode("\n", $output);
615
+
616
+		//loop through to remove any critical pages from the array.
617
+		foreach ($critical_pages as $page_id) {
618
+			$needle = 'value="' . $page_id . '"';
619
+			foreach ($split_output as $key => $haystack) {
620
+				if (strpos($haystack, $needle) !== false) {
621
+					unset($split_output[$key]);
622
+				}
623
+			}
624
+		}
625
+		//replace output with the new contents
626
+		return implode("\n", $split_output);
627
+	}
628
+
629
+
630
+	/**
631
+	 * enqueue all admin scripts that need loaded for admin pages
632
+	 *
633
+	 * @return void
634
+	 */
635
+	public function enqueue_admin_scripts()
636
+	{
637
+		// this javascript is loaded on every admin page to catch any injections ee needs to add to wp run js.
638
+		// Note: the intention of this script is to only do TARGETED injections.  I.E, only injecting on certain script
639
+		// calls.
640
+		wp_enqueue_script(
641
+			'ee-inject-wp',
642
+			EE_ADMIN_URL . 'assets/ee-cpt-wp-injects.js',
643
+			array('jquery'),
644
+			EVENT_ESPRESSO_VERSION,
645
+			true
646
+		);
647
+		// register cookie script for future dependencies
648
+		wp_register_script(
649
+			'jquery-cookie',
650
+			EE_THIRD_PARTY_URL . 'joyride/jquery.cookie.js',
651
+			array('jquery'),
652
+			'2.1',
653
+			true
654
+		);
655
+		//joyride is turned OFF by default, but prior to the admin_enqueue_scripts hook, can be turned back on again
656
+		// via: add_filter('FHEE_load_joyride', '__return_true' );
657
+		if (apply_filters('FHEE_load_joyride', false)) {
658
+			//joyride style
659
+			wp_register_style('joyride-css', EE_THIRD_PARTY_URL . 'joyride/joyride-2.1.css', array(), '2.1');
660
+			wp_register_style(
661
+				'ee-joyride-css',
662
+				EE_GLOBAL_ASSETS_URL . 'css/ee-joyride-styles.css',
663
+				array('joyride-css'),
664
+				EVENT_ESPRESSO_VERSION
665
+			);
666
+			wp_register_script(
667
+				'joyride-modernizr',
668
+				EE_THIRD_PARTY_URL . 'joyride/modernizr.mq.js',
669
+				array(),
670
+				'2.1',
671
+				true
672
+			);
673
+			//joyride JS
674
+			wp_register_script(
675
+				'jquery-joyride',
676
+				EE_THIRD_PARTY_URL . 'joyride/jquery.joyride-2.1.js',
677
+				array('jquery-cookie', 'joyride-modernizr'),
678
+				'2.1',
679
+				true
680
+			);
681
+			// wanna go for a joyride?
682
+			wp_enqueue_style('ee-joyride-css');
683
+			wp_enqueue_script('jquery-joyride');
684
+		}
685
+	}
686
+
687
+
688
+	/**
689
+	 * display_admin_notices
690
+	 *
691
+	 * @return void
692
+	 */
693
+	public function display_admin_notices()
694
+	{
695
+		echo EE_Error::get_notices();
696
+	}
697
+
698
+
699
+
700
+	/**
701
+	 * @param array $elements
702
+	 * @return array
703
+	 * @throws EE_Error
704
+	 * @throws InvalidArgumentException
705
+	 * @throws InvalidDataTypeException
706
+	 * @throws InvalidInterfaceException
707
+	 */
708
+	public function dashboard_glance_items($elements)
709
+	{
710
+		$elements                        = is_array($elements) ? $elements : array($elements);
711
+		$events                          = EEM_Event::instance()->count();
712
+		$items['events']['url']          = EE_Admin_Page::add_query_args_and_nonce(
713
+			array('page' => 'espresso_events'),
714
+			admin_url('admin.php')
715
+		);
716
+		$items['events']['text']         = sprintf(_n('%s Event', '%s Events', $events), number_format_i18n($events));
717
+		$items['events']['title']        = esc_html__('Click to view all Events', 'event_espresso');
718
+		$registrations                   = EEM_Registration::instance()->count(
719
+			array(
720
+				array(
721
+					'STS_ID' => array('!=', EEM_Registration::status_id_incomplete),
722
+				),
723
+			)
724
+		);
725
+		$items['registrations']['url']   = EE_Admin_Page::add_query_args_and_nonce(
726
+			array('page' => 'espresso_registrations'),
727
+			admin_url('admin.php')
728
+		);
729
+		$items['registrations']['text']  = sprintf(
730
+			_n('%s Registration', '%s Registrations', $registrations),
731
+			number_format_i18n($registrations)
732
+		);
733
+		$items['registrations']['title'] = esc_html__('Click to view all registrations', 'event_espresso');
734
+
735
+		$items = (array)apply_filters('FHEE__EE_Admin__dashboard_glance_items__items', $items);
736
+
737
+		foreach ($items as $type => $item_properties) {
738
+			$elements[] = sprintf(
739
+				'<a class="ee-dashboard-link-' . $type . '" href="%s" title="%s">%s</a>',
740
+				$item_properties['url'],
741
+				$item_properties['title'],
742
+				$item_properties['text']
743
+			);
744
+		}
745
+		return $elements;
746
+	}
747
+
748
+
749
+	/**
750
+	 * check_for_invalid_datetime_formats
751
+	 * if an admin changes their date or time format settings on the WP General Settings admin page, verify that
752
+	 * their selected format can be parsed by PHP
753
+	 *
754
+	 * @param    $value
755
+	 * @param    $option
756
+	 * @throws EE_Error
757
+	 * @return    string
758
+	 */
759
+	public function check_for_invalid_datetime_formats($value, $option)
760
+	{
761
+		// check for date_format or time_format
762
+		switch ($option) {
763
+			case 'date_format':
764
+				$date_time_format = $value . ' ' . get_option('time_format');
765
+				break;
766
+			case 'time_format':
767
+				$date_time_format = get_option('date_format') . ' ' . $value;
768
+				break;
769
+			default:
770
+				$date_time_format = false;
771
+		}
772
+		// do we have a date_time format to check ?
773
+		if ($date_time_format) {
774
+			$error_msg = EEH_DTT_Helper::validate_format_string($date_time_format);
775
+
776
+			if (is_array($error_msg)) {
777
+				$msg = '<p>'
778
+					   . sprintf(
779
+						   esc_html__(
780
+							   'The following date time "%s" ( %s ) is difficult to be properly parsed by PHP for the following reasons:',
781
+							   'event_espresso'
782
+						   ),
783
+						   date($date_time_format),
784
+						   $date_time_format
785
+					   )
786
+					   . '</p><p><ul>';
787
+
788
+
789
+				foreach ($error_msg as $error) {
790
+					$msg .= '<li>' . $error . '</li>';
791
+				}
792
+
793
+				$msg .= '</ul></p><p>'
794
+						. sprintf(
795
+							esc_html__(
796
+								'%sPlease note that your date and time formats have been reset to "F j, Y" and "g:i a" respectively.%s',
797
+								'event_espresso'
798
+							),
799
+							'<span style="color:#D54E21;">',
800
+							'</span>'
801
+						)
802
+						. '</p>';
803
+
804
+				// trigger WP settings error
805
+				add_settings_error(
806
+					'date_format',
807
+					'date_format',
808
+					$msg
809
+				);
810
+
811
+				// set format to something valid
812
+				switch ($option) {
813
+					case 'date_format':
814
+						$value = 'F j, Y';
815
+						break;
816
+					case 'time_format':
817
+						$value = 'g:i a';
818
+						break;
819
+				}
820
+			}
821
+		}
822
+		return $value;
823
+	}
824
+
825
+
826
+	/**
827
+	 * its_eSpresso - converts the less commonly used spelling of "Expresso" to "Espresso"
828
+	 *
829
+	 * @param $content
830
+	 * @return    string
831
+	 */
832
+	public function its_eSpresso($content)
833
+	{
834
+		return str_replace('[EXPRESSO_', '[ESPRESSO_', $content);
835
+	}
836
+
837
+
838
+	/**
839
+	 * espresso_admin_footer
840
+	 *
841
+	 * @return    string
842
+	 */
843
+	public function espresso_admin_footer()
844
+	{
845
+		return \EEH_Template::powered_by_event_espresso('aln-cntr', '', array('utm_content' => 'admin_footer'));
846
+	}
847
+
848
+
849
+	/**
850
+	 * static method for registering ee admin page.
851
+	 * This method is deprecated in favor of the new location in EE_Register_Admin_Page::register.
852
+	 *
853
+	 * @since      4.3.0
854
+	 * @deprecated 4.3.0    Use EE_Register_Admin_Page::register() instead
855
+	 * @see        EE_Register_Admin_Page::register()
856
+	 * @param       $page_basename
857
+	 * @param       $page_path
858
+	 * @param array $config
859
+	 * @return void
860
+	 * @throws EE_Error
861
+	 */
862
+	public static function register_ee_admin_page($page_basename, $page_path, $config = array())
863
+	{
864
+		EE_Error::doing_it_wrong(
865
+			__METHOD__,
866
+			sprintf(
867
+				esc_html__(
868
+					'Usage is deprecated.  Use EE_Register_Admin_Page::register() for registering the %s admin page.',
869
+					'event_espresso'
870
+				),
871
+				$page_basename
872
+			),
873
+			'4.3'
874
+		);
875
+		if (class_exists('EE_Register_Admin_Page')) {
876
+			$config['page_path'] = $page_path;
877
+		}
878
+		EE_Register_Admin_Page::register($page_basename, $config);
879
+	}
880
+
881
+
882
+	/**
883
+	 * @deprecated 4.8.41
884
+	 * @param  int      $post_ID
885
+	 * @param  \WP_Post $post
886
+	 * @return void
887
+	 */
888
+	public static function parse_post_content_on_save($post_ID, $post)
889
+	{
890
+		EE_Error::doing_it_wrong(
891
+			__METHOD__,
892
+			esc_html__('Usage is deprecated', 'event_espresso'),
893
+			'4.8.41'
894
+		);
895
+	}
896
+
897
+
898
+	/**
899
+	 * @deprecated 4.8.41
900
+	 * @param  $option
901
+	 * @param  $old_value
902
+	 * @param  $value
903
+	 * @return void
904
+	 */
905
+	public function reset_page_for_posts_on_change($option, $old_value, $value)
906
+	{
907
+		EE_Error::doing_it_wrong(
908
+			__METHOD__,
909
+			esc_html__('Usage is deprecated', 'event_espresso'),
910
+			'4.8.41'
911
+		);
912
+	}
913
+
914
+
915
+
916
+	/**
917
+	 * @deprecated 4.9.27
918
+	 * @return void
919
+	 */
920
+	public function get_persistent_admin_notices()
921
+	{
922
+		EE_Error::doing_it_wrong(
923
+			__METHOD__,
924
+			sprintf(
925
+				__('Usage is deprecated. Use "%1$s" instead.', 'event_espresso'),
926
+				'\EventEspresso\core\services\notifications\PersistentAdminNoticeManager'
927
+			),
928
+			'4.9.27'
929
+		);
930
+	}
931
+
932
+
933
+
934
+	/**
935
+	 * @deprecated 4.9.27
936
+	 * @throws InvalidInterfaceException
937
+	 * @throws InvalidDataTypeException
938
+	 * @throws DomainException
939
+	 */
940
+	public function dismiss_ee_nag_notice_callback()
941
+	{
942
+		EE_Error::doing_it_wrong(
943
+			__METHOD__,
944
+			sprintf(
945
+				__('Usage is deprecated. Use "%1$s" instead.', 'event_espresso'),
946
+				'\EventEspresso\core\services\notifications\PersistentAdminNoticeManager'
947
+			),
948
+			'4.9.27'
949
+		);
950
+		$this->persistent_admin_notice_manager->dismissNotice();
951
+	}
952 952
 }
Please login to merge, or discard this patch.
Spacing   +30 added lines, -30 removed lines patch added patch discarded remove patch
@@ -40,7 +40,7 @@  discard block
 block discarded – undo
40 40
     public static function instance()
41 41
     {
42 42
         // check if class object is instantiated
43
-        if (! self::$_instance instanceof EE_Admin) {
43
+        if ( ! self::$_instance instanceof EE_Admin) {
44 44
             self::$_instance = new self();
45 45
         }
46 46
         return self::$_instance;
@@ -100,11 +100,11 @@  discard block
 block discarded – undo
100 100
      */
101 101
     private function _define_all_constants()
102 102
     {
103
-        if (! defined('EE_ADMIN_URL')) {
104
-            define('EE_ADMIN_URL', EE_PLUGIN_DIR_URL . 'core/admin/');
105
-            define('EE_ADMIN_PAGES_URL', EE_PLUGIN_DIR_URL . 'admin_pages/');
106
-            define('EE_ADMIN_TEMPLATE', EE_ADMIN . 'templates' . DS);
107
-            define('WP_ADMIN_PATH', ABSPATH . 'wp-admin/');
103
+        if ( ! defined('EE_ADMIN_URL')) {
104
+            define('EE_ADMIN_URL', EE_PLUGIN_DIR_URL.'core/admin/');
105
+            define('EE_ADMIN_PAGES_URL', EE_PLUGIN_DIR_URL.'admin_pages/');
106
+            define('EE_ADMIN_TEMPLATE', EE_ADMIN.'templates'.DS);
107
+            define('WP_ADMIN_PATH', ABSPATH.'wp-admin/');
108 108
             define('WP_AJAX_URL', admin_url('admin-ajax.php'));
109 109
         }
110 110
     }
@@ -122,7 +122,7 @@  discard block
 block discarded – undo
122 122
         // set $main_file in stone
123 123
         static $main_file;
124 124
         // if $main_file is not set yet
125
-        if (! $main_file) {
125
+        if ( ! $main_file) {
126 126
             $main_file = plugin_basename(EVENT_ESPRESSO_MAIN_FILE);
127 127
         }
128 128
         if ($plugin === $main_file) {
@@ -175,9 +175,9 @@  discard block
 block discarded – undo
175 175
     public function hide_admin_pages_except_maintenance_mode($admin_page_folder_names = array())
176 176
     {
177 177
         return array(
178
-            'maintenance' => EE_ADMIN_PAGES . 'maintenance' . DS,
179
-            'about'       => EE_ADMIN_PAGES . 'about' . DS,
180
-            'support'     => EE_ADMIN_PAGES . 'support' . DS,
178
+            'maintenance' => EE_ADMIN_PAGES.'maintenance'.DS,
179
+            'about'       => EE_ADMIN_PAGES.'about'.DS,
180
+            'support'     => EE_ADMIN_PAGES.'support'.DS,
181 181
         );
182 182
     }
183 183
 
@@ -219,7 +219,7 @@  discard block
 block discarded – undo
219 219
             add_filter('get_edit_post_link', array($this, 'modify_edit_post_link'), 10, 2);
220 220
         }
221 221
         // run the admin page factory but ONLY if we are doing an ee admin ajax request
222
-        if (! defined('DOING_AJAX') || EE_ADMIN_AJAX) {
222
+        if ( ! defined('DOING_AJAX') || EE_ADMIN_AJAX) {
223 223
             try {
224 224
                 //this loads the controller for the admin pages which will setup routing etc
225 225
                 EE_Registry::instance()->load_core('Admin_Page_Loader');
@@ -252,7 +252,7 @@  discard block
 block discarded – undo
252 252
         //@todo This needs to stay in core for a bit to catch anyone upgrading from a version without this to a version
253 253
         //with this.  But after enough time (indeterminate at this point) we can just remove this notice.
254 254
         //this was added with https://events.codebasehq.com/projects/event-espresso/tickets/10626
255
-        if (! get_option('timezone_string') && EEM_Event::instance()->count() > 0) {
255
+        if ( ! get_option('timezone_string') && EEM_Event::instance()->count() > 0) {
256 256
             new PersistentAdminNotice(
257 257
                 'datetime_fix_notice',
258 258
                 sprintf(
@@ -264,13 +264,13 @@  discard block
 block discarded – undo
264 264
                     '</strong>',
265 265
                     '<a href="https://eventespresso.com/2017/08/important-upcoming-changes-dates-times">',
266 266
                     '</a>',
267
-                    '<a href="' . EE_Admin_Page::add_query_args_and_nonce(
267
+                    '<a href="'.EE_Admin_Page::add_query_args_and_nonce(
268 268
                         array(
269 269
                             'page' => 'espresso_maintenance_settings',
270 270
                             'action' => 'datetime_tools'
271 271
                         ),
272 272
                         admin_url('admin.php')
273
-                    ) . '">'
273
+                    ).'">'
274 274
                 ),
275 275
                 false,
276 276
                 'manage_options',
@@ -318,7 +318,7 @@  discard block
 block discarded – undo
318 318
     public function enable_hidden_ee_nav_menu_metaboxes()
319 319
     {
320 320
         global $wp_meta_boxes, $pagenow;
321
-        if (! is_array($wp_meta_boxes) || $pagenow !== 'nav-menus.php') {
321
+        if ( ! is_array($wp_meta_boxes) || $pagenow !== 'nav-menus.php') {
322 322
             return;
323 323
         }
324 324
         $user = wp_get_current_user();
@@ -389,7 +389,7 @@  discard block
 block discarded – undo
389 389
      */
390 390
     public function modify_edit_post_link($link, $id)
391 391
     {
392
-        if (! $post = get_post($id)) {
392
+        if ( ! $post = get_post($id)) {
393 393
             return $link;
394 394
         }
395 395
         if ($post->post_type === 'espresso_attendees') {
@@ -615,7 +615,7 @@  discard block
 block discarded – undo
615 615
 
616 616
         //loop through to remove any critical pages from the array.
617 617
         foreach ($critical_pages as $page_id) {
618
-            $needle = 'value="' . $page_id . '"';
618
+            $needle = 'value="'.$page_id.'"';
619 619
             foreach ($split_output as $key => $haystack) {
620 620
                 if (strpos($haystack, $needle) !== false) {
621 621
                     unset($split_output[$key]);
@@ -639,7 +639,7 @@  discard block
 block discarded – undo
639 639
         // calls.
640 640
         wp_enqueue_script(
641 641
             'ee-inject-wp',
642
-            EE_ADMIN_URL . 'assets/ee-cpt-wp-injects.js',
642
+            EE_ADMIN_URL.'assets/ee-cpt-wp-injects.js',
643 643
             array('jquery'),
644 644
             EVENT_ESPRESSO_VERSION,
645 645
             true
@@ -647,7 +647,7 @@  discard block
 block discarded – undo
647 647
         // register cookie script for future dependencies
648 648
         wp_register_script(
649 649
             'jquery-cookie',
650
-            EE_THIRD_PARTY_URL . 'joyride/jquery.cookie.js',
650
+            EE_THIRD_PARTY_URL.'joyride/jquery.cookie.js',
651 651
             array('jquery'),
652 652
             '2.1',
653 653
             true
@@ -656,16 +656,16 @@  discard block
 block discarded – undo
656 656
         // via: add_filter('FHEE_load_joyride', '__return_true' );
657 657
         if (apply_filters('FHEE_load_joyride', false)) {
658 658
             //joyride style
659
-            wp_register_style('joyride-css', EE_THIRD_PARTY_URL . 'joyride/joyride-2.1.css', array(), '2.1');
659
+            wp_register_style('joyride-css', EE_THIRD_PARTY_URL.'joyride/joyride-2.1.css', array(), '2.1');
660 660
             wp_register_style(
661 661
                 'ee-joyride-css',
662
-                EE_GLOBAL_ASSETS_URL . 'css/ee-joyride-styles.css',
662
+                EE_GLOBAL_ASSETS_URL.'css/ee-joyride-styles.css',
663 663
                 array('joyride-css'),
664 664
                 EVENT_ESPRESSO_VERSION
665 665
             );
666 666
             wp_register_script(
667 667
                 'joyride-modernizr',
668
-                EE_THIRD_PARTY_URL . 'joyride/modernizr.mq.js',
668
+                EE_THIRD_PARTY_URL.'joyride/modernizr.mq.js',
669 669
                 array(),
670 670
                 '2.1',
671 671
                 true
@@ -673,7 +673,7 @@  discard block
 block discarded – undo
673 673
             //joyride JS
674 674
             wp_register_script(
675 675
                 'jquery-joyride',
676
-                EE_THIRD_PARTY_URL . 'joyride/jquery.joyride-2.1.js',
676
+                EE_THIRD_PARTY_URL.'joyride/jquery.joyride-2.1.js',
677 677
                 array('jquery-cookie', 'joyride-modernizr'),
678 678
                 '2.1',
679 679
                 true
@@ -722,21 +722,21 @@  discard block
 block discarded – undo
722 722
                 ),
723 723
             )
724 724
         );
725
-        $items['registrations']['url']   = EE_Admin_Page::add_query_args_and_nonce(
725
+        $items['registrations']['url'] = EE_Admin_Page::add_query_args_and_nonce(
726 726
             array('page' => 'espresso_registrations'),
727 727
             admin_url('admin.php')
728 728
         );
729
-        $items['registrations']['text']  = sprintf(
729
+        $items['registrations']['text'] = sprintf(
730 730
             _n('%s Registration', '%s Registrations', $registrations),
731 731
             number_format_i18n($registrations)
732 732
         );
733 733
         $items['registrations']['title'] = esc_html__('Click to view all registrations', 'event_espresso');
734 734
 
735
-        $items = (array)apply_filters('FHEE__EE_Admin__dashboard_glance_items__items', $items);
735
+        $items = (array) apply_filters('FHEE__EE_Admin__dashboard_glance_items__items', $items);
736 736
 
737 737
         foreach ($items as $type => $item_properties) {
738 738
             $elements[] = sprintf(
739
-                '<a class="ee-dashboard-link-' . $type . '" href="%s" title="%s">%s</a>',
739
+                '<a class="ee-dashboard-link-'.$type.'" href="%s" title="%s">%s</a>',
740 740
                 $item_properties['url'],
741 741
                 $item_properties['title'],
742 742
                 $item_properties['text']
@@ -761,10 +761,10 @@  discard block
 block discarded – undo
761 761
         // check for date_format or time_format
762 762
         switch ($option) {
763 763
             case 'date_format':
764
-                $date_time_format = $value . ' ' . get_option('time_format');
764
+                $date_time_format = $value.' '.get_option('time_format');
765 765
                 break;
766 766
             case 'time_format':
767
-                $date_time_format = get_option('date_format') . ' ' . $value;
767
+                $date_time_format = get_option('date_format').' '.$value;
768 768
                 break;
769 769
             default:
770 770
                 $date_time_format = false;
@@ -787,7 +787,7 @@  discard block
 block discarded – undo
787 787
 
788 788
 
789 789
                 foreach ($error_msg as $error) {
790
-                    $msg .= '<li>' . $error . '</li>';
790
+                    $msg .= '<li>'.$error.'</li>';
791 791
                 }
792 792
 
793 793
                 $msg .= '</ul></p><p>'
Please login to merge, or discard this patch.
admin_pages/registration_form/Registration_Form_Admin_Page.core.php 2 patches
Indentation   +640 added lines, -640 removed lines patch added patch discarded remove patch
@@ -1,6 +1,6 @@  discard block
 block discarded – undo
1 1
 <?php
2 2
 if (! defined('EVENT_ESPRESSO_VERSION')) {
3
-    exit('NO direct script access allowed');
3
+	exit('NO direct script access allowed');
4 4
 }
5 5
 
6 6
 /**
@@ -28,596 +28,596 @@  discard block
 block discarded – undo
28 28
 class Registration_Form_Admin_Page extends EE_Admin_Page
29 29
 {
30 30
 
31
-    /**
32
-     * _question
33
-     * holds the specific question object for the question details screen
34
-     *
35
-     * @var EE_Question $_question
36
-     */
37
-    protected $_question;
38
-
39
-    /**
40
-     * _question_group
41
-     * holds the specific question group object for the question group details screen
42
-     *
43
-     * @var EE_Question_Group $_question_group
44
-     */
45
-    protected $_question_group;
46
-
47
-    /**
48
-     *_question_model EEM_Question model instance (for queries)
49
-     *
50
-     * @var EEM_Question $_question_model ;
51
-     */
52
-    protected $_question_model;
53
-
54
-    /**
55
-     * _question_group_model EEM_Question_group instance (for queries)
56
-     *
57
-     * @var EEM_Question_Group $_question_group_model
58
-     */
59
-    protected $_question_group_model;
60
-
61
-
62
-    /**
63
-     * @Constructor
64
-     * @param bool $routing indicate whether we want to just load the object and handle routing or just load the object.
65
-     * @access public
66
-     */
67
-    public function __construct($routing = true)
68
-    {
69
-        require_once(EE_MODELS . 'EEM_Question.model.php');
70
-        require_once(EE_MODELS . 'EEM_Question_Group.model.php');
71
-        $this->_question_model       = EEM_Question::instance();
72
-        $this->_question_group_model = EEM_Question_Group::instance();
73
-        parent::__construct($routing);
74
-    }
75
-
76
-
77
-    protected function _init_page_props()
78
-    {
79
-        $this->page_slug        = REGISTRATION_FORM_PG_SLUG;
80
-        $this->page_label       = esc_html__('Registration Form', 'event_espresso');
81
-        $this->_admin_base_url  = REGISTRATION_FORM_ADMIN_URL;
82
-        $this->_admin_base_path = REGISTRATION_FORM_ADMIN;
83
-    }
84
-
85
-
86
-    protected function _ajax_hooks()
87
-    {
88
-    }
89
-
90
-
91
-    protected function _define_page_props()
92
-    {
93
-        $this->_admin_page_title = esc_html__('Registration Form', 'event_espresso');
94
-        $this->_labels           = array(
95
-            'buttons' => array(
96
-                'edit_question' => esc_html__('Edit Question', 'event_espresso'),
97
-            ),
98
-        );
99
-    }
100
-
101
-
102
-    /**
103
-     *_set_page_routes
104
-     */
105
-    protected function _set_page_routes()
106
-    {
107
-        $qst_id             = ! empty($this->_req_data['QST_ID']) ? $this->_req_data['QST_ID'] : 0;
108
-        $this->_page_routes = array(
109
-            'default' => array(
110
-                'func'       => '_questions_overview_list_table',
111
-                'capability' => 'ee_read_questions',
112
-            ),
113
-
114
-            'edit_question' => array(
115
-                'func'       => '_edit_question',
116
-                'capability' => 'ee_edit_question',
117
-                'obj_id'     => $qst_id,
118
-                'args'       => array('edit'),
119
-            ),
120
-
121
-            'question_groups' => array(
122
-                'func'       => '_questions_groups_preview',
123
-                'capability' => 'ee_read_question_groups',
124
-            ),
125
-
126
-            'update_question' => array(
127
-                'func'       => '_insert_or_update_question',
128
-                'args'       => array('new_question' => false),
129
-                'capability' => 'ee_edit_question',
130
-                'obj_id'     => $qst_id,
131
-                'noheader'   => true,
132
-            ),
133
-        );
134
-    }
135
-
136
-
137
-    protected function _set_page_config()
138
-    {
139
-        $this->_page_config = array(
140
-            'default' => array(
141
-                'nav'           => array(
142
-                    'label' => esc_html__('Questions', 'event_espresso'),
143
-                    'order' => 10,
144
-                ),
145
-                'list_table'    => 'Registration_Form_Questions_Admin_List_Table',
146
-                'metaboxes'     => $this->_default_espresso_metaboxes,
147
-                'help_tabs'     => array(
148
-                    'registration_form_questions_overview_help_tab'                           => array(
149
-                        'title'    => esc_html__('Questions Overview', 'event_espresso'),
150
-                        'filename' => 'registration_form_questions_overview',
151
-                    ),
152
-                    'registration_form_questions_overview_table_column_headings_help_tab'     => array(
153
-                        'title'    => esc_html__('Questions Overview Table Column Headings', 'event_espresso'),
154
-                        'filename' => 'registration_form_questions_overview_table_column_headings',
155
-                    ),
156
-                    'registration_form_questions_overview_views_bulk_actions_search_help_tab' => array(
157
-                        'title'    => esc_html__('Question Overview Views & Bulk Actions & Search', 'event_espresso'),
158
-                        'filename' => 'registration_form_questions_overview_views_bulk_actions_search',
159
-                    ),
160
-                ),
161
-                'help_tour'     => array('Registration_Form_Questions_Overview_Help_Tour'),
162
-                'require_nonce' => false,
163
-                'qtips'         => array(
164
-                    'EE_Registration_Form_Tips',
165
-                )/**/
166
-            ),
167
-
168
-            'question_groups' => array(
169
-                'nav'           => array(
170
-                    'label' => esc_html__('Question Groups', 'event_espresso'),
171
-                    'order' => 20,
172
-                ),
173
-                'metaboxes'     => $this->_default_espresso_metaboxes,
174
-                'help_tabs'     => array(
175
-                    'registration_form_question_groups_help_tab' => array(
176
-                        'title'    => esc_html__('Question Groups', 'event_espresso'),
177
-                        'filename' => 'registration_form_question_groups',
178
-                    ),
179
-                ),
180
-                'help_tour'     => array('Registration_Form_Question_Groups_Help_Tour'),
181
-                'require_nonce' => false,
182
-            ),
183
-
184
-            'edit_question' => array(
185
-                'nav'           => array(
186
-                    'label'      => esc_html__('Edit Question', 'event_espresso'),
187
-                    'order'      => 15,
188
-                    'persistent' => false,
189
-                    'url'        => isset($this->_req_data['question_id']) ? add_query_arg(array('question_id' => $this->_req_data['question_id']),
190
-                        $this->_current_page_view_url) : $this->_admin_base_url,
191
-                ),
192
-                'metaboxes'     => array_merge($this->_default_espresso_metaboxes, array('_publish_post_box')),
193
-                'help_tabs'     => array(
194
-                    'registration_form_edit_question_group_help_tab' => array(
195
-                        'title'    => esc_html__('Edit Question', 'event_espresso'),
196
-                        'filename' => 'registration_form_edit_question',
197
-                    ),
198
-                ),
199
-                'help_tour'     => array('Registration_Form_Edit_Question_Help_Tour'),
200
-                'require_nonce' => false,
201
-            ),
202
-        );
203
-    }
204
-
205
-
206
-    protected function _add_screen_options()
207
-    {
208
-        //todo
209
-    }
210
-
211
-    protected function _add_screen_options_default()
212
-    {
213
-        $page_title              = $this->_admin_page_title;
214
-        $this->_admin_page_title = esc_html__('Questions', 'event_espresso');
215
-        $this->_per_page_screen_option();
216
-        $this->_admin_page_title = $page_title;
217
-    }
218
-
219
-    protected function _add_screen_options_question_groups()
220
-    {
221
-        $page_title              = $this->_admin_page_title;
222
-        $this->_admin_page_title = esc_html__('Question Groups', 'event_espresso');
223
-        $this->_per_page_screen_option();
224
-        $this->_admin_page_title = $page_title;
225
-    }
226
-
227
-    //none of the below group are currently used for Event Categories
228
-    protected function _add_feature_pointers()
229
-    {
230
-    }
231
-
232
-    public function load_scripts_styles()
233
-    {
234
-        wp_register_style('espresso_registration',
235
-            REGISTRATION_FORM_ASSETS_URL . 'espresso_registration_form_admin.css', array(), EVENT_ESPRESSO_VERSION);
236
-        wp_enqueue_style('espresso_registration');
237
-    }
238
-
239
-    public function admin_init()
240
-    {
241
-    }
242
-
243
-    public function admin_notices()
244
-    {
245
-    }
246
-
247
-    public function admin_footer_scripts()
248
-    {
249
-    }
250
-
251
-
252
-    public function load_scripts_styles_default()
253
-    {
254
-    }
255
-
256
-
257
-    public function load_scripts_styles_add_question()
258
-    {
259
-        $this->load_scripts_styles_forms();
260
-        wp_register_script('espresso_registration_form_single',
261
-            REGISTRATION_FORM_ASSETS_URL . 'espresso_registration_form_admin.js', array('jquery-ui-sortable'),
262
-            EVENT_ESPRESSO_VERSION, true);
263
-        wp_enqueue_script('espresso_registration_form_single');
264
-    }
265
-
266
-    public function load_scripts_styles_edit_question()
267
-    {
268
-        $this->load_scripts_styles_forms();
269
-        wp_register_script('espresso_registration_form_single',
270
-            REGISTRATION_FORM_ASSETS_URL . 'espresso_registration_form_admin.js', array('jquery-ui-sortable'),
271
-            EVENT_ESPRESSO_VERSION, true);
272
-        wp_enqueue_script('espresso_registration_form_single');
273
-    }
274
-
275
-
276
-    public function recaptcha_info_help_tab()
277
-    {
278
-        $template = REGISTRATION_FORM_TEMPLATE_PATH . 'recaptcha_info_help_tab.template.php';
279
-        EEH_Template::display_template($template, array());
280
-    }
281
-
282
-
283
-    public function load_scripts_styles_forms()
284
-    {
285
-        //styles
286
-        wp_enqueue_style('espresso-ui-theme');
287
-        //scripts
288
-        wp_enqueue_script('ee_admin_js');
289
-    }
290
-
291
-
292
-    protected function _set_list_table_views_default()
293
-    {
294
-        $this->_views = array(
295
-            'all' => array(
296
-                'slug'  => 'all',
297
-                'label' => esc_html__('View All Questions', 'event_espresso'),
298
-                'count' => 0,
31
+	/**
32
+	 * _question
33
+	 * holds the specific question object for the question details screen
34
+	 *
35
+	 * @var EE_Question $_question
36
+	 */
37
+	protected $_question;
38
+
39
+	/**
40
+	 * _question_group
41
+	 * holds the specific question group object for the question group details screen
42
+	 *
43
+	 * @var EE_Question_Group $_question_group
44
+	 */
45
+	protected $_question_group;
46
+
47
+	/**
48
+	 *_question_model EEM_Question model instance (for queries)
49
+	 *
50
+	 * @var EEM_Question $_question_model ;
51
+	 */
52
+	protected $_question_model;
53
+
54
+	/**
55
+	 * _question_group_model EEM_Question_group instance (for queries)
56
+	 *
57
+	 * @var EEM_Question_Group $_question_group_model
58
+	 */
59
+	protected $_question_group_model;
60
+
61
+
62
+	/**
63
+	 * @Constructor
64
+	 * @param bool $routing indicate whether we want to just load the object and handle routing or just load the object.
65
+	 * @access public
66
+	 */
67
+	public function __construct($routing = true)
68
+	{
69
+		require_once(EE_MODELS . 'EEM_Question.model.php');
70
+		require_once(EE_MODELS . 'EEM_Question_Group.model.php');
71
+		$this->_question_model       = EEM_Question::instance();
72
+		$this->_question_group_model = EEM_Question_Group::instance();
73
+		parent::__construct($routing);
74
+	}
75
+
76
+
77
+	protected function _init_page_props()
78
+	{
79
+		$this->page_slug        = REGISTRATION_FORM_PG_SLUG;
80
+		$this->page_label       = esc_html__('Registration Form', 'event_espresso');
81
+		$this->_admin_base_url  = REGISTRATION_FORM_ADMIN_URL;
82
+		$this->_admin_base_path = REGISTRATION_FORM_ADMIN;
83
+	}
84
+
85
+
86
+	protected function _ajax_hooks()
87
+	{
88
+	}
89
+
90
+
91
+	protected function _define_page_props()
92
+	{
93
+		$this->_admin_page_title = esc_html__('Registration Form', 'event_espresso');
94
+		$this->_labels           = array(
95
+			'buttons' => array(
96
+				'edit_question' => esc_html__('Edit Question', 'event_espresso'),
97
+			),
98
+		);
99
+	}
100
+
101
+
102
+	/**
103
+	 *_set_page_routes
104
+	 */
105
+	protected function _set_page_routes()
106
+	{
107
+		$qst_id             = ! empty($this->_req_data['QST_ID']) ? $this->_req_data['QST_ID'] : 0;
108
+		$this->_page_routes = array(
109
+			'default' => array(
110
+				'func'       => '_questions_overview_list_table',
111
+				'capability' => 'ee_read_questions',
112
+			),
113
+
114
+			'edit_question' => array(
115
+				'func'       => '_edit_question',
116
+				'capability' => 'ee_edit_question',
117
+				'obj_id'     => $qst_id,
118
+				'args'       => array('edit'),
119
+			),
120
+
121
+			'question_groups' => array(
122
+				'func'       => '_questions_groups_preview',
123
+				'capability' => 'ee_read_question_groups',
124
+			),
125
+
126
+			'update_question' => array(
127
+				'func'       => '_insert_or_update_question',
128
+				'args'       => array('new_question' => false),
129
+				'capability' => 'ee_edit_question',
130
+				'obj_id'     => $qst_id,
131
+				'noheader'   => true,
132
+			),
133
+		);
134
+	}
135
+
136
+
137
+	protected function _set_page_config()
138
+	{
139
+		$this->_page_config = array(
140
+			'default' => array(
141
+				'nav'           => array(
142
+					'label' => esc_html__('Questions', 'event_espresso'),
143
+					'order' => 10,
144
+				),
145
+				'list_table'    => 'Registration_Form_Questions_Admin_List_Table',
146
+				'metaboxes'     => $this->_default_espresso_metaboxes,
147
+				'help_tabs'     => array(
148
+					'registration_form_questions_overview_help_tab'                           => array(
149
+						'title'    => esc_html__('Questions Overview', 'event_espresso'),
150
+						'filename' => 'registration_form_questions_overview',
151
+					),
152
+					'registration_form_questions_overview_table_column_headings_help_tab'     => array(
153
+						'title'    => esc_html__('Questions Overview Table Column Headings', 'event_espresso'),
154
+						'filename' => 'registration_form_questions_overview_table_column_headings',
155
+					),
156
+					'registration_form_questions_overview_views_bulk_actions_search_help_tab' => array(
157
+						'title'    => esc_html__('Question Overview Views & Bulk Actions & Search', 'event_espresso'),
158
+						'filename' => 'registration_form_questions_overview_views_bulk_actions_search',
159
+					),
160
+				),
161
+				'help_tour'     => array('Registration_Form_Questions_Overview_Help_Tour'),
162
+				'require_nonce' => false,
163
+				'qtips'         => array(
164
+					'EE_Registration_Form_Tips',
165
+				)/**/
166
+			),
167
+
168
+			'question_groups' => array(
169
+				'nav'           => array(
170
+					'label' => esc_html__('Question Groups', 'event_espresso'),
171
+					'order' => 20,
172
+				),
173
+				'metaboxes'     => $this->_default_espresso_metaboxes,
174
+				'help_tabs'     => array(
175
+					'registration_form_question_groups_help_tab' => array(
176
+						'title'    => esc_html__('Question Groups', 'event_espresso'),
177
+						'filename' => 'registration_form_question_groups',
178
+					),
179
+				),
180
+				'help_tour'     => array('Registration_Form_Question_Groups_Help_Tour'),
181
+				'require_nonce' => false,
182
+			),
183
+
184
+			'edit_question' => array(
185
+				'nav'           => array(
186
+					'label'      => esc_html__('Edit Question', 'event_espresso'),
187
+					'order'      => 15,
188
+					'persistent' => false,
189
+					'url'        => isset($this->_req_data['question_id']) ? add_query_arg(array('question_id' => $this->_req_data['question_id']),
190
+						$this->_current_page_view_url) : $this->_admin_base_url,
191
+				),
192
+				'metaboxes'     => array_merge($this->_default_espresso_metaboxes, array('_publish_post_box')),
193
+				'help_tabs'     => array(
194
+					'registration_form_edit_question_group_help_tab' => array(
195
+						'title'    => esc_html__('Edit Question', 'event_espresso'),
196
+						'filename' => 'registration_form_edit_question',
197
+					),
198
+				),
199
+				'help_tour'     => array('Registration_Form_Edit_Question_Help_Tour'),
200
+				'require_nonce' => false,
201
+			),
202
+		);
203
+	}
204
+
205
+
206
+	protected function _add_screen_options()
207
+	{
208
+		//todo
209
+	}
210
+
211
+	protected function _add_screen_options_default()
212
+	{
213
+		$page_title              = $this->_admin_page_title;
214
+		$this->_admin_page_title = esc_html__('Questions', 'event_espresso');
215
+		$this->_per_page_screen_option();
216
+		$this->_admin_page_title = $page_title;
217
+	}
218
+
219
+	protected function _add_screen_options_question_groups()
220
+	{
221
+		$page_title              = $this->_admin_page_title;
222
+		$this->_admin_page_title = esc_html__('Question Groups', 'event_espresso');
223
+		$this->_per_page_screen_option();
224
+		$this->_admin_page_title = $page_title;
225
+	}
226
+
227
+	//none of the below group are currently used for Event Categories
228
+	protected function _add_feature_pointers()
229
+	{
230
+	}
231
+
232
+	public function load_scripts_styles()
233
+	{
234
+		wp_register_style('espresso_registration',
235
+			REGISTRATION_FORM_ASSETS_URL . 'espresso_registration_form_admin.css', array(), EVENT_ESPRESSO_VERSION);
236
+		wp_enqueue_style('espresso_registration');
237
+	}
238
+
239
+	public function admin_init()
240
+	{
241
+	}
242
+
243
+	public function admin_notices()
244
+	{
245
+	}
246
+
247
+	public function admin_footer_scripts()
248
+	{
249
+	}
250
+
251
+
252
+	public function load_scripts_styles_default()
253
+	{
254
+	}
255
+
256
+
257
+	public function load_scripts_styles_add_question()
258
+	{
259
+		$this->load_scripts_styles_forms();
260
+		wp_register_script('espresso_registration_form_single',
261
+			REGISTRATION_FORM_ASSETS_URL . 'espresso_registration_form_admin.js', array('jquery-ui-sortable'),
262
+			EVENT_ESPRESSO_VERSION, true);
263
+		wp_enqueue_script('espresso_registration_form_single');
264
+	}
265
+
266
+	public function load_scripts_styles_edit_question()
267
+	{
268
+		$this->load_scripts_styles_forms();
269
+		wp_register_script('espresso_registration_form_single',
270
+			REGISTRATION_FORM_ASSETS_URL . 'espresso_registration_form_admin.js', array('jquery-ui-sortable'),
271
+			EVENT_ESPRESSO_VERSION, true);
272
+		wp_enqueue_script('espresso_registration_form_single');
273
+	}
274
+
275
+
276
+	public function recaptcha_info_help_tab()
277
+	{
278
+		$template = REGISTRATION_FORM_TEMPLATE_PATH . 'recaptcha_info_help_tab.template.php';
279
+		EEH_Template::display_template($template, array());
280
+	}
281
+
282
+
283
+	public function load_scripts_styles_forms()
284
+	{
285
+		//styles
286
+		wp_enqueue_style('espresso-ui-theme');
287
+		//scripts
288
+		wp_enqueue_script('ee_admin_js');
289
+	}
290
+
291
+
292
+	protected function _set_list_table_views_default()
293
+	{
294
+		$this->_views = array(
295
+			'all' => array(
296
+				'slug'  => 'all',
297
+				'label' => esc_html__('View All Questions', 'event_espresso'),
298
+				'count' => 0,
299 299
 //				'bulk_action' => array(
300 300
 //					'trash_questions' => esc_html__('Trash', 'event_espresso'),
301 301
 //					)
302
-            ),
303
-        );
304
-
305
-        if (EE_Registry::instance()->CAP->current_user_can('ee_delete_questions',
306
-            'espresso_registration_form_trash_questions')
307
-        ) {
308
-            $this->_views['trash'] = array(
309
-                'slug'  => 'trash',
310
-                'label' => esc_html__('Trash', 'event_espresso'),
311
-                'count' => 0,
302
+			),
303
+		);
304
+
305
+		if (EE_Registry::instance()->CAP->current_user_can('ee_delete_questions',
306
+			'espresso_registration_form_trash_questions')
307
+		) {
308
+			$this->_views['trash'] = array(
309
+				'slug'  => 'trash',
310
+				'label' => esc_html__('Trash', 'event_espresso'),
311
+				'count' => 0,
312 312
 //				'bulk_action' => array(
313 313
 //					'delete_questions' => esc_html__('Delete Permanently', 'event_espresso'),
314 314
 //					'restore_questions' => esc_html__('Restore', 'event_espresso'),
315
-            );
316
-        }
317
-    }
318
-
319
-    /**
320
-     * This just previews the question groups tab that comes in caffeinated.
321
-     *
322
-     * @return string html
323
-     */
324
-    protected function _questions_groups_preview()
325
-    {
326
-        $this->_admin_page_title              = esc_html__('Question Groups (Preview)', 'event_espresso');
327
-        $this->_template_args['preview_img']  = '<img src="' . REGISTRATION_FORM_ASSETS_URL . 'caf_reg_form_preview.jpg" alt="' . esc_attr__('Preview Question Groups Overview List Table screenshot',
328
-                'event_espresso') . '" />';
329
-        $this->_template_args['preview_text'] = '<strong>' . esc_html__('Question Groups is a feature that is only available in the premium version of Event Espresso 4 which is available with a support license purchase on EventEspresso.com. With the Question Groups feature you are able to create new question groups, edit existing question groups, and create and edit new questions and add them to question groups.',
330
-                'event_espresso') . '</strong>';
331
-        $this->display_admin_caf_preview_page('question_groups_tab');
332
-    }
333
-
334
-
335
-    /**
336
-     * Extracts the question field's values from the POST request to update or insert them
337
-     *
338
-     * @param \EEM_Base $model
339
-     * @return array where each key is the name of a model's field/db column, and each value is its value.
340
-     */
341
-    protected function _set_column_values_for(EEM_Base $model)
342
-    {
343
-        do_action('AHEE_log', __FILE__, __FUNCTION__, '');
344
-        $set_column_values = array();
345
-
346
-        //some initial checks for proper values.
347
-        //if QST_admin_only, then no matter what QST_required is we disable.
348
-        if (! empty($this->_req_data['QST_admin_only'])) {
349
-            $this->_req_data['QST_required'] = 0;
350
-        }
351
-        foreach ($model->field_settings() as $fieldName => $settings) {
352
-            // basically if QSG_identifier is empty or not set
353
-            if ($fieldName === 'QSG_identifier' && (isset($this->_req_data['QSG_identifier']) && empty($this->_req_data['QSG_identifier']))) {
354
-                $QSG_name                      = isset($this->_req_data['QSG_name']) ? $this->_req_data['QSG_name'] : '';
355
-                $set_column_values[$fieldName] = sanitize_title($QSG_name) . '-' . uniqid('', true);
315
+			);
316
+		}
317
+	}
318
+
319
+	/**
320
+	 * This just previews the question groups tab that comes in caffeinated.
321
+	 *
322
+	 * @return string html
323
+	 */
324
+	protected function _questions_groups_preview()
325
+	{
326
+		$this->_admin_page_title              = esc_html__('Question Groups (Preview)', 'event_espresso');
327
+		$this->_template_args['preview_img']  = '<img src="' . REGISTRATION_FORM_ASSETS_URL . 'caf_reg_form_preview.jpg" alt="' . esc_attr__('Preview Question Groups Overview List Table screenshot',
328
+				'event_espresso') . '" />';
329
+		$this->_template_args['preview_text'] = '<strong>' . esc_html__('Question Groups is a feature that is only available in the premium version of Event Espresso 4 which is available with a support license purchase on EventEspresso.com. With the Question Groups feature you are able to create new question groups, edit existing question groups, and create and edit new questions and add them to question groups.',
330
+				'event_espresso') . '</strong>';
331
+		$this->display_admin_caf_preview_page('question_groups_tab');
332
+	}
333
+
334
+
335
+	/**
336
+	 * Extracts the question field's values from the POST request to update or insert them
337
+	 *
338
+	 * @param \EEM_Base $model
339
+	 * @return array where each key is the name of a model's field/db column, and each value is its value.
340
+	 */
341
+	protected function _set_column_values_for(EEM_Base $model)
342
+	{
343
+		do_action('AHEE_log', __FILE__, __FUNCTION__, '');
344
+		$set_column_values = array();
345
+
346
+		//some initial checks for proper values.
347
+		//if QST_admin_only, then no matter what QST_required is we disable.
348
+		if (! empty($this->_req_data['QST_admin_only'])) {
349
+			$this->_req_data['QST_required'] = 0;
350
+		}
351
+		foreach ($model->field_settings() as $fieldName => $settings) {
352
+			// basically if QSG_identifier is empty or not set
353
+			if ($fieldName === 'QSG_identifier' && (isset($this->_req_data['QSG_identifier']) && empty($this->_req_data['QSG_identifier']))) {
354
+				$QSG_name                      = isset($this->_req_data['QSG_name']) ? $this->_req_data['QSG_name'] : '';
355
+				$set_column_values[$fieldName] = sanitize_title($QSG_name) . '-' . uniqid('', true);
356 356
 //				dd($set_column_values);
357
-            } //if the admin label is blank, use a slug version of the question text
358
-            else if ($fieldName === 'QST_admin_label' && (isset($this->_req_data['QST_admin_label']) && empty($this->_req_data['QST_admin_label']))) {
359
-                $QST_text                      = isset($this->_req_data['QST_display_text']) ? $this->_req_data['QST_display_text'] : '';
360
-                $set_column_values[$fieldName] = sanitize_title(wp_trim_words($QST_text, 10));
361
-            } else if ($fieldName === 'QST_admin_only' && (! isset($this->_req_data['QST_admin_only']))) {
362
-                $set_column_values[$fieldName] = 0;
363
-            } else if ($fieldName === 'QST_max') {
364
-                $qst_system = EEM_Question::instance()->get_var(
365
-                    array(
366
-                        array(
367
-                            'QST_ID' => isset($this->_req_data['QST_ID']) ? $this->_req_data['QST_ID'] : 0,
368
-                        ),
369
-                    ),
370
-                    'QST_system');
371
-                $max_max    = EEM_Question::instance()->absolute_max_for_system_question($qst_system);
372
-                if (empty($this->_req_data['QST_max']) ||
373
-                    $this->_req_data['QST_max'] > $max_max
374
-                ) {
375
-                    $set_column_values[$fieldName] = $max_max;
376
-                }
377
-            }
378
-
379
-
380
-            //only add a property to the array if it's not null (otherwise the model should just use the default value)
381
-            if (
382
-                ! isset($set_column_values[$fieldName]) &&
383
-                isset($this->_req_data[$fieldName])
384
-            ) {
385
-                $set_column_values[$fieldName] = $this->_req_data[$fieldName];
386
-            }
387
-
388
-        }
389
-        return $set_column_values;//validation fo this data to be performed by the model before insertion.
390
-    }
391
-
392
-
393
-    /**
394
-     *_questions_overview_list_table
395
-     */
396
-    protected function _questions_overview_list_table()
397
-    {
398
-        $this->_search_btn_label = esc_html__('Questions', 'event_espresso');
399
-        $this->display_admin_list_table_page_with_sidebar();
400
-    }
401
-
402
-
403
-    /**
404
-     * _edit_question
405
-     */
406
-    protected function _edit_question()
407
-    {
408
-        do_action('AHEE_log', __FILE__, __FUNCTION__, '');
409
-        $ID = isset($this->_req_data['QST_ID']) && ! empty($this->_req_data['QST_ID']) ? absint($this->_req_data['QST_ID']) : false;
410
-
411
-        switch ($this->_req_action) {
412
-            case 'add_question' :
413
-                $this->_admin_page_title = esc_html__('Add Question', 'event_espresso');
414
-                break;
415
-            case 'edit_question' :
416
-                $this->_admin_page_title = esc_html__('Edit Question', 'event_espresso');
417
-                break;
418
-            default :
419
-                $this->_admin_page_title = ucwords(str_replace('_', ' ', $this->_req_action));
420
-        }
421
-
422
-        // add PRC_ID to title if editing
423
-        $this->_admin_page_title = $ID ? $this->_admin_page_title . ' # ' . $ID : $this->_admin_page_title;
424
-        if ($ID) {
425
-            $question                 = $this->_question_model->get_one_by_ID($ID);
426
-            $additional_hidden_fields = array('QST_ID' => array('type' => 'hidden', 'value' => $ID));
427
-            $this->_set_add_edit_form_tags('update_question', $additional_hidden_fields);
428
-        } else {
429
-            $question = EE_Question::new_instance();
430
-            $question->set_order_to_latest();
431
-            $this->_set_add_edit_form_tags('insert_question');
432
-        }
433
-        if( $question->system_ID() === EEM_Attendee::system_question_phone ){
434
-            $question_types = array_intersect_key(
435
-                EEM_Question::instance()->allowed_question_types(),
436
-                array_flip(
437
-                    array(
438
-                        EEM_Question::QST_type_text,
439
-                        EEM_Question::QST_type_us_phone
440
-                    )
441
-                )
442
-            );
443
-        } else {
444
-            $question_types = $question->has_answers() ? $this->_question_model->question_types_in_same_category($question->type()) : $this->_question_model->allowed_question_types();
445
-        }
446
-        $this->_template_args['QST_ID']                     = $ID;
447
-        $this->_template_args['question']                   = $question;
448
-        $this->_template_args['question_types']             = $question_types;
449
-        $this->_template_args['max_max']                    = EEM_Question::instance()->absolute_max_for_system_question(
450
-            $question->system_ID()
451
-        );
452
-        $this->_template_args['question_type_descriptions'] = $this->_get_question_type_descriptions();
453
-        $this->_set_publish_post_box_vars('id', $ID);
454
-        $this->_template_args['admin_page_content'] = EEH_Template::display_template(
455
-            REGISTRATION_FORM_TEMPLATE_PATH . 'questions_main_meta_box.template.php',
456
-            $this->_template_args, true
457
-        );
458
-
459
-        // the details template wrapper
460
-        $this->display_admin_page_with_sidebar();
461
-    }
462
-
463
-
464
-    /**
465
-     * @return string
466
-     */
467
-    protected function _get_question_type_descriptions()
468
-    {
469
-        EE_Registry::instance()->load_helper('HTML');
470
-        $descriptions               = '';
471
-        $question_type_descriptions = EEM_Question::instance()->question_descriptions();
472
-        foreach ($question_type_descriptions as $type => $question_type_description) {
473
-            if ($type == 'HTML_TEXTAREA') {
474
-                $html = new EE_Simple_HTML_Validation_Strategy();
475
-                $question_type_description .= sprintf(
476
-                    esc_html__('%1$s(allowed tags: %2$s)', 'event_espresso'),
477
-                    '<br/>',
478
-                    $html->get_list_of_allowed_tags()
479
-                );
480
-            }
481
-            $descriptions .= EEH_HTML::p(
482
-                $question_type_description,
483
-                'question_type_description-' . $type,
484
-                'question_type_description description',
485
-                'display:none;'
486
-            );
487
-        }
488
-        return $descriptions;
489
-    }
490
-
491
-
492
-    /**
493
-     * @param bool|true $new_question
494
-     * @throws \EE_Error
495
-     */
496
-    protected function _insert_or_update_question($new_question = true)
497
-    {
498
-        do_action('AHEE_log', __FILE__, __FUNCTION__, '');
499
-        $set_column_values = $this->_set_column_values_for($this->_question_model);
500
-        if ($new_question) {
501
-            $question = EE_Question::new_instance($set_column_values);
502
-            $action_desc = 'added';
503
-        } else {
504
-            $question     = EEM_Question::instance()->get_one_by_ID(absint($this->_req_data['QST_ID']));
505
-            foreach($set_column_values as $field => $new_value) {
506
-                $question->set($field, $new_value);
507
-            }
508
-            $action_desc = 'updated';
509
-        }
510
-        $success = $question->save();
511
-        $ID = $question->ID();
512
-        if ($ID && $question->should_have_question_options()) {
513
-            //save the related options
514
-            //trash removed options, save old ones
515
-            //get list of all options
516
-            $options  = $question->options();
517
-            if (! empty($options)) {
518
-                foreach ($options as $option_ID => $option) {
519
-                    $option_req_index = $this->_get_option_req_data_index($option_ID);
520
-                    if ($option_req_index !== false) {
521
-                        $option->save($this->_req_data['question_options'][$option_req_index]);
522
-                    } else {
523
-                        //not found, remove it
524
-                        $option->delete();
525
-                    }
526
-                }
527
-            }
528
-            //save new related options
529
-            foreach ($this->_req_data['question_options'] as $index => $option_req_data) {
530
-                //skip $index that is from our sample
531
-                if ( $index === 'xxcountxx' ) {
532
-                    continue;
533
-                }
534
-                //note we allow saving blank options.
535
-                if (empty($option_req_data['QSO_ID'])
536
-                ) {//no ID! save it!
537
-                    $new_option = EE_Question_Option::new_instance(array(
538
-                        'QSO_value' => $option_req_data['QSO_value'],
539
-                        'QSO_desc'  => $option_req_data['QSO_desc'],
540
-                        'QSO_order' => $option_req_data['QSO_order'],
541
-                        'QST_ID'    => $question->ID(),
542
-                    ));
543
-                    $new_option->save();
544
-                }
545
-            }
546
-        }
547
-        $query_args = array('action' => 'edit_question', 'QST_ID' => $ID);
548
-        if ($success !== false) {
549
-            $msg = $new_question ? sprintf(esc_html__('The %s has been created', 'event_espresso'),
550
-                $this->_question_model->item_name()) : sprintf(esc_html__('The %s has been updated', 'event_espresso'),
551
-                $this->_question_model->item_name());
552
-            EE_Error::add_success($msg);
553
-        }
554
-
555
-        $this->_redirect_after_action(false, '', $action_desc, $query_args, true);
556
-    }
557
-
558
-
559
-    /**
560
-     * Upon saving a question, there should be an array of 'question_options'. This array is index numerically, but not
561
-     * by ID
562
-     * (this is done because new question options don't have an ID, but we may want to add multiple simultaneously).
563
-     * So, this function gets the index in that request data array called question_options. Returns FALSE if not found.
564
-     *
565
-     * @param int $ID of the question option to find
566
-     * @return int index in question_options array if successful, FALSE if unsuccessful
567
-     */
568
-    protected function _get_option_req_data_index($ID)
569
-    {
570
-        $req_data_for_question_options = $this->_req_data['question_options'];
571
-        foreach ($req_data_for_question_options as $num => $option_data) {
572
-            if (array_key_exists('QSO_ID', $option_data) && (int)$option_data['QSO_ID'] === $ID) {
573
-                return $num;
574
-            }
575
-        }
576
-        return false;
577
-    }
578
-
579
-
580
-
581
-
582
-    /***********/
583
-    /* QUERIES */
584
-    /**
585
-     * For internal use in getting all the query parameters
586
-     * (because it's pretty well the same between question, question groups,
587
-     * and for both when searching for trashed and untrashed ones)
588
-     *
589
-     * @param EEM_Base $model either EEM_Question or EEM_Question_Group
590
-     * @param int      $per_page
591
-     * @param int      $current_page
592
-     * @return array lik EEM_Base::get_all's $query_params parameter
593
-     */
594
-    protected function get_query_params($model, $per_page = 10, $current_page = 10)
595
-    {
596
-        $query_params             = array();
597
-        $offset                   = ($current_page - 1) * $per_page;
598
-        $query_params['limit']    = array($offset, $per_page);
599
-        $order                    = (isset($this->_req_data['order']) && ! empty($this->_req_data['order'])) ? $this->_req_data['order'] : 'ASC';
600
-        $orderby_field            = $model instanceof EEM_Question ? 'QST_ID' : 'QSG_order';
601
-        $field_to_order_by        = empty($this->_req_data['orderby']) ? $orderby_field : $this->_req_data['orderby'];
602
-        $query_params['order_by'] = array($field_to_order_by => $order);
603
-        $search_string            = array_key_exists('s', $this->_req_data) ? $this->_req_data['s'] : null;
604
-        if (! empty($search_string)) {
605
-            if ($model instanceof EEM_Question_Group) {
606
-                $query_params[0] = array(
607
-                    'OR' => array(
608
-                        'QSG_name' => array('LIKE', "%$search_string%"),
609
-                        'QSG_desc' => array('LIKE', "%$search_string%"),
610
-                    ),
611
-                );
612
-            } else {
613
-                $query_params[0] = array(
614
-                    'QST_display_text' => array('LIKE', "%$search_string%"),
615
-                );
616
-            }
617
-        }
618
-
619
-        //capability checks (just leaving this commented out for reference because it illustrates some complicated query params that could be useful when fully implemented)
620
-        /*if ( $model instanceof EEM_Question_Group ) {
357
+			} //if the admin label is blank, use a slug version of the question text
358
+			else if ($fieldName === 'QST_admin_label' && (isset($this->_req_data['QST_admin_label']) && empty($this->_req_data['QST_admin_label']))) {
359
+				$QST_text                      = isset($this->_req_data['QST_display_text']) ? $this->_req_data['QST_display_text'] : '';
360
+				$set_column_values[$fieldName] = sanitize_title(wp_trim_words($QST_text, 10));
361
+			} else if ($fieldName === 'QST_admin_only' && (! isset($this->_req_data['QST_admin_only']))) {
362
+				$set_column_values[$fieldName] = 0;
363
+			} else if ($fieldName === 'QST_max') {
364
+				$qst_system = EEM_Question::instance()->get_var(
365
+					array(
366
+						array(
367
+							'QST_ID' => isset($this->_req_data['QST_ID']) ? $this->_req_data['QST_ID'] : 0,
368
+						),
369
+					),
370
+					'QST_system');
371
+				$max_max    = EEM_Question::instance()->absolute_max_for_system_question($qst_system);
372
+				if (empty($this->_req_data['QST_max']) ||
373
+					$this->_req_data['QST_max'] > $max_max
374
+				) {
375
+					$set_column_values[$fieldName] = $max_max;
376
+				}
377
+			}
378
+
379
+
380
+			//only add a property to the array if it's not null (otherwise the model should just use the default value)
381
+			if (
382
+				! isset($set_column_values[$fieldName]) &&
383
+				isset($this->_req_data[$fieldName])
384
+			) {
385
+				$set_column_values[$fieldName] = $this->_req_data[$fieldName];
386
+			}
387
+
388
+		}
389
+		return $set_column_values;//validation fo this data to be performed by the model before insertion.
390
+	}
391
+
392
+
393
+	/**
394
+	 *_questions_overview_list_table
395
+	 */
396
+	protected function _questions_overview_list_table()
397
+	{
398
+		$this->_search_btn_label = esc_html__('Questions', 'event_espresso');
399
+		$this->display_admin_list_table_page_with_sidebar();
400
+	}
401
+
402
+
403
+	/**
404
+	 * _edit_question
405
+	 */
406
+	protected function _edit_question()
407
+	{
408
+		do_action('AHEE_log', __FILE__, __FUNCTION__, '');
409
+		$ID = isset($this->_req_data['QST_ID']) && ! empty($this->_req_data['QST_ID']) ? absint($this->_req_data['QST_ID']) : false;
410
+
411
+		switch ($this->_req_action) {
412
+			case 'add_question' :
413
+				$this->_admin_page_title = esc_html__('Add Question', 'event_espresso');
414
+				break;
415
+			case 'edit_question' :
416
+				$this->_admin_page_title = esc_html__('Edit Question', 'event_espresso');
417
+				break;
418
+			default :
419
+				$this->_admin_page_title = ucwords(str_replace('_', ' ', $this->_req_action));
420
+		}
421
+
422
+		// add PRC_ID to title if editing
423
+		$this->_admin_page_title = $ID ? $this->_admin_page_title . ' # ' . $ID : $this->_admin_page_title;
424
+		if ($ID) {
425
+			$question                 = $this->_question_model->get_one_by_ID($ID);
426
+			$additional_hidden_fields = array('QST_ID' => array('type' => 'hidden', 'value' => $ID));
427
+			$this->_set_add_edit_form_tags('update_question', $additional_hidden_fields);
428
+		} else {
429
+			$question = EE_Question::new_instance();
430
+			$question->set_order_to_latest();
431
+			$this->_set_add_edit_form_tags('insert_question');
432
+		}
433
+		if( $question->system_ID() === EEM_Attendee::system_question_phone ){
434
+			$question_types = array_intersect_key(
435
+				EEM_Question::instance()->allowed_question_types(),
436
+				array_flip(
437
+					array(
438
+						EEM_Question::QST_type_text,
439
+						EEM_Question::QST_type_us_phone
440
+					)
441
+				)
442
+			);
443
+		} else {
444
+			$question_types = $question->has_answers() ? $this->_question_model->question_types_in_same_category($question->type()) : $this->_question_model->allowed_question_types();
445
+		}
446
+		$this->_template_args['QST_ID']                     = $ID;
447
+		$this->_template_args['question']                   = $question;
448
+		$this->_template_args['question_types']             = $question_types;
449
+		$this->_template_args['max_max']                    = EEM_Question::instance()->absolute_max_for_system_question(
450
+			$question->system_ID()
451
+		);
452
+		$this->_template_args['question_type_descriptions'] = $this->_get_question_type_descriptions();
453
+		$this->_set_publish_post_box_vars('id', $ID);
454
+		$this->_template_args['admin_page_content'] = EEH_Template::display_template(
455
+			REGISTRATION_FORM_TEMPLATE_PATH . 'questions_main_meta_box.template.php',
456
+			$this->_template_args, true
457
+		);
458
+
459
+		// the details template wrapper
460
+		$this->display_admin_page_with_sidebar();
461
+	}
462
+
463
+
464
+	/**
465
+	 * @return string
466
+	 */
467
+	protected function _get_question_type_descriptions()
468
+	{
469
+		EE_Registry::instance()->load_helper('HTML');
470
+		$descriptions               = '';
471
+		$question_type_descriptions = EEM_Question::instance()->question_descriptions();
472
+		foreach ($question_type_descriptions as $type => $question_type_description) {
473
+			if ($type == 'HTML_TEXTAREA') {
474
+				$html = new EE_Simple_HTML_Validation_Strategy();
475
+				$question_type_description .= sprintf(
476
+					esc_html__('%1$s(allowed tags: %2$s)', 'event_espresso'),
477
+					'<br/>',
478
+					$html->get_list_of_allowed_tags()
479
+				);
480
+			}
481
+			$descriptions .= EEH_HTML::p(
482
+				$question_type_description,
483
+				'question_type_description-' . $type,
484
+				'question_type_description description',
485
+				'display:none;'
486
+			);
487
+		}
488
+		return $descriptions;
489
+	}
490
+
491
+
492
+	/**
493
+	 * @param bool|true $new_question
494
+	 * @throws \EE_Error
495
+	 */
496
+	protected function _insert_or_update_question($new_question = true)
497
+	{
498
+		do_action('AHEE_log', __FILE__, __FUNCTION__, '');
499
+		$set_column_values = $this->_set_column_values_for($this->_question_model);
500
+		if ($new_question) {
501
+			$question = EE_Question::new_instance($set_column_values);
502
+			$action_desc = 'added';
503
+		} else {
504
+			$question     = EEM_Question::instance()->get_one_by_ID(absint($this->_req_data['QST_ID']));
505
+			foreach($set_column_values as $field => $new_value) {
506
+				$question->set($field, $new_value);
507
+			}
508
+			$action_desc = 'updated';
509
+		}
510
+		$success = $question->save();
511
+		$ID = $question->ID();
512
+		if ($ID && $question->should_have_question_options()) {
513
+			//save the related options
514
+			//trash removed options, save old ones
515
+			//get list of all options
516
+			$options  = $question->options();
517
+			if (! empty($options)) {
518
+				foreach ($options as $option_ID => $option) {
519
+					$option_req_index = $this->_get_option_req_data_index($option_ID);
520
+					if ($option_req_index !== false) {
521
+						$option->save($this->_req_data['question_options'][$option_req_index]);
522
+					} else {
523
+						//not found, remove it
524
+						$option->delete();
525
+					}
526
+				}
527
+			}
528
+			//save new related options
529
+			foreach ($this->_req_data['question_options'] as $index => $option_req_data) {
530
+				//skip $index that is from our sample
531
+				if ( $index === 'xxcountxx' ) {
532
+					continue;
533
+				}
534
+				//note we allow saving blank options.
535
+				if (empty($option_req_data['QSO_ID'])
536
+				) {//no ID! save it!
537
+					$new_option = EE_Question_Option::new_instance(array(
538
+						'QSO_value' => $option_req_data['QSO_value'],
539
+						'QSO_desc'  => $option_req_data['QSO_desc'],
540
+						'QSO_order' => $option_req_data['QSO_order'],
541
+						'QST_ID'    => $question->ID(),
542
+					));
543
+					$new_option->save();
544
+				}
545
+			}
546
+		}
547
+		$query_args = array('action' => 'edit_question', 'QST_ID' => $ID);
548
+		if ($success !== false) {
549
+			$msg = $new_question ? sprintf(esc_html__('The %s has been created', 'event_espresso'),
550
+				$this->_question_model->item_name()) : sprintf(esc_html__('The %s has been updated', 'event_espresso'),
551
+				$this->_question_model->item_name());
552
+			EE_Error::add_success($msg);
553
+		}
554
+
555
+		$this->_redirect_after_action(false, '', $action_desc, $query_args, true);
556
+	}
557
+
558
+
559
+	/**
560
+	 * Upon saving a question, there should be an array of 'question_options'. This array is index numerically, but not
561
+	 * by ID
562
+	 * (this is done because new question options don't have an ID, but we may want to add multiple simultaneously).
563
+	 * So, this function gets the index in that request data array called question_options. Returns FALSE if not found.
564
+	 *
565
+	 * @param int $ID of the question option to find
566
+	 * @return int index in question_options array if successful, FALSE if unsuccessful
567
+	 */
568
+	protected function _get_option_req_data_index($ID)
569
+	{
570
+		$req_data_for_question_options = $this->_req_data['question_options'];
571
+		foreach ($req_data_for_question_options as $num => $option_data) {
572
+			if (array_key_exists('QSO_ID', $option_data) && (int)$option_data['QSO_ID'] === $ID) {
573
+				return $num;
574
+			}
575
+		}
576
+		return false;
577
+	}
578
+
579
+
580
+
581
+
582
+	/***********/
583
+	/* QUERIES */
584
+	/**
585
+	 * For internal use in getting all the query parameters
586
+	 * (because it's pretty well the same between question, question groups,
587
+	 * and for both when searching for trashed and untrashed ones)
588
+	 *
589
+	 * @param EEM_Base $model either EEM_Question or EEM_Question_Group
590
+	 * @param int      $per_page
591
+	 * @param int      $current_page
592
+	 * @return array lik EEM_Base::get_all's $query_params parameter
593
+	 */
594
+	protected function get_query_params($model, $per_page = 10, $current_page = 10)
595
+	{
596
+		$query_params             = array();
597
+		$offset                   = ($current_page - 1) * $per_page;
598
+		$query_params['limit']    = array($offset, $per_page);
599
+		$order                    = (isset($this->_req_data['order']) && ! empty($this->_req_data['order'])) ? $this->_req_data['order'] : 'ASC';
600
+		$orderby_field            = $model instanceof EEM_Question ? 'QST_ID' : 'QSG_order';
601
+		$field_to_order_by        = empty($this->_req_data['orderby']) ? $orderby_field : $this->_req_data['orderby'];
602
+		$query_params['order_by'] = array($field_to_order_by => $order);
603
+		$search_string            = array_key_exists('s', $this->_req_data) ? $this->_req_data['s'] : null;
604
+		if (! empty($search_string)) {
605
+			if ($model instanceof EEM_Question_Group) {
606
+				$query_params[0] = array(
607
+					'OR' => array(
608
+						'QSG_name' => array('LIKE', "%$search_string%"),
609
+						'QSG_desc' => array('LIKE', "%$search_string%"),
610
+					),
611
+				);
612
+			} else {
613
+				$query_params[0] = array(
614
+					'QST_display_text' => array('LIKE', "%$search_string%"),
615
+				);
616
+			}
617
+		}
618
+
619
+		//capability checks (just leaving this commented out for reference because it illustrates some complicated query params that could be useful when fully implemented)
620
+		/*if ( $model instanceof EEM_Question_Group ) {
621 621
             if ( ! EE_Registry::instance()->CAP->current_user_can( 'edit_others_question_groups', 'espresso_registration_form_edit_question_group' ) ) {
622 622
                 $query_params[0] = array(
623 623
                     'AND' => array(
@@ -647,62 +647,62 @@  discard block
 block discarded – undo
647 647
             }
648 648
         }/**/
649 649
 
650
-        return $query_params;
651
-
652
-    }
653
-
654
-
655
-    /**
656
-     * @param int        $per_page
657
-     * @param int        $current_page
658
-     * @param bool|false $count
659
-     * @return \EE_Soft_Delete_Base_Class[]|int
660
-     */
661
-    public function get_questions($per_page = 10, $current_page = 1, $count = false)
662
-    {
663
-        $QST          = EEM_Question::instance();
664
-        $query_params = $this->get_query_params($QST, $per_page, $current_page);
665
-        if ($count) {
666
-            $where   = isset($query_params[0]) ? array($query_params[0]) : array();
667
-            $results = $QST->count($where);
668
-        } else {
669
-            $results = $QST->get_all($query_params);
670
-        }
671
-        return $results;
672
-
673
-    }
674
-
675
-
676
-    /**
677
-     * @param            $per_page
678
-     * @param int        $current_page
679
-     * @param bool|false $count
680
-     * @return \EE_Soft_Delete_Base_Class[]|int
681
-     */
682
-    public function get_trashed_questions($per_page, $current_page = 1, $count = false)
683
-    {
684
-        $query_params = $this->get_query_params(EEM_Question::instance(), $per_page, $current_page);
685
-        $where        = isset($query_params[0]) ? array($query_params[0]) : array();
686
-        $questions    = $count ? EEM_Question::instance()->count_deleted($where) : EEM_Question::instance()->get_all_deleted($query_params);
687
-        return $questions;
688
-    }
689
-
690
-
691
-    /**
692
-     * @param            $per_page
693
-     * @param int        $current_page
694
-     * @param bool|false $count
695
-     * @return \EE_Soft_Delete_Base_Class[]
696
-     */
697
-    public function get_question_groups($per_page, $current_page = 1, $count = false)
698
-    {
699
-        /** @type EEM_Question_Group $questionGroupModel */
700
-        $questionGroupModel = EEM_Question_Group::instance();
701
-        //note: this a subclass of EEM_Soft_Delete_Base, so this is actually only getting non-trashed items
702
-        return $questionGroupModel->get_all(
703
-            $this->get_query_params($questionGroupModel, $per_page, $current_page)
704
-        );
705
-    }
650
+		return $query_params;
651
+
652
+	}
653
+
654
+
655
+	/**
656
+	 * @param int        $per_page
657
+	 * @param int        $current_page
658
+	 * @param bool|false $count
659
+	 * @return \EE_Soft_Delete_Base_Class[]|int
660
+	 */
661
+	public function get_questions($per_page = 10, $current_page = 1, $count = false)
662
+	{
663
+		$QST          = EEM_Question::instance();
664
+		$query_params = $this->get_query_params($QST, $per_page, $current_page);
665
+		if ($count) {
666
+			$where   = isset($query_params[0]) ? array($query_params[0]) : array();
667
+			$results = $QST->count($where);
668
+		} else {
669
+			$results = $QST->get_all($query_params);
670
+		}
671
+		return $results;
672
+
673
+	}
674
+
675
+
676
+	/**
677
+	 * @param            $per_page
678
+	 * @param int        $current_page
679
+	 * @param bool|false $count
680
+	 * @return \EE_Soft_Delete_Base_Class[]|int
681
+	 */
682
+	public function get_trashed_questions($per_page, $current_page = 1, $count = false)
683
+	{
684
+		$query_params = $this->get_query_params(EEM_Question::instance(), $per_page, $current_page);
685
+		$where        = isset($query_params[0]) ? array($query_params[0]) : array();
686
+		$questions    = $count ? EEM_Question::instance()->count_deleted($where) : EEM_Question::instance()->get_all_deleted($query_params);
687
+		return $questions;
688
+	}
689
+
690
+
691
+	/**
692
+	 * @param            $per_page
693
+	 * @param int        $current_page
694
+	 * @param bool|false $count
695
+	 * @return \EE_Soft_Delete_Base_Class[]
696
+	 */
697
+	public function get_question_groups($per_page, $current_page = 1, $count = false)
698
+	{
699
+		/** @type EEM_Question_Group $questionGroupModel */
700
+		$questionGroupModel = EEM_Question_Group::instance();
701
+		//note: this a subclass of EEM_Soft_Delete_Base, so this is actually only getting non-trashed items
702
+		return $questionGroupModel->get_all(
703
+			$this->get_query_params($questionGroupModel, $per_page, $current_page)
704
+		);
705
+	}
706 706
 
707 707
 
708 708
 } //ends Registration_Form_Admin_Page class
Please login to merge, or discard this patch.
Spacing   +27 added lines, -27 removed lines patch added patch discarded remove patch
@@ -1,5 +1,5 @@  discard block
 block discarded – undo
1 1
 <?php
2
-if (! defined('EVENT_ESPRESSO_VERSION')) {
2
+if ( ! defined('EVENT_ESPRESSO_VERSION')) {
3 3
     exit('NO direct script access allowed');
4 4
 }
5 5
 
@@ -66,8 +66,8 @@  discard block
 block discarded – undo
66 66
      */
67 67
     public function __construct($routing = true)
68 68
     {
69
-        require_once(EE_MODELS . 'EEM_Question.model.php');
70
-        require_once(EE_MODELS . 'EEM_Question_Group.model.php');
69
+        require_once(EE_MODELS.'EEM_Question.model.php');
70
+        require_once(EE_MODELS.'EEM_Question_Group.model.php');
71 71
         $this->_question_model       = EEM_Question::instance();
72 72
         $this->_question_group_model = EEM_Question_Group::instance();
73 73
         parent::__construct($routing);
@@ -232,7 +232,7 @@  discard block
 block discarded – undo
232 232
     public function load_scripts_styles()
233 233
     {
234 234
         wp_register_style('espresso_registration',
235
-            REGISTRATION_FORM_ASSETS_URL . 'espresso_registration_form_admin.css', array(), EVENT_ESPRESSO_VERSION);
235
+            REGISTRATION_FORM_ASSETS_URL.'espresso_registration_form_admin.css', array(), EVENT_ESPRESSO_VERSION);
236 236
         wp_enqueue_style('espresso_registration');
237 237
     }
238 238
 
@@ -258,7 +258,7 @@  discard block
 block discarded – undo
258 258
     {
259 259
         $this->load_scripts_styles_forms();
260 260
         wp_register_script('espresso_registration_form_single',
261
-            REGISTRATION_FORM_ASSETS_URL . 'espresso_registration_form_admin.js', array('jquery-ui-sortable'),
261
+            REGISTRATION_FORM_ASSETS_URL.'espresso_registration_form_admin.js', array('jquery-ui-sortable'),
262 262
             EVENT_ESPRESSO_VERSION, true);
263 263
         wp_enqueue_script('espresso_registration_form_single');
264 264
     }
@@ -267,7 +267,7 @@  discard block
 block discarded – undo
267 267
     {
268 268
         $this->load_scripts_styles_forms();
269 269
         wp_register_script('espresso_registration_form_single',
270
-            REGISTRATION_FORM_ASSETS_URL . 'espresso_registration_form_admin.js', array('jquery-ui-sortable'),
270
+            REGISTRATION_FORM_ASSETS_URL.'espresso_registration_form_admin.js', array('jquery-ui-sortable'),
271 271
             EVENT_ESPRESSO_VERSION, true);
272 272
         wp_enqueue_script('espresso_registration_form_single');
273 273
     }
@@ -275,7 +275,7 @@  discard block
 block discarded – undo
275 275
 
276 276
     public function recaptcha_info_help_tab()
277 277
     {
278
-        $template = REGISTRATION_FORM_TEMPLATE_PATH . 'recaptcha_info_help_tab.template.php';
278
+        $template = REGISTRATION_FORM_TEMPLATE_PATH.'recaptcha_info_help_tab.template.php';
279 279
         EEH_Template::display_template($template, array());
280 280
     }
281 281
 
@@ -324,10 +324,10 @@  discard block
 block discarded – undo
324 324
     protected function _questions_groups_preview()
325 325
     {
326 326
         $this->_admin_page_title              = esc_html__('Question Groups (Preview)', 'event_espresso');
327
-        $this->_template_args['preview_img']  = '<img src="' . REGISTRATION_FORM_ASSETS_URL . 'caf_reg_form_preview.jpg" alt="' . esc_attr__('Preview Question Groups Overview List Table screenshot',
328
-                'event_espresso') . '" />';
329
-        $this->_template_args['preview_text'] = '<strong>' . esc_html__('Question Groups is a feature that is only available in the premium version of Event Espresso 4 which is available with a support license purchase on EventEspresso.com. With the Question Groups feature you are able to create new question groups, edit existing question groups, and create and edit new questions and add them to question groups.',
330
-                'event_espresso') . '</strong>';
327
+        $this->_template_args['preview_img']  = '<img src="'.REGISTRATION_FORM_ASSETS_URL.'caf_reg_form_preview.jpg" alt="'.esc_attr__('Preview Question Groups Overview List Table screenshot',
328
+                'event_espresso').'" />';
329
+        $this->_template_args['preview_text'] = '<strong>'.esc_html__('Question Groups is a feature that is only available in the premium version of Event Espresso 4 which is available with a support license purchase on EventEspresso.com. With the Question Groups feature you are able to create new question groups, edit existing question groups, and create and edit new questions and add them to question groups.',
330
+                'event_espresso').'</strong>';
331 331
         $this->display_admin_caf_preview_page('question_groups_tab');
332 332
     }
333 333
 
@@ -345,20 +345,20 @@  discard block
 block discarded – undo
345 345
 
346 346
         //some initial checks for proper values.
347 347
         //if QST_admin_only, then no matter what QST_required is we disable.
348
-        if (! empty($this->_req_data['QST_admin_only'])) {
348
+        if ( ! empty($this->_req_data['QST_admin_only'])) {
349 349
             $this->_req_data['QST_required'] = 0;
350 350
         }
351 351
         foreach ($model->field_settings() as $fieldName => $settings) {
352 352
             // basically if QSG_identifier is empty or not set
353 353
             if ($fieldName === 'QSG_identifier' && (isset($this->_req_data['QSG_identifier']) && empty($this->_req_data['QSG_identifier']))) {
354 354
                 $QSG_name                      = isset($this->_req_data['QSG_name']) ? $this->_req_data['QSG_name'] : '';
355
-                $set_column_values[$fieldName] = sanitize_title($QSG_name) . '-' . uniqid('', true);
355
+                $set_column_values[$fieldName] = sanitize_title($QSG_name).'-'.uniqid('', true);
356 356
 //				dd($set_column_values);
357 357
             } //if the admin label is blank, use a slug version of the question text
358 358
             else if ($fieldName === 'QST_admin_label' && (isset($this->_req_data['QST_admin_label']) && empty($this->_req_data['QST_admin_label']))) {
359 359
                 $QST_text                      = isset($this->_req_data['QST_display_text']) ? $this->_req_data['QST_display_text'] : '';
360 360
                 $set_column_values[$fieldName] = sanitize_title(wp_trim_words($QST_text, 10));
361
-            } else if ($fieldName === 'QST_admin_only' && (! isset($this->_req_data['QST_admin_only']))) {
361
+            } else if ($fieldName === 'QST_admin_only' && ( ! isset($this->_req_data['QST_admin_only']))) {
362 362
                 $set_column_values[$fieldName] = 0;
363 363
             } else if ($fieldName === 'QST_max') {
364 364
                 $qst_system = EEM_Question::instance()->get_var(
@@ -368,7 +368,7 @@  discard block
 block discarded – undo
368 368
                         ),
369 369
                     ),
370 370
                     'QST_system');
371
-                $max_max    = EEM_Question::instance()->absolute_max_for_system_question($qst_system);
371
+                $max_max = EEM_Question::instance()->absolute_max_for_system_question($qst_system);
372 372
                 if (empty($this->_req_data['QST_max']) ||
373 373
                     $this->_req_data['QST_max'] > $max_max
374 374
                 ) {
@@ -386,7 +386,7 @@  discard block
 block discarded – undo
386 386
             }
387 387
 
388 388
         }
389
-        return $set_column_values;//validation fo this data to be performed by the model before insertion.
389
+        return $set_column_values; //validation fo this data to be performed by the model before insertion.
390 390
     }
391 391
 
392 392
 
@@ -420,7 +420,7 @@  discard block
 block discarded – undo
420 420
         }
421 421
 
422 422
         // add PRC_ID to title if editing
423
-        $this->_admin_page_title = $ID ? $this->_admin_page_title . ' # ' . $ID : $this->_admin_page_title;
423
+        $this->_admin_page_title = $ID ? $this->_admin_page_title.' # '.$ID : $this->_admin_page_title;
424 424
         if ($ID) {
425 425
             $question                 = $this->_question_model->get_one_by_ID($ID);
426 426
             $additional_hidden_fields = array('QST_ID' => array('type' => 'hidden', 'value' => $ID));
@@ -430,7 +430,7 @@  discard block
 block discarded – undo
430 430
             $question->set_order_to_latest();
431 431
             $this->_set_add_edit_form_tags('insert_question');
432 432
         }
433
-        if( $question->system_ID() === EEM_Attendee::system_question_phone ){
433
+        if ($question->system_ID() === EEM_Attendee::system_question_phone) {
434 434
             $question_types = array_intersect_key(
435 435
                 EEM_Question::instance()->allowed_question_types(),
436 436
                 array_flip(
@@ -452,7 +452,7 @@  discard block
 block discarded – undo
452 452
         $this->_template_args['question_type_descriptions'] = $this->_get_question_type_descriptions();
453 453
         $this->_set_publish_post_box_vars('id', $ID);
454 454
         $this->_template_args['admin_page_content'] = EEH_Template::display_template(
455
-            REGISTRATION_FORM_TEMPLATE_PATH . 'questions_main_meta_box.template.php',
455
+            REGISTRATION_FORM_TEMPLATE_PATH.'questions_main_meta_box.template.php',
456 456
             $this->_template_args, true
457 457
         );
458 458
 
@@ -480,7 +480,7 @@  discard block
 block discarded – undo
480 480
             }
481 481
             $descriptions .= EEH_HTML::p(
482 482
                 $question_type_description,
483
-                'question_type_description-' . $type,
483
+                'question_type_description-'.$type,
484 484
                 'question_type_description description',
485 485
                 'display:none;'
486 486
             );
@@ -501,8 +501,8 @@  discard block
 block discarded – undo
501 501
             $question = EE_Question::new_instance($set_column_values);
502 502
             $action_desc = 'added';
503 503
         } else {
504
-            $question     = EEM_Question::instance()->get_one_by_ID(absint($this->_req_data['QST_ID']));
505
-            foreach($set_column_values as $field => $new_value) {
504
+            $question = EEM_Question::instance()->get_one_by_ID(absint($this->_req_data['QST_ID']));
505
+            foreach ($set_column_values as $field => $new_value) {
506 506
                 $question->set($field, $new_value);
507 507
             }
508 508
             $action_desc = 'updated';
@@ -513,8 +513,8 @@  discard block
 block discarded – undo
513 513
             //save the related options
514 514
             //trash removed options, save old ones
515 515
             //get list of all options
516
-            $options  = $question->options();
517
-            if (! empty($options)) {
516
+            $options = $question->options();
517
+            if ( ! empty($options)) {
518 518
                 foreach ($options as $option_ID => $option) {
519 519
                     $option_req_index = $this->_get_option_req_data_index($option_ID);
520 520
                     if ($option_req_index !== false) {
@@ -528,7 +528,7 @@  discard block
 block discarded – undo
528 528
             //save new related options
529 529
             foreach ($this->_req_data['question_options'] as $index => $option_req_data) {
530 530
                 //skip $index that is from our sample
531
-                if ( $index === 'xxcountxx' ) {
531
+                if ($index === 'xxcountxx') {
532 532
                     continue;
533 533
                 }
534 534
                 //note we allow saving blank options.
@@ -569,7 +569,7 @@  discard block
 block discarded – undo
569 569
     {
570 570
         $req_data_for_question_options = $this->_req_data['question_options'];
571 571
         foreach ($req_data_for_question_options as $num => $option_data) {
572
-            if (array_key_exists('QSO_ID', $option_data) && (int)$option_data['QSO_ID'] === $ID) {
572
+            if (array_key_exists('QSO_ID', $option_data) && (int) $option_data['QSO_ID'] === $ID) {
573 573
                 return $num;
574 574
             }
575 575
         }
@@ -601,7 +601,7 @@  discard block
 block discarded – undo
601 601
         $field_to_order_by        = empty($this->_req_data['orderby']) ? $orderby_field : $this->_req_data['orderby'];
602 602
         $query_params['order_by'] = array($field_to_order_by => $order);
603 603
         $search_string            = array_key_exists('s', $this->_req_data) ? $this->_req_data['s'] : null;
604
-        if (! empty($search_string)) {
604
+        if ( ! empty($search_string)) {
605 605
             if ($model instanceof EEM_Question_Group) {
606 606
                 $query_params[0] = array(
607 607
                     'OR' => array(
Please login to merge, or discard this patch.
modules/messages/EED_Messages.module.php 2 patches
Indentation   +1239 added lines, -1239 removed lines patch added patch discarded remove patch
@@ -18,1254 +18,1254 @@
 block discarded – undo
18 18
 class EED_Messages extends EED_Module
19 19
 {
20 20
 
21
-    /**
22
-     * This holds the EE_messages controller
23
-     *
24
-     * @deprecated 4.9.0
25
-     * @var EE_messages $_EEMSG
26
-     */
27
-    protected static $_EEMSG;
28
-
29
-    /**
30
-     * @type EE_Message_Resource_Manager $_message_resource_manager
31
-     */
32
-    protected static $_message_resource_manager;
33
-
34
-    /**
35
-     * This holds the EE_Messages_Processor business class.
36
-     *
37
-     * @type EE_Messages_Processor
38
-     */
39
-    protected static $_MSG_PROCESSOR;
40
-
41
-    /**
42
-     * holds all the paths for various messages components.
43
-     * Utilized by autoloader registry
44
-     *
45
-     * @var array
46
-     */
47
-    protected static $_MSG_PATHS;
48
-
49
-
50
-    /**
51
-     * This will hold an array of messages template packs that are registered in the messages system.
52
-     * Format is:
53
-     * array(
54
-     *    'template_pack_dbref' => EE_Messages_Template_Pack (instance)
55
-     * )
56
-     *
57
-     * @var EE_Messages_Template_Pack[]
58
-     */
59
-    protected static $_TMP_PACKS = array();
60
-
61
-
62
-    /**
63
-     * @return EED_Messages
64
-     */
65
-    public static function instance()
66
-    {
67
-        return parent::get_instance(__CLASS__);
68
-    }
69
-
70
-
71
-    /**
72
-     *  set_hooks - for hooking into EE Core, other modules, etc
73
-     *
74
-     * @since 4.5.0
75
-     * @return    void
76
-     */
77
-    public static function set_hooks()
78
-    {
79
-        //actions
80
-        add_action('AHEE__EE_Payment_Processor__update_txn_based_on_payment', array('EED_Messages', 'payment'), 10, 2);
81
-        add_action('AHEE__EE_Registration_Processor__trigger_registration_update_notifications',
82
-            array('EED_Messages', 'maybe_registration'), 10, 2);
83
-        //filters
84
-        add_filter('FHEE__EE_Registration__receipt_url__receipt_url',
85
-            array('EED_Messages', 'registration_message_trigger_url'), 10, 4);
86
-        add_filter('FHEE__EE_Registration__invoice_url__invoice_url',
87
-            array('EED_Messages', 'registration_message_trigger_url'), 10, 4);
88
-        //register routes
89
-        self::_register_routes();
90
-    }
91
-
92
-    /**
93
-     *    set_hooks_admin - for hooking into EE Admin Core, other modules, etc
94
-     *
95
-     * @access    public
96
-     * @return    void
97
-     */
98
-    public static function set_hooks_admin()
99
-    {
100
-        //actions
101
-        add_action('AHEE__EE_Payment_Processor__update_txn_based_on_payment', array('EED_Messages', 'payment'), 10, 2);
102
-        add_action('AHEE__Transactions_Admin_Page___send_payment_reminder__process_admin_payment_reminder',
103
-            array('EED_Messages', 'payment_reminder'), 10);
104
-        add_action('AHEE__EE_Registration_Processor__trigger_registration_update_notifications',
105
-            array('EED_Messages', 'maybe_registration'), 10, 3);
106
-        add_action('AHEE__Extend_Registrations_Admin_Page___newsletter_selected_send__with_registrations',
107
-            array('EED_Messages', 'send_newsletter_message'), 10, 2);
108
-        add_action('AHEE__EES_Espresso_Cancelled__process_shortcode__transaction',
109
-            array('EED_Messages', 'cancelled_registration'), 10);
110
-        add_action('AHEE__EE_Admin_Page___process_admin_payment_notification',
111
-            array('EED_Messages', 'process_admin_payment'), 10, 1);
112
-        //filters
113
-        add_filter('FHEE__EE_Admin_Page___process_resend_registration__success',
114
-            array('EED_Messages', 'process_resend'), 10, 2);
115
-        add_filter('FHEE__EE_Registration__receipt_url__receipt_url',
116
-            array('EED_Messages', 'registration_message_trigger_url'), 10, 4);
117
-        add_filter('FHEE__EE_Registration__invoice_url__invoice_url',
118
-            array('EED_Messages', 'registration_message_trigger_url'), 10, 4);
119
-    }
120
-
121
-
122
-    /**
123
-     * All the message triggers done by route go in here.
124
-     *
125
-     * @since 4.5.0
126
-     * @return void
127
-     */
128
-    protected static function _register_routes()
129
-    {
130
-        EE_Config::register_route('msg_url_trigger', 'Messages', 'run');
131
-        EE_Config::register_route('msg_cron_trigger', 'Messages', 'execute_batch_request');
132
-        EE_Config::register_route('msg_browser_trigger', 'Messages', 'browser_trigger');
133
-        EE_Config::register_route('msg_browser_error_trigger', 'Messages', 'browser_error_trigger');
134
-        do_action('AHEE__EED_Messages___register_routes');
135
-    }
136
-
137
-
138
-    /**
139
-     * This is called when a browser display trigger is executed.
140
-     * The browser display trigger is typically used when a already generated message is displayed directly in the
141
-     * browser.
142
-     *
143
-     * @since 4.9.0
144
-     * @param WP $WP
145
-     * @throws EE_Error
146
-     * @throws InvalidArgumentException
147
-     * @throws ReflectionException
148
-     * @throws InvalidDataTypeException
149
-     * @throws InvalidInterfaceException
150
-     */
151
-    public function browser_trigger($WP)
152
-    {
153
-        //ensure controller is loaded
154
-        self::_load_controller();
155
-        $token = EE_Registry::instance()->REQ->get('token');
156
-        try {
157
-            $mtg = new EE_Message_Generated_From_Token($token, 'html', self::$_message_resource_manager);
158
-            self::$_MSG_PROCESSOR->generate_and_send_now($mtg);
159
-        } catch (EE_Error $e) {
160
-            $error_msg = __('Please note that a system message failed to send due to a technical issue.',
161
-                'event_espresso');
162
-            // add specific message for developers if WP_DEBUG in on
163
-            $error_msg .= '||' . $e->getMessage();
164
-            EE_Error::add_error($error_msg, __FILE__, __FUNCTION__, __LINE__);
165
-        }
166
-    }
167
-
168
-
169
-    /**
170
-     * This is called when a browser error trigger is executed.
171
-     * When triggered this will grab the EE_Message matching the token in the request and use that to get the error
172
-     * message and display it.
173
-     *
174
-     * @since 4.9.0
175
-     * @param $WP
176
-     * @throws EE_Error
177
-     * @throws InvalidArgumentException
178
-     * @throws InvalidDataTypeException
179
-     * @throws InvalidInterfaceException
180
-     */
181
-    public function browser_error_trigger($WP)
182
-    {
183
-        $token = EE_Registry::instance()->REQ->get('token');
184
-        if ($token) {
185
-            $message = EEM_Message::instance()->get_one_by_token($token);
186
-            if ($message instanceof EE_Message) {
187
-                header('HTTP/1.1 200 OK');
188
-                $error_msg = nl2br($message->error_message());
189
-                ?>
21
+	/**
22
+	 * This holds the EE_messages controller
23
+	 *
24
+	 * @deprecated 4.9.0
25
+	 * @var EE_messages $_EEMSG
26
+	 */
27
+	protected static $_EEMSG;
28
+
29
+	/**
30
+	 * @type EE_Message_Resource_Manager $_message_resource_manager
31
+	 */
32
+	protected static $_message_resource_manager;
33
+
34
+	/**
35
+	 * This holds the EE_Messages_Processor business class.
36
+	 *
37
+	 * @type EE_Messages_Processor
38
+	 */
39
+	protected static $_MSG_PROCESSOR;
40
+
41
+	/**
42
+	 * holds all the paths for various messages components.
43
+	 * Utilized by autoloader registry
44
+	 *
45
+	 * @var array
46
+	 */
47
+	protected static $_MSG_PATHS;
48
+
49
+
50
+	/**
51
+	 * This will hold an array of messages template packs that are registered in the messages system.
52
+	 * Format is:
53
+	 * array(
54
+	 *    'template_pack_dbref' => EE_Messages_Template_Pack (instance)
55
+	 * )
56
+	 *
57
+	 * @var EE_Messages_Template_Pack[]
58
+	 */
59
+	protected static $_TMP_PACKS = array();
60
+
61
+
62
+	/**
63
+	 * @return EED_Messages
64
+	 */
65
+	public static function instance()
66
+	{
67
+		return parent::get_instance(__CLASS__);
68
+	}
69
+
70
+
71
+	/**
72
+	 *  set_hooks - for hooking into EE Core, other modules, etc
73
+	 *
74
+	 * @since 4.5.0
75
+	 * @return    void
76
+	 */
77
+	public static function set_hooks()
78
+	{
79
+		//actions
80
+		add_action('AHEE__EE_Payment_Processor__update_txn_based_on_payment', array('EED_Messages', 'payment'), 10, 2);
81
+		add_action('AHEE__EE_Registration_Processor__trigger_registration_update_notifications',
82
+			array('EED_Messages', 'maybe_registration'), 10, 2);
83
+		//filters
84
+		add_filter('FHEE__EE_Registration__receipt_url__receipt_url',
85
+			array('EED_Messages', 'registration_message_trigger_url'), 10, 4);
86
+		add_filter('FHEE__EE_Registration__invoice_url__invoice_url',
87
+			array('EED_Messages', 'registration_message_trigger_url'), 10, 4);
88
+		//register routes
89
+		self::_register_routes();
90
+	}
91
+
92
+	/**
93
+	 *    set_hooks_admin - for hooking into EE Admin Core, other modules, etc
94
+	 *
95
+	 * @access    public
96
+	 * @return    void
97
+	 */
98
+	public static function set_hooks_admin()
99
+	{
100
+		//actions
101
+		add_action('AHEE__EE_Payment_Processor__update_txn_based_on_payment', array('EED_Messages', 'payment'), 10, 2);
102
+		add_action('AHEE__Transactions_Admin_Page___send_payment_reminder__process_admin_payment_reminder',
103
+			array('EED_Messages', 'payment_reminder'), 10);
104
+		add_action('AHEE__EE_Registration_Processor__trigger_registration_update_notifications',
105
+			array('EED_Messages', 'maybe_registration'), 10, 3);
106
+		add_action('AHEE__Extend_Registrations_Admin_Page___newsletter_selected_send__with_registrations',
107
+			array('EED_Messages', 'send_newsletter_message'), 10, 2);
108
+		add_action('AHEE__EES_Espresso_Cancelled__process_shortcode__transaction',
109
+			array('EED_Messages', 'cancelled_registration'), 10);
110
+		add_action('AHEE__EE_Admin_Page___process_admin_payment_notification',
111
+			array('EED_Messages', 'process_admin_payment'), 10, 1);
112
+		//filters
113
+		add_filter('FHEE__EE_Admin_Page___process_resend_registration__success',
114
+			array('EED_Messages', 'process_resend'), 10, 2);
115
+		add_filter('FHEE__EE_Registration__receipt_url__receipt_url',
116
+			array('EED_Messages', 'registration_message_trigger_url'), 10, 4);
117
+		add_filter('FHEE__EE_Registration__invoice_url__invoice_url',
118
+			array('EED_Messages', 'registration_message_trigger_url'), 10, 4);
119
+	}
120
+
121
+
122
+	/**
123
+	 * All the message triggers done by route go in here.
124
+	 *
125
+	 * @since 4.5.0
126
+	 * @return void
127
+	 */
128
+	protected static function _register_routes()
129
+	{
130
+		EE_Config::register_route('msg_url_trigger', 'Messages', 'run');
131
+		EE_Config::register_route('msg_cron_trigger', 'Messages', 'execute_batch_request');
132
+		EE_Config::register_route('msg_browser_trigger', 'Messages', 'browser_trigger');
133
+		EE_Config::register_route('msg_browser_error_trigger', 'Messages', 'browser_error_trigger');
134
+		do_action('AHEE__EED_Messages___register_routes');
135
+	}
136
+
137
+
138
+	/**
139
+	 * This is called when a browser display trigger is executed.
140
+	 * The browser display trigger is typically used when a already generated message is displayed directly in the
141
+	 * browser.
142
+	 *
143
+	 * @since 4.9.0
144
+	 * @param WP $WP
145
+	 * @throws EE_Error
146
+	 * @throws InvalidArgumentException
147
+	 * @throws ReflectionException
148
+	 * @throws InvalidDataTypeException
149
+	 * @throws InvalidInterfaceException
150
+	 */
151
+	public function browser_trigger($WP)
152
+	{
153
+		//ensure controller is loaded
154
+		self::_load_controller();
155
+		$token = EE_Registry::instance()->REQ->get('token');
156
+		try {
157
+			$mtg = new EE_Message_Generated_From_Token($token, 'html', self::$_message_resource_manager);
158
+			self::$_MSG_PROCESSOR->generate_and_send_now($mtg);
159
+		} catch (EE_Error $e) {
160
+			$error_msg = __('Please note that a system message failed to send due to a technical issue.',
161
+				'event_espresso');
162
+			// add specific message for developers if WP_DEBUG in on
163
+			$error_msg .= '||' . $e->getMessage();
164
+			EE_Error::add_error($error_msg, __FILE__, __FUNCTION__, __LINE__);
165
+		}
166
+	}
167
+
168
+
169
+	/**
170
+	 * This is called when a browser error trigger is executed.
171
+	 * When triggered this will grab the EE_Message matching the token in the request and use that to get the error
172
+	 * message and display it.
173
+	 *
174
+	 * @since 4.9.0
175
+	 * @param $WP
176
+	 * @throws EE_Error
177
+	 * @throws InvalidArgumentException
178
+	 * @throws InvalidDataTypeException
179
+	 * @throws InvalidInterfaceException
180
+	 */
181
+	public function browser_error_trigger($WP)
182
+	{
183
+		$token = EE_Registry::instance()->REQ->get('token');
184
+		if ($token) {
185
+			$message = EEM_Message::instance()->get_one_by_token($token);
186
+			if ($message instanceof EE_Message) {
187
+				header('HTTP/1.1 200 OK');
188
+				$error_msg = nl2br($message->error_message());
189
+				?>
190 190
                 <!DOCTYPE html>
191 191
                 <html>
192 192
                 <head></head>
193 193
                 <body>
194 194
                 <?php echo empty($error_msg)
195
-                    ? esc_html__('Unfortunately, we were unable to capture the error message for this message.',
196
-                        'event_espresso')
197
-                    : wp_kses(
198
-                        $error_msg,
199
-                        array(
200
-                            'a'      => array(
201
-                                'href'  => array(),
202
-                                'title' => array(),
203
-                            ),
204
-                            'span'   => array(),
205
-                            'div'    => array(),
206
-                            'p'      => array(),
207
-                            'strong' => array(),
208
-                            'em'     => array(),
209
-                            'br'     => array(),
210
-                        )
211
-                    ); ?>
195
+					? esc_html__('Unfortunately, we were unable to capture the error message for this message.',
196
+						'event_espresso')
197
+					: wp_kses(
198
+						$error_msg,
199
+						array(
200
+							'a'      => array(
201
+								'href'  => array(),
202
+								'title' => array(),
203
+							),
204
+							'span'   => array(),
205
+							'div'    => array(),
206
+							'p'      => array(),
207
+							'strong' => array(),
208
+							'em'     => array(),
209
+							'br'     => array(),
210
+						)
211
+					); ?>
212 212
                 </body>
213 213
                 </html>
214 214
                 <?php
215
-                exit;
216
-            }
217
-        }
218
-        return;
219
-    }
220
-
221
-
222
-    /**
223
-     *  This runs when the msg_url_trigger route has initiated.
224
-     *
225
-     * @since 4.5.0
226
-     * @param WP $WP
227
-     * @throws EE_Error
228
-     * @throws InvalidArgumentException
229
-     * @throws ReflectionException
230
-     * @throws InvalidDataTypeException
231
-     * @throws InvalidInterfaceException
232
-     */
233
-    public function run($WP)
234
-    {
235
-        //ensure controller is loaded
236
-        self::_load_controller();
237
-        // attempt to process message
238
-        try {
239
-            /** @type EE_Message_To_Generate_From_Request $message_to_generate */
240
-            $message_to_generate = EE_Registry::instance()->load_lib('Message_To_Generate_From_Request');
241
-            self::$_MSG_PROCESSOR->generate_and_send_now($message_to_generate);
242
-        } catch (EE_Error $e) {
243
-            $error_msg = __('Please note that a system message failed to send due to a technical issue.',
244
-                'event_espresso');
245
-            // add specific message for developers if WP_DEBUG in on
246
-            $error_msg .= '||' . $e->getMessage();
247
-            EE_Error::add_error($error_msg, __FILE__, __FUNCTION__, __LINE__);
248
-        }
249
-    }
250
-
251
-
252
-    /**
253
-     * This is triggered by the 'msg_cron_trigger' route.
254
-     *
255
-     * @param WP $WP
256
-     */
257
-    public function execute_batch_request($WP)
258
-    {
259
-        $this->run_cron();
260
-        header('HTTP/1.1 200 OK');
261
-        exit();
262
-    }
263
-
264
-
265
-    /**
266
-     * This gets executed on wp_cron jobs or when a batch request is initiated on its own separate non regular wp
267
-     * request.
268
-     */
269
-    public function run_cron()
270
-    {
271
-        self::_load_controller();
272
-        //get required vars
273
-        $cron_type     = EE_Registry::instance()->REQ->get('type');
274
-        $transient_key = EE_Registry::instance()->REQ->get('key');
275
-
276
-        //now let's verify transient, if not valid exit immediately
277
-        if (! get_transient($transient_key)) {
278
-            /**
279
-             * trigger error so this gets in the error logs.  This is important because it happens on a non-user
280
-             * request.
281
-             */
282
-            trigger_error(esc_attr__('Invalid Request (Transient does not exist)', 'event_espresso'));
283
-        }
284
-
285
-        //if made it here, lets' delete the transient to keep the db clean
286
-        delete_transient($transient_key);
287
-
288
-        if (apply_filters('FHEE__EED_Messages__run_cron__use_wp_cron', true)) {
289
-
290
-            $method = 'batch_' . $cron_type . '_from_queue';
291
-            if (method_exists(self::$_MSG_PROCESSOR, $method)) {
292
-                self::$_MSG_PROCESSOR->$method();
293
-            } else {
294
-                //no matching task
295
-                /**
296
-                 * trigger error so this gets in the error logs.  This is important because it happens on a non user
297
-                 * request.
298
-                 */
299
-                trigger_error(esc_attr(sprintf(__('There is no task corresponding to this route %s', 'event_espresso'),
300
-                    $cron_type)));
301
-            }
302
-        }
303
-
304
-        do_action('FHEE__EED_Messages__run_cron__end');
305
-    }
306
-
307
-
308
-    /**
309
-     * This is used to retrieve the template pack for the given name.
310
-     * Retrieved packs are cached on the static $_TMP_PACKS array.  If there is no class matching the given name then
311
-     * the default template pack is returned.
312
-     *
313
-     * @deprecated 4.9.0  @see EEH_MSG_Template::get_template_pack()
314
-     * @param string $template_pack_name This should correspond to the dbref of the template pack (which is also used
315
-     *                                   in generating the Pack class name).
316
-     * @return EE_Messages_Template_Pack
317
-     * @throws EE_Error
318
-     * @throws InvalidArgumentException
319
-     * @throws ReflectionException
320
-     * @throws InvalidDataTypeException
321
-     * @throws InvalidInterfaceException
322
-     */
323
-    public static function get_template_pack($template_pack_name)
324
-    {
325
-        EE_Registry::instance()->load_helper('MSG_Template');
326
-        return EEH_MSG_Template::get_template_pack($template_pack_name);
327
-    }
328
-
329
-
330
-    /**
331
-     * Retrieves an array of all template packs.
332
-     * Array is in the format array( 'dbref' => EE_Messages_Template_Pack )
333
-     *
334
-     * @deprecated 4.9.0  @see EEH_MSG_Template_Pack::get_template_pack_collection
335
-     * @return EE_Messages_Template_Pack[]
336
-     * @throws EE_Error
337
-     * @throws InvalidArgumentException
338
-     * @throws ReflectionException
339
-     * @throws InvalidDataTypeException
340
-     * @throws InvalidInterfaceException
341
-     */
342
-    public static function get_template_packs()
343
-    {
344
-        EE_Registry::instance()->load_helper('MSG_Template');
345
-
346
-        //for backward compat, let's make sure this returns in the same format as originally.
347
-        $template_pack_collection = EEH_MSG_Template::get_template_pack_collection();
348
-        $template_pack_collection->rewind();
349
-        $template_packs = array();
350
-        while ($template_pack_collection->valid()) {
351
-            $template_packs[$template_pack_collection->current()->dbref] = $template_pack_collection->current();
352
-            $template_pack_collection->next();
353
-        }
354
-        return $template_packs;
355
-    }
356
-
357
-
358
-    /**
359
-     * This simply makes sure the autoloaders are registered for the EE_messages system.
360
-     *
361
-     * @since 4.5.0
362
-     * @return void
363
-     * @throws EE_Error
364
-     */
365
-    public static function set_autoloaders()
366
-    {
367
-        if (empty(self::$_MSG_PATHS)) {
368
-            self::_set_messages_paths();
369
-            foreach (self::$_MSG_PATHS as $path) {
370
-                EEH_Autoloader::register_autoloaders_for_each_file_in_folder($path);
371
-            }
372
-            // add aliases
373
-            EEH_Autoloader::add_alias('EE_messages', 'EE_messages');
374
-            EEH_Autoloader::add_alias('EE_messenger', 'EE_messenger');
375
-        }
376
-    }
377
-
378
-
379
-    /**
380
-     * Take care of adding all the paths for the messages components to the $_MSG_PATHS property
381
-     * for use by the Messages Autoloaders
382
-     *
383
-     * @since 4.5.0
384
-     * @return void.
385
-     */
386
-    protected static function _set_messages_paths()
387
-    {
388
-        $dir_ref = array(
389
-            'messages/message_type',
390
-            'messages/messenger',
391
-            'messages/defaults',
392
-            'messages/defaults/email',
393
-            'messages/data_class',
394
-            'messages/validators',
395
-            'messages/validators/email',
396
-            'messages/validators/html',
397
-            'shortcodes',
398
-        );
399
-        $paths   = array();
400
-        foreach ($dir_ref as $index => $dir) {
401
-            $paths[$index] = EE_LIBRARIES . $dir;
402
-        }
403
-        self::$_MSG_PATHS = apply_filters('FHEE__EED_Messages___set_messages_paths___MSG_PATHS', $paths);
404
-    }
405
-
406
-
407
-    /**
408
-     * Takes care of loading dependencies
409
-     *
410
-     * @since 4.5.0
411
-     * @return void
412
-     * @throws EE_Error
413
-     * @throws InvalidArgumentException
414
-     * @throws ReflectionException
415
-     * @throws InvalidDataTypeException
416
-     * @throws InvalidInterfaceException
417
-     */
418
-    protected static function _load_controller()
419
-    {
420
-        if (! self::$_MSG_PROCESSOR instanceof EE_Messages_Processor) {
421
-            EE_Registry::instance()->load_core('Request_Handler');
422
-            self::set_autoloaders();
423
-            self::$_EEMSG                    = EE_Registry::instance()->load_lib('messages');
424
-            self::$_MSG_PROCESSOR            = EE_Registry::instance()->load_lib('Messages_Processor');
425
-            self::$_message_resource_manager = EE_Registry::instance()->load_lib('Message_Resource_Manager');
426
-        }
427
-    }
428
-
429
-
430
-    /**
431
-     * @param EE_Transaction $transaction
432
-     * @throws EE_Error
433
-     * @throws InvalidArgumentException
434
-     * @throws InvalidDataTypeException
435
-     * @throws InvalidInterfaceException
436
-     * @throws ReflectionException
437
-     */
438
-    public static function payment_reminder(EE_Transaction $transaction)
439
-    {
440
-        self::_load_controller();
441
-        $data = array($transaction, null);
442
-        self::$_MSG_PROCESSOR->generate_for_all_active_messengers('payment_reminder', $data);
443
-    }
444
-
445
-
446
-    /**
447
-     * Any messages triggers for after successful gateway payments should go in here.
448
-     *
449
-     * @param EE_Transaction $transaction object
450
-     * @param EE_Payment|null     $payment     object
451
-     * @return void
452
-     * @throws EE_Error
453
-     * @throws InvalidArgumentException
454
-     * @throws ReflectionException
455
-     * @throws InvalidDataTypeException
456
-     * @throws InvalidInterfaceException
457
-     */
458
-    public static function payment(EE_Transaction $transaction, EE_Payment $payment = null)
459
-    {
460
-        //if there's no payment object, then we cannot do a payment type message!
461
-        if (! $payment instanceof EE_Payment) {
462
-            return;
463
-        }
464
-        self::_load_controller();
465
-        $data = array($transaction, $payment);
466
-        EE_Registry::instance()->load_helper('MSG_Template');
467
-        $message_type = EEH_MSG_Template::convert_payment_status_to_message_type($payment->STS_ID());
468
-        //if payment amount is less than 0 then switch to payment_refund message type.
469
-        $message_type = $payment->amount() < 0 ? 'payment_refund' : $message_type;
470
-        self::$_MSG_PROCESSOR->generate_for_all_active_messengers($message_type, $data);
471
-    }
472
-
473
-
474
-    /**
475
-     * @param EE_Transaction $transaction
476
-     * @throws EE_Error
477
-     * @throws InvalidArgumentException
478
-     * @throws InvalidDataTypeException
479
-     * @throws InvalidInterfaceException
480
-     * @throws ReflectionException
481
-     */
482
-    public static function cancelled_registration(EE_Transaction $transaction)
483
-    {
484
-        self::_load_controller();
485
-        $data = array($transaction, null);
486
-        self::$_MSG_PROCESSOR->generate_for_all_active_messengers('cancelled_registration', $data);
487
-    }
488
-
489
-
490
-
491
-    /**
492
-     * Trigger for Registration messages
493
-     * Note that what registration message type is sent depends on what the reg status is for the registrations on the
494
-     * incoming transaction.
495
-     *
496
-     * @param EE_Registration $registration
497
-     * @param array           $extra_details
498
-     * @return void
499
-     * @throws EE_Error
500
-     * @throws InvalidArgumentException
501
-     * @throws InvalidDataTypeException
502
-     * @throws InvalidInterfaceException
503
-     * @throws ReflectionException
504
-     * @throws EntityNotFoundException
505
-     */
506
-    public static function maybe_registration(EE_Registration $registration, $extra_details = array())
507
-    {
508
-
509
-        if (! self::_verify_registration_notification_send($registration, $extra_details)) {
510
-            //no messages please
511
-            return;
512
-        }
513
-
514
-        // get all non-trashed registrations so we make sure we send messages for the right status.
515
-        $all_registrations = $registration->transaction()->registrations(
516
-            array(
517
-                array('REG_deleted' => false),
518
-                'order_by' => array(
519
-                    'Event.EVT_name'     => 'ASC',
520
-                    'Attendee.ATT_lname' => 'ASC',
521
-                    'Attendee.ATT_fname' => 'ASC'
522
-                )
523
-            )
524
-        );
525
-        //cached array of statuses so we only trigger messages once per status.
526
-        $statuses_sent = array();
527
-        self::_load_controller();
528
-        $mtgs = array();
529
-
530
-        //loop through registrations and trigger messages once per status.
531
-        foreach ($all_registrations as $reg) {
532
-
533
-            //already triggered?
534
-            if (in_array($reg->status_ID(), $statuses_sent)) {
535
-                continue;
536
-            }
537
-
538
-            $message_type    = EEH_MSG_Template::convert_reg_status_to_message_type($reg->status_ID());
539
-            $mtgs            = array_merge(
540
-                    $mtgs,
541
-                    self::$_MSG_PROCESSOR->setup_mtgs_for_all_active_messengers(
542
-                            $message_type,
543
-                            array($registration->transaction(), null, $reg->status_ID())
544
-                    )
545
-            );
546
-            $statuses_sent[] = $reg->status_ID();
547
-        }
548
-
549
-        if (count($statuses_sent) > 1) {
550
-            $mtgs = array_merge(
551
-                $mtgs,
552
-                self::$_MSG_PROCESSOR->setup_mtgs_for_all_active_messengers(
553
-                    'registration_summary',
554
-                    array($registration->transaction(), null)
555
-                )
556
-            );
557
-        }
558
-
559
-        //batch queue and initiate request
560
-        self::$_MSG_PROCESSOR->batch_queue_for_generation_and_persist($mtgs);
561
-        self::$_MSG_PROCESSOR->get_queue()->initiate_request_by_priority();
562
-    }
563
-
564
-
565
-    /**
566
-     * This is a helper method used to very whether a registration notification should be sent or
567
-     * not.  Prevents duplicate notifications going out for registration context notifications.
568
-     *
569
-     * @param EE_Registration $registration  [description]
570
-     * @param array           $extra_details [description]
571
-     * @return bool          true = send away, false = nope halt the presses.
572
-     */
573
-    protected static function _verify_registration_notification_send(
574
-        EE_Registration $registration,
575
-        $extra_details = array()
576
-    ) {
577
-        //self::log(
578
-        //	__CLASS__, __FUNCTION__, __LINE__,
579
-        //	$registration->transaction(),
580
-        //	array( '$extra_details' => $extra_details )
581
-        //);
582
-        // currently only using this to send messages for the primary registrant
583
-        if (! $registration->is_primary_registrant()) {
584
-            return false;
585
-        }
586
-        // first we check if we're in admin and not doing front ajax
587
-        if (is_admin() && ! EE_FRONT_AJAX) {
588
-            //make sure appropriate admin params are set for sending messages
589
-            if (empty($_REQUEST['txn_reg_status_change']['send_notifications']) || ! absint($_REQUEST['txn_reg_status_change']['send_notifications'])) {
590
-                //no messages sent please.
591
-                return false;
592
-            }
593
-        } else {
594
-            // frontend request (either regular or via AJAX)
595
-            // TXN is NOT finalized ?
596
-            if (! isset($extra_details['finalized']) || $extra_details['finalized'] === false) {
597
-                return false;
598
-            }
599
-            // return visit but nothing changed ???
600
-            if (
601
-                isset($extra_details['revisit'], $extra_details['status_updates']) &&
602
-                $extra_details['revisit'] && ! $extra_details['status_updates']
603
-            ) {
604
-                return false;
605
-            }
606
-            // NOT sending messages && reg status is something other than "Not-Approved"
607
-            if (
608
-                ! apply_filters('FHEE__EED_Messages___maybe_registration__deliver_notifications', false) &&
609
-                $registration->status_ID() !== EEM_Registration::status_id_not_approved
610
-            ) {
611
-                return false;
612
-            }
613
-        }
614
-        // release the kraken
615
-        return true;
616
-    }
617
-
618
-
619
-    /**
620
-     * Simply returns an array indexed by Registration Status ID and the related message_type name associated with that
621
-     * status id.
622
-     *
623
-     * @deprecated 4.9.0  Use EEH_MSG_Template::reg_status_to_message_type_array()
624
-     *                    or EEH_MSG_Template::convert_reg_status_to_message_type
625
-     * @param string $reg_status
626
-     * @return array
627
-     * @throws EE_Error
628
-     * @throws InvalidArgumentException
629
-     * @throws ReflectionException
630
-     * @throws InvalidDataTypeException
631
-     * @throws InvalidInterfaceException
632
-     */
633
-    protected static function _get_reg_status_array($reg_status = '')
634
-    {
635
-        EE_Registry::instance()->load_helper('MSG_Template');
636
-        return EEH_MSG_Template::convert_reg_status_to_message_type($reg_status)
637
-            ? EEH_MSG_Template::convert_reg_status_to_message_type($reg_status)
638
-            : EEH_MSG_Template::reg_status_to_message_type_array();
639
-    }
640
-
641
-
642
-    /**
643
-     * Simply returns the payment message type for the given payment status.
644
-     *
645
-     * @deprecated 4.9.0 Use EEH_MSG_Template::payment_status_to_message_type_array
646
-     *                   or EEH_MSG_Template::convert_payment_status_to_message_type
647
-     * @param string $payment_status The payment status being matched.
648
-     * @return bool|string The payment message type slug matching the status or false if no match.
649
-     * @throws EE_Error
650
-     * @throws InvalidArgumentException
651
-     * @throws ReflectionException
652
-     * @throws InvalidDataTypeException
653
-     * @throws InvalidInterfaceException
654
-     */
655
-    protected static function _get_payment_message_type($payment_status)
656
-    {
657
-        EE_Registry::instance()->load_helper('MSG_Template');
658
-        return EEH_MSG_Template::convert_payment_status_to_message_type($payment_status)
659
-            ? EEH_MSG_Template::convert_payment_status_to_message_type($payment_status)
660
-            : false;
661
-    }
662
-
663
-
664
-    /**
665
-     * Message triggers for a resending already sent message(s) (via EE_Message list table)
666
-     *
667
-     * @access public
668
-     * @param array $req_data This is the $_POST & $_GET data sent from EE_Admin Pages
669
-     * @return bool success/fail
670
-     * @throws EE_Error
671
-     * @throws InvalidArgumentException
672
-     * @throws InvalidDataTypeException
673
-     * @throws InvalidInterfaceException
674
-     * @throws ReflectionException
675
-     */
676
-    public static function process_resend($req_data)
677
-    {
678
-        self::_load_controller();
679
-
680
-        //if $msgID in this request then skip to the new resend_message
681
-        if (EE_Registry::instance()->REQ->get('MSG_ID')) {
682
-            return self::resend_message();
683
-        }
684
-
685
-        //make sure any incoming request data is set on the REQ so that it gets picked up later.
686
-        $req_data = (array)$req_data;
687
-        foreach ($req_data as $request_key => $request_value) {
688
-            EE_Registry::instance()->REQ->set($request_key, $request_value);
689
-        }
690
-
691
-        if (! $messages_to_send = self::$_MSG_PROCESSOR->setup_messages_to_generate_from_registration_ids_in_request()) {
692
-            return false;
693
-        }
694
-
695
-        try {
696
-            self::$_MSG_PROCESSOR->batch_queue_for_generation_and_persist($messages_to_send);
697
-            self::$_MSG_PROCESSOR->get_queue()->initiate_request_by_priority();
698
-        } catch (EE_Error $e) {
699
-            EE_Error::add_error($e->getMessage(), __FILE__, __FUNCTION__, __LINE__);
700
-            return false;
701
-        }
702
-        EE_Error::add_success(
703
-            __('Messages have been successfully queued for generation and sending.', 'event_espresso')
704
-        );
705
-        return true; //everything got queued.
706
-    }
707
-
708
-
709
-    /**
710
-     * Message triggers for a resending already sent message(s) (via EE_Message list table)
711
-     *
712
-     * @return bool
713
-     * @throws EE_Error
714
-     * @throws InvalidArgumentException
715
-     * @throws InvalidDataTypeException
716
-     * @throws InvalidInterfaceException
717
-     * @throws ReflectionException
718
-     */
719
-    public static function resend_message()
720
-    {
721
-        self::_load_controller();
722
-
723
-        $msgID = EE_Registry::instance()->REQ->get('MSG_ID');
724
-        if (! $msgID) {
725
-            EE_Error::add_error(__('Something went wrong because there is no "MSG_ID" value in the request',
726
-                'event_espresso'), __FILE__, __FUNCTION__, __LINE__);
727
-            return false;
728
-        }
729
-
730
-        self::$_MSG_PROCESSOR->setup_messages_from_ids_and_send((array)$msgID);
731
-
732
-        //setup success message.
733
-        $count_ready_for_resend = self::$_MSG_PROCESSOR->get_queue()->count_STS_in_queue(EEM_Message::status_resend);
734
-        EE_Error::add_success(sprintf(
735
-            _n(
736
-                'There was %d message queued for resending.',
737
-                'There were %d messages queued for resending.',
738
-                $count_ready_for_resend,
739
-                'event_espresso'
740
-            ),
741
-            $count_ready_for_resend
742
-        ));
743
-        return true;
744
-    }
745
-
746
-
747
-    /**
748
-     * Message triggers for manual payment applied by admin
749
-     *
750
-     * @param  EE_Payment $payment EE_payment object
751
-     * @return bool success/fail
752
-     * @throws EE_Error
753
-     * @throws InvalidArgumentException
754
-     * @throws ReflectionException
755
-     * @throws InvalidDataTypeException
756
-     * @throws InvalidInterfaceException
757
-     */
758
-    public static function process_admin_payment(EE_Payment $payment)
759
-    {
760
-        EE_Registry::instance()->load_helper('MSG_Template');
761
-        //we need to get the transaction object
762
-        $transaction = $payment->transaction();
763
-        if ($transaction instanceof EE_Transaction) {
764
-            $data         = array($transaction, $payment);
765
-            $message_type = EEH_MSG_Template::convert_payment_status_to_message_type($payment->STS_ID());
766
-
767
-            //if payment amount is less than 0 then switch to payment_refund message type.
768
-            $message_type = $payment->amount() < 0 ? 'payment_refund' : $message_type;
769
-
770
-            //if payment_refund is selected, but the status is NOT accepted.  Then change message type to false so NO message notification goes out.
771
-            $message_type = $message_type == 'payment_refund' && $payment->STS_ID() != EEM_Payment::status_id_approved ? false : $message_type;
772
-
773
-            self::_load_controller();
774
-
775
-            self::$_MSG_PROCESSOR->generate_for_all_active_messengers($message_type, $data);
776
-
777
-            //get count of queued for generation
778
-            $count_to_generate = self::$_MSG_PROCESSOR->get_queue()->count_STS_in_queue(array(
779
-                EEM_Message::status_incomplete,
780
-                EEM_Message::status_idle,
781
-            ));
782
-
783
-            if ($count_to_generate > 0 && self::$_MSG_PROCESSOR->get_queue()->get_message_repository()->count() !== 0) {
784
-                add_filter('FHEE__EE_Admin_Page___process_admin_payment_notification__success', '__return_true');
785
-                return true;
786
-            } else {
787
-                $count_failed = self::$_MSG_PROCESSOR->get_queue()->count_STS_in_queue(EEM_Message::instance()->stati_indicating_failed_sending());
788
-                /**
789
-                 * Verify that there are actually errors.  If not then we return a success message because the queue might have been emptied due to successful
790
-                 * IMMEDIATE generation.
791
-                 */
792
-                if ($count_failed > 0) {
793
-                    EE_Error::add_error(sprintf(
794
-                        _n(
795
-                            'The payment notification generation failed.',
796
-                            '%d payment notifications failed being sent.',
797
-                            $count_failed,
798
-                            'event_espresso'
799
-                        ),
800
-                        $count_failed
801
-                    ), __FILE__, __FUNCTION__, __LINE__);
802
-
803
-                    return false;
804
-                } else {
805
-                    add_filter('FHEE__EE_Admin_Page___process_admin_payment_notification__success', '__return_true');
806
-                    return true;
807
-                }
808
-            }
809
-        } else {
810
-            EE_Error::add_error(
811
-                'Unable to generate the payment notification because the given value for the transaction is invalid.',
812
-                'event_espresso'
813
-            );
814
-            return false;
815
-        }
816
-    }
817
-
818
-
819
-    /**
820
-     * Callback for AHEE__Extend_Registrations_Admin_Page___newsletter_selected_send_with_registrations trigger
821
-     *
822
-     * @since   4.3.0
823
-     * @param  EE_Registration[] $registrations an array of EE_Registration objects
824
-     * @param  int               $grp_id        a specific message template group id.
825
-     * @return void
826
-     * @throws EE_Error
827
-     * @throws InvalidArgumentException
828
-     * @throws InvalidDataTypeException
829
-     * @throws InvalidInterfaceException
830
-     * @throws ReflectionException
831
-     */
832
-    public static function send_newsletter_message($registrations, $grp_id)
833
-    {
834
-        //make sure mtp is id and set it in the EE_Request Handler later messages setup.
835
-        EE_Registry::instance()->REQ->set('GRP_ID', (int)$grp_id);
836
-        self::_load_controller();
837
-        self::$_MSG_PROCESSOR->generate_for_all_active_messengers('newsletter', $registrations);
838
-    }
839
-
840
-
841
-    /**
842
-     * Callback for FHEE__EE_Registration__invoice_url__invoice_url or FHEE__EE_Registration__receipt_url__receipt_url
843
-     *
844
-     * @since   4.3.0
845
-     * @param    string          $registration_message_trigger_url
846
-     * @param    EE_Registration $registration
847
-     * @param string             $messenger
848
-     * @param string             $message_type
849
-     * @return string
850
-     * @throws EE_Error
851
-     * @throws InvalidArgumentException
852
-     * @throws InvalidDataTypeException
853
-     * @throws InvalidInterfaceException
854
-     */
855
-    public static function registration_message_trigger_url(
856
-        $registration_message_trigger_url,
857
-        EE_Registration $registration,
858
-        $messenger = 'html',
859
-        $message_type = 'invoice'
860
-    ) {
861
-        // whitelist $messenger
862
-        switch ($messenger) {
863
-            case 'pdf' :
864
-                $sending_messenger    = 'pdf';
865
-                $generating_messenger = 'html';
866
-                break;
867
-            case 'html' :
868
-            default :
869
-                $sending_messenger    = 'html';
870
-                $generating_messenger = 'html';
871
-                break;
872
-        }
873
-        // whitelist $message_type
874
-        switch ($message_type) {
875
-            case 'receipt' :
876
-                $message_type = 'receipt';
877
-                break;
878
-            case 'invoice' :
879
-            default :
880
-                $message_type = 'invoice';
881
-                break;
882
-        }
883
-        // verify that both the messenger AND the message type are active
884
-        if (EEH_MSG_Template::is_messenger_active($sending_messenger) && EEH_MSG_Template::is_mt_active($message_type)) {
885
-            //need to get the correct message template group for this (i.e. is there a custom invoice for the event this registration is registered for?)
886
-            $template_query_params = array(
887
-                'MTP_is_active'    => true,
888
-                'MTP_messenger'    => $generating_messenger,
889
-                'MTP_message_type' => $message_type,
890
-                'Event.EVT_ID'     => $registration->event_ID(),
891
-            );
892
-            //get the message template group.
893
-            $msg_template_group = EEM_Message_Template_Group::instance()->get_one(array($template_query_params));
894
-            //if we don't have an EE_Message_Template_Group then return
895
-            if (! $msg_template_group instanceof EE_Message_Template_Group) {
896
-                // remove EVT_ID from query params so that global templates get picked up
897
-                unset($template_query_params['Event.EVT_ID']);
898
-                //get global template as the fallback
899
-                $msg_template_group = EEM_Message_Template_Group::instance()->get_one(array($template_query_params));
900
-            }
901
-            //if we don't have an EE_Message_Template_Group then return
902
-            if (! $msg_template_group instanceof EE_Message_Template_Group) {
903
-                return '';
904
-            }
905
-            // generate the URL
906
-            $registration_message_trigger_url = EEH_MSG_Template::generate_url_trigger(
907
-                $sending_messenger,
908
-                $generating_messenger,
909
-                'purchaser',
910
-                $message_type,
911
-                $registration,
912
-                $msg_template_group->ID(),
913
-                $registration->transaction_ID()
914
-            );
915
-
916
-        }
917
-        return $registration_message_trigger_url;
918
-    }
919
-
920
-
921
-    /**
922
-     * Use to generate and return a message preview!
923
-     *
924
-     * @param  string $type      This should correspond with a valid message type
925
-     * @param  string $context   This should correspond with a valid context for the message type
926
-     * @param  string $messenger This should correspond with a valid messenger.
927
-     * @param bool    $send      true we will do a test send using the messenger delivery, false we just do a regular
928
-     *                           preview
929
-     * @return bool|string The body of the message or if send is requested, sends.
930
-     * @throws EE_Error
931
-     * @throws InvalidArgumentException
932
-     * @throws InvalidDataTypeException
933
-     * @throws InvalidInterfaceException
934
-     * @throws ReflectionException
935
-     */
936
-    public static function preview_message($type, $context, $messenger, $send = false)
937
-    {
938
-        self::_load_controller();
939
-        $mtg                     = new EE_Message_To_Generate(
940
-            $messenger,
941
-            $type,
942
-            array(),
943
-            $context,
944
-            true
945
-        );
946
-        $generated_preview_queue = self::$_MSG_PROCESSOR->generate_for_preview($mtg, $send);
947
-        if ($generated_preview_queue instanceof EE_Messages_Queue) {
948
-            //loop through all content for the preview and remove any persisted records.
949
-            $content = '';
950
-            foreach ($generated_preview_queue->get_message_repository() as $message) {
951
-                $content = $message->content();
952
-                if ($message->ID() > 0 && $message->STS_ID() !== EEM_Message::status_failed) {
953
-                    $message->delete();
954
-                }
955
-            }
956
-            return $content;
957
-        } else {
958
-            return $generated_preview_queue;
959
-        }
960
-    }
961
-
962
-
963
-    /**
964
-     * This is a method that allows for sending a message using a messenger matching the string given and the provided
965
-     * EE_Message_Queue object.  The EE_Message_Queue object is used to create a single aggregate EE_Message via the
966
-     * content found in the EE_Message objects in the queue.
967
-     *
968
-     * @since 4.9.0
969
-     * @param string            $messenger            a string matching a valid active messenger in the system
970
-     * @param string            $message_type         Although it seems contrary to the name of the method, a message
971
-     *                                                type name is still required to send along the message type to the
972
-     *                                                messenger because this is used for determining what specific
973
-     *                                                variations might be loaded for the generated message.
974
-     * @param EE_Messages_Queue $queue
975
-     * @param string            $custom_subject       Can be used to set what the custom subject string will be on the
976
-     *                                                aggregate EE_Message object.
977
-     * @return bool success or fail.
978
-     * @throws EE_Error
979
-     * @throws InvalidArgumentException
980
-     * @throws ReflectionException
981
-     * @throws InvalidDataTypeException
982
-     * @throws InvalidInterfaceException
983
-     */
984
-    public static function send_message_with_messenger_only(
985
-        $messenger,
986
-        $message_type,
987
-        EE_Messages_Queue $queue,
988
-        $custom_subject = ''
989
-    ) {
990
-        self::_load_controller();
991
-        /** @type EE_Message_To_Generate_From_Queue $message_to_generate */
992
-        $message_to_generate = EE_Registry::instance()->load_lib(
993
-            'Message_To_Generate_From_Queue',
994
-            array(
995
-                $messenger,
996
-                $message_type,
997
-                $queue,
998
-                $custom_subject,
999
-            )
1000
-        );
1001
-        return self::$_MSG_PROCESSOR->queue_for_sending($message_to_generate);
1002
-    }
1003
-
1004
-
1005
-    /**
1006
-     * Generates Messages immediately for EE_Message IDs (but only for the correct status for generation)
1007
-     *
1008
-     * @since 4.9.0
1009
-     * @param array $message_ids An array of message ids
1010
-     * @return bool|EE_Messages_Queue false if nothing was generated, EE_Messages_Queue containing generated
1011
-     *                           messages.
1012
-     * @throws EE_Error
1013
-     * @throws InvalidArgumentException
1014
-     * @throws InvalidDataTypeException
1015
-     * @throws InvalidInterfaceException
1016
-     * @throws ReflectionException
1017
-     */
1018
-    public static function generate_now($message_ids)
1019
-    {
1020
-        self::_load_controller();
1021
-        $messages        = EEM_Message::instance()->get_all(
1022
-            array(
1023
-                0 => array(
1024
-                    'MSG_ID' => array('IN', $message_ids),
1025
-                    'STS_ID' => EEM_Message::status_incomplete,
1026
-                ),
1027
-            )
1028
-        );
1029
-        $generated_queue = false;
1030
-        if ($messages) {
1031
-            $generated_queue = self::$_MSG_PROCESSOR->batch_generate_from_queue($messages);
1032
-        }
1033
-
1034
-        if (! $generated_queue instanceof EE_Messages_Queue) {
1035
-            EE_Error::add_error(
1036
-                __('The messages were not generated. This could mean there is already a batch being generated on a separate request, or because the selected messages are not ready for generation. Please wait a minute or two and try again.',
1037
-                    'event_espresso'),
1038
-                __FILE__, __FUNCTION__, __LINE__
1039
-            );
1040
-        }
1041
-        return $generated_queue;
1042
-    }
1043
-
1044
-
1045
-    /**
1046
-     * Sends messages immediately for the incoming message_ids that have the status of EEM_Message::status_resend or,
1047
-     * EEM_Message::status_idle
1048
-     *
1049
-     * @since 4.9.0
1050
-     * @param $message_ids
1051
-     * @return bool|EE_Messages_Queue false if no messages sent.
1052
-     * @throws EE_Error
1053
-     * @throws InvalidArgumentException
1054
-     * @throws InvalidDataTypeException
1055
-     * @throws InvalidInterfaceException
1056
-     * @throws ReflectionException
1057
-     */
1058
-    public static function send_now($message_ids)
1059
-    {
1060
-        self::_load_controller();
1061
-        $messages   = EEM_Message::instance()->get_all(
1062
-            array(
1063
-                0 => array(
1064
-                    'MSG_ID' => array('IN', $message_ids),
1065
-                    'STS_ID' => array(
1066
-                        'IN',
1067
-                        array(EEM_Message::status_idle, EEM_Message::status_resend, EEM_Message::status_retry),
1068
-                    ),
1069
-                ),
1070
-            )
1071
-        );
1072
-        $sent_queue = false;
1073
-        if ($messages) {
1074
-            $sent_queue = self::$_MSG_PROCESSOR->batch_send_from_queue($messages);
1075
-        }
1076
-
1077
-        if (! $sent_queue instanceof EE_Messages_Queue) {
1078
-            EE_Error::add_error(
1079
-                __('The messages were not sent. This could mean there is already a batch being sent on a separate request, or because the selected messages are not sendable. Please wait a minute or two and try again.',
1080
-                    'event_espresso'),
1081
-                __FILE__, __FUNCTION__, __LINE__
1082
-            );
1083
-        } else {
1084
-            //can count how many sent by using the messages in the queue
1085
-            $sent_count = $sent_queue->count_STS_in_queue(EEM_Message::instance()->stati_indicating_sent());
1086
-            if ($sent_count > 0) {
1087
-                EE_Error::add_success(
1088
-                    sprintf(
1089
-                        _n(
1090
-                            'There was %d message successfully sent.',
1091
-                            'There were %d messages successfully sent.',
1092
-                            $sent_count,
1093
-                            'event_espresso'
1094
-                        ),
1095
-                        $sent_count
1096
-                    )
1097
-                );
1098
-            } else {
1099
-                EE_Error::overwrite_errors();
1100
-                EE_Error::add_error(
1101
-                    __('No message was sent because of problems with sending. Either all the messages you selected were not a sendable message, they were ALREADY sent on a different scheduled task, or there was an error.
215
+				exit;
216
+			}
217
+		}
218
+		return;
219
+	}
220
+
221
+
222
+	/**
223
+	 *  This runs when the msg_url_trigger route has initiated.
224
+	 *
225
+	 * @since 4.5.0
226
+	 * @param WP $WP
227
+	 * @throws EE_Error
228
+	 * @throws InvalidArgumentException
229
+	 * @throws ReflectionException
230
+	 * @throws InvalidDataTypeException
231
+	 * @throws InvalidInterfaceException
232
+	 */
233
+	public function run($WP)
234
+	{
235
+		//ensure controller is loaded
236
+		self::_load_controller();
237
+		// attempt to process message
238
+		try {
239
+			/** @type EE_Message_To_Generate_From_Request $message_to_generate */
240
+			$message_to_generate = EE_Registry::instance()->load_lib('Message_To_Generate_From_Request');
241
+			self::$_MSG_PROCESSOR->generate_and_send_now($message_to_generate);
242
+		} catch (EE_Error $e) {
243
+			$error_msg = __('Please note that a system message failed to send due to a technical issue.',
244
+				'event_espresso');
245
+			// add specific message for developers if WP_DEBUG in on
246
+			$error_msg .= '||' . $e->getMessage();
247
+			EE_Error::add_error($error_msg, __FILE__, __FUNCTION__, __LINE__);
248
+		}
249
+	}
250
+
251
+
252
+	/**
253
+	 * This is triggered by the 'msg_cron_trigger' route.
254
+	 *
255
+	 * @param WP $WP
256
+	 */
257
+	public function execute_batch_request($WP)
258
+	{
259
+		$this->run_cron();
260
+		header('HTTP/1.1 200 OK');
261
+		exit();
262
+	}
263
+
264
+
265
+	/**
266
+	 * This gets executed on wp_cron jobs or when a batch request is initiated on its own separate non regular wp
267
+	 * request.
268
+	 */
269
+	public function run_cron()
270
+	{
271
+		self::_load_controller();
272
+		//get required vars
273
+		$cron_type     = EE_Registry::instance()->REQ->get('type');
274
+		$transient_key = EE_Registry::instance()->REQ->get('key');
275
+
276
+		//now let's verify transient, if not valid exit immediately
277
+		if (! get_transient($transient_key)) {
278
+			/**
279
+			 * trigger error so this gets in the error logs.  This is important because it happens on a non-user
280
+			 * request.
281
+			 */
282
+			trigger_error(esc_attr__('Invalid Request (Transient does not exist)', 'event_espresso'));
283
+		}
284
+
285
+		//if made it here, lets' delete the transient to keep the db clean
286
+		delete_transient($transient_key);
287
+
288
+		if (apply_filters('FHEE__EED_Messages__run_cron__use_wp_cron', true)) {
289
+
290
+			$method = 'batch_' . $cron_type . '_from_queue';
291
+			if (method_exists(self::$_MSG_PROCESSOR, $method)) {
292
+				self::$_MSG_PROCESSOR->$method();
293
+			} else {
294
+				//no matching task
295
+				/**
296
+				 * trigger error so this gets in the error logs.  This is important because it happens on a non user
297
+				 * request.
298
+				 */
299
+				trigger_error(esc_attr(sprintf(__('There is no task corresponding to this route %s', 'event_espresso'),
300
+					$cron_type)));
301
+			}
302
+		}
303
+
304
+		do_action('FHEE__EED_Messages__run_cron__end');
305
+	}
306
+
307
+
308
+	/**
309
+	 * This is used to retrieve the template pack for the given name.
310
+	 * Retrieved packs are cached on the static $_TMP_PACKS array.  If there is no class matching the given name then
311
+	 * the default template pack is returned.
312
+	 *
313
+	 * @deprecated 4.9.0  @see EEH_MSG_Template::get_template_pack()
314
+	 * @param string $template_pack_name This should correspond to the dbref of the template pack (which is also used
315
+	 *                                   in generating the Pack class name).
316
+	 * @return EE_Messages_Template_Pack
317
+	 * @throws EE_Error
318
+	 * @throws InvalidArgumentException
319
+	 * @throws ReflectionException
320
+	 * @throws InvalidDataTypeException
321
+	 * @throws InvalidInterfaceException
322
+	 */
323
+	public static function get_template_pack($template_pack_name)
324
+	{
325
+		EE_Registry::instance()->load_helper('MSG_Template');
326
+		return EEH_MSG_Template::get_template_pack($template_pack_name);
327
+	}
328
+
329
+
330
+	/**
331
+	 * Retrieves an array of all template packs.
332
+	 * Array is in the format array( 'dbref' => EE_Messages_Template_Pack )
333
+	 *
334
+	 * @deprecated 4.9.0  @see EEH_MSG_Template_Pack::get_template_pack_collection
335
+	 * @return EE_Messages_Template_Pack[]
336
+	 * @throws EE_Error
337
+	 * @throws InvalidArgumentException
338
+	 * @throws ReflectionException
339
+	 * @throws InvalidDataTypeException
340
+	 * @throws InvalidInterfaceException
341
+	 */
342
+	public static function get_template_packs()
343
+	{
344
+		EE_Registry::instance()->load_helper('MSG_Template');
345
+
346
+		//for backward compat, let's make sure this returns in the same format as originally.
347
+		$template_pack_collection = EEH_MSG_Template::get_template_pack_collection();
348
+		$template_pack_collection->rewind();
349
+		$template_packs = array();
350
+		while ($template_pack_collection->valid()) {
351
+			$template_packs[$template_pack_collection->current()->dbref] = $template_pack_collection->current();
352
+			$template_pack_collection->next();
353
+		}
354
+		return $template_packs;
355
+	}
356
+
357
+
358
+	/**
359
+	 * This simply makes sure the autoloaders are registered for the EE_messages system.
360
+	 *
361
+	 * @since 4.5.0
362
+	 * @return void
363
+	 * @throws EE_Error
364
+	 */
365
+	public static function set_autoloaders()
366
+	{
367
+		if (empty(self::$_MSG_PATHS)) {
368
+			self::_set_messages_paths();
369
+			foreach (self::$_MSG_PATHS as $path) {
370
+				EEH_Autoloader::register_autoloaders_for_each_file_in_folder($path);
371
+			}
372
+			// add aliases
373
+			EEH_Autoloader::add_alias('EE_messages', 'EE_messages');
374
+			EEH_Autoloader::add_alias('EE_messenger', 'EE_messenger');
375
+		}
376
+	}
377
+
378
+
379
+	/**
380
+	 * Take care of adding all the paths for the messages components to the $_MSG_PATHS property
381
+	 * for use by the Messages Autoloaders
382
+	 *
383
+	 * @since 4.5.0
384
+	 * @return void.
385
+	 */
386
+	protected static function _set_messages_paths()
387
+	{
388
+		$dir_ref = array(
389
+			'messages/message_type',
390
+			'messages/messenger',
391
+			'messages/defaults',
392
+			'messages/defaults/email',
393
+			'messages/data_class',
394
+			'messages/validators',
395
+			'messages/validators/email',
396
+			'messages/validators/html',
397
+			'shortcodes',
398
+		);
399
+		$paths   = array();
400
+		foreach ($dir_ref as $index => $dir) {
401
+			$paths[$index] = EE_LIBRARIES . $dir;
402
+		}
403
+		self::$_MSG_PATHS = apply_filters('FHEE__EED_Messages___set_messages_paths___MSG_PATHS', $paths);
404
+	}
405
+
406
+
407
+	/**
408
+	 * Takes care of loading dependencies
409
+	 *
410
+	 * @since 4.5.0
411
+	 * @return void
412
+	 * @throws EE_Error
413
+	 * @throws InvalidArgumentException
414
+	 * @throws ReflectionException
415
+	 * @throws InvalidDataTypeException
416
+	 * @throws InvalidInterfaceException
417
+	 */
418
+	protected static function _load_controller()
419
+	{
420
+		if (! self::$_MSG_PROCESSOR instanceof EE_Messages_Processor) {
421
+			EE_Registry::instance()->load_core('Request_Handler');
422
+			self::set_autoloaders();
423
+			self::$_EEMSG                    = EE_Registry::instance()->load_lib('messages');
424
+			self::$_MSG_PROCESSOR            = EE_Registry::instance()->load_lib('Messages_Processor');
425
+			self::$_message_resource_manager = EE_Registry::instance()->load_lib('Message_Resource_Manager');
426
+		}
427
+	}
428
+
429
+
430
+	/**
431
+	 * @param EE_Transaction $transaction
432
+	 * @throws EE_Error
433
+	 * @throws InvalidArgumentException
434
+	 * @throws InvalidDataTypeException
435
+	 * @throws InvalidInterfaceException
436
+	 * @throws ReflectionException
437
+	 */
438
+	public static function payment_reminder(EE_Transaction $transaction)
439
+	{
440
+		self::_load_controller();
441
+		$data = array($transaction, null);
442
+		self::$_MSG_PROCESSOR->generate_for_all_active_messengers('payment_reminder', $data);
443
+	}
444
+
445
+
446
+	/**
447
+	 * Any messages triggers for after successful gateway payments should go in here.
448
+	 *
449
+	 * @param EE_Transaction $transaction object
450
+	 * @param EE_Payment|null     $payment     object
451
+	 * @return void
452
+	 * @throws EE_Error
453
+	 * @throws InvalidArgumentException
454
+	 * @throws ReflectionException
455
+	 * @throws InvalidDataTypeException
456
+	 * @throws InvalidInterfaceException
457
+	 */
458
+	public static function payment(EE_Transaction $transaction, EE_Payment $payment = null)
459
+	{
460
+		//if there's no payment object, then we cannot do a payment type message!
461
+		if (! $payment instanceof EE_Payment) {
462
+			return;
463
+		}
464
+		self::_load_controller();
465
+		$data = array($transaction, $payment);
466
+		EE_Registry::instance()->load_helper('MSG_Template');
467
+		$message_type = EEH_MSG_Template::convert_payment_status_to_message_type($payment->STS_ID());
468
+		//if payment amount is less than 0 then switch to payment_refund message type.
469
+		$message_type = $payment->amount() < 0 ? 'payment_refund' : $message_type;
470
+		self::$_MSG_PROCESSOR->generate_for_all_active_messengers($message_type, $data);
471
+	}
472
+
473
+
474
+	/**
475
+	 * @param EE_Transaction $transaction
476
+	 * @throws EE_Error
477
+	 * @throws InvalidArgumentException
478
+	 * @throws InvalidDataTypeException
479
+	 * @throws InvalidInterfaceException
480
+	 * @throws ReflectionException
481
+	 */
482
+	public static function cancelled_registration(EE_Transaction $transaction)
483
+	{
484
+		self::_load_controller();
485
+		$data = array($transaction, null);
486
+		self::$_MSG_PROCESSOR->generate_for_all_active_messengers('cancelled_registration', $data);
487
+	}
488
+
489
+
490
+
491
+	/**
492
+	 * Trigger for Registration messages
493
+	 * Note that what registration message type is sent depends on what the reg status is for the registrations on the
494
+	 * incoming transaction.
495
+	 *
496
+	 * @param EE_Registration $registration
497
+	 * @param array           $extra_details
498
+	 * @return void
499
+	 * @throws EE_Error
500
+	 * @throws InvalidArgumentException
501
+	 * @throws InvalidDataTypeException
502
+	 * @throws InvalidInterfaceException
503
+	 * @throws ReflectionException
504
+	 * @throws EntityNotFoundException
505
+	 */
506
+	public static function maybe_registration(EE_Registration $registration, $extra_details = array())
507
+	{
508
+
509
+		if (! self::_verify_registration_notification_send($registration, $extra_details)) {
510
+			//no messages please
511
+			return;
512
+		}
513
+
514
+		// get all non-trashed registrations so we make sure we send messages for the right status.
515
+		$all_registrations = $registration->transaction()->registrations(
516
+			array(
517
+				array('REG_deleted' => false),
518
+				'order_by' => array(
519
+					'Event.EVT_name'     => 'ASC',
520
+					'Attendee.ATT_lname' => 'ASC',
521
+					'Attendee.ATT_fname' => 'ASC'
522
+				)
523
+			)
524
+		);
525
+		//cached array of statuses so we only trigger messages once per status.
526
+		$statuses_sent = array();
527
+		self::_load_controller();
528
+		$mtgs = array();
529
+
530
+		//loop through registrations and trigger messages once per status.
531
+		foreach ($all_registrations as $reg) {
532
+
533
+			//already triggered?
534
+			if (in_array($reg->status_ID(), $statuses_sent)) {
535
+				continue;
536
+			}
537
+
538
+			$message_type    = EEH_MSG_Template::convert_reg_status_to_message_type($reg->status_ID());
539
+			$mtgs            = array_merge(
540
+					$mtgs,
541
+					self::$_MSG_PROCESSOR->setup_mtgs_for_all_active_messengers(
542
+							$message_type,
543
+							array($registration->transaction(), null, $reg->status_ID())
544
+					)
545
+			);
546
+			$statuses_sent[] = $reg->status_ID();
547
+		}
548
+
549
+		if (count($statuses_sent) > 1) {
550
+			$mtgs = array_merge(
551
+				$mtgs,
552
+				self::$_MSG_PROCESSOR->setup_mtgs_for_all_active_messengers(
553
+					'registration_summary',
554
+					array($registration->transaction(), null)
555
+				)
556
+			);
557
+		}
558
+
559
+		//batch queue and initiate request
560
+		self::$_MSG_PROCESSOR->batch_queue_for_generation_and_persist($mtgs);
561
+		self::$_MSG_PROCESSOR->get_queue()->initiate_request_by_priority();
562
+	}
563
+
564
+
565
+	/**
566
+	 * This is a helper method used to very whether a registration notification should be sent or
567
+	 * not.  Prevents duplicate notifications going out for registration context notifications.
568
+	 *
569
+	 * @param EE_Registration $registration  [description]
570
+	 * @param array           $extra_details [description]
571
+	 * @return bool          true = send away, false = nope halt the presses.
572
+	 */
573
+	protected static function _verify_registration_notification_send(
574
+		EE_Registration $registration,
575
+		$extra_details = array()
576
+	) {
577
+		//self::log(
578
+		//	__CLASS__, __FUNCTION__, __LINE__,
579
+		//	$registration->transaction(),
580
+		//	array( '$extra_details' => $extra_details )
581
+		//);
582
+		// currently only using this to send messages for the primary registrant
583
+		if (! $registration->is_primary_registrant()) {
584
+			return false;
585
+		}
586
+		// first we check if we're in admin and not doing front ajax
587
+		if (is_admin() && ! EE_FRONT_AJAX) {
588
+			//make sure appropriate admin params are set for sending messages
589
+			if (empty($_REQUEST['txn_reg_status_change']['send_notifications']) || ! absint($_REQUEST['txn_reg_status_change']['send_notifications'])) {
590
+				//no messages sent please.
591
+				return false;
592
+			}
593
+		} else {
594
+			// frontend request (either regular or via AJAX)
595
+			// TXN is NOT finalized ?
596
+			if (! isset($extra_details['finalized']) || $extra_details['finalized'] === false) {
597
+				return false;
598
+			}
599
+			// return visit but nothing changed ???
600
+			if (
601
+				isset($extra_details['revisit'], $extra_details['status_updates']) &&
602
+				$extra_details['revisit'] && ! $extra_details['status_updates']
603
+			) {
604
+				return false;
605
+			}
606
+			// NOT sending messages && reg status is something other than "Not-Approved"
607
+			if (
608
+				! apply_filters('FHEE__EED_Messages___maybe_registration__deliver_notifications', false) &&
609
+				$registration->status_ID() !== EEM_Registration::status_id_not_approved
610
+			) {
611
+				return false;
612
+			}
613
+		}
614
+		// release the kraken
615
+		return true;
616
+	}
617
+
618
+
619
+	/**
620
+	 * Simply returns an array indexed by Registration Status ID and the related message_type name associated with that
621
+	 * status id.
622
+	 *
623
+	 * @deprecated 4.9.0  Use EEH_MSG_Template::reg_status_to_message_type_array()
624
+	 *                    or EEH_MSG_Template::convert_reg_status_to_message_type
625
+	 * @param string $reg_status
626
+	 * @return array
627
+	 * @throws EE_Error
628
+	 * @throws InvalidArgumentException
629
+	 * @throws ReflectionException
630
+	 * @throws InvalidDataTypeException
631
+	 * @throws InvalidInterfaceException
632
+	 */
633
+	protected static function _get_reg_status_array($reg_status = '')
634
+	{
635
+		EE_Registry::instance()->load_helper('MSG_Template');
636
+		return EEH_MSG_Template::convert_reg_status_to_message_type($reg_status)
637
+			? EEH_MSG_Template::convert_reg_status_to_message_type($reg_status)
638
+			: EEH_MSG_Template::reg_status_to_message_type_array();
639
+	}
640
+
641
+
642
+	/**
643
+	 * Simply returns the payment message type for the given payment status.
644
+	 *
645
+	 * @deprecated 4.9.0 Use EEH_MSG_Template::payment_status_to_message_type_array
646
+	 *                   or EEH_MSG_Template::convert_payment_status_to_message_type
647
+	 * @param string $payment_status The payment status being matched.
648
+	 * @return bool|string The payment message type slug matching the status or false if no match.
649
+	 * @throws EE_Error
650
+	 * @throws InvalidArgumentException
651
+	 * @throws ReflectionException
652
+	 * @throws InvalidDataTypeException
653
+	 * @throws InvalidInterfaceException
654
+	 */
655
+	protected static function _get_payment_message_type($payment_status)
656
+	{
657
+		EE_Registry::instance()->load_helper('MSG_Template');
658
+		return EEH_MSG_Template::convert_payment_status_to_message_type($payment_status)
659
+			? EEH_MSG_Template::convert_payment_status_to_message_type($payment_status)
660
+			: false;
661
+	}
662
+
663
+
664
+	/**
665
+	 * Message triggers for a resending already sent message(s) (via EE_Message list table)
666
+	 *
667
+	 * @access public
668
+	 * @param array $req_data This is the $_POST & $_GET data sent from EE_Admin Pages
669
+	 * @return bool success/fail
670
+	 * @throws EE_Error
671
+	 * @throws InvalidArgumentException
672
+	 * @throws InvalidDataTypeException
673
+	 * @throws InvalidInterfaceException
674
+	 * @throws ReflectionException
675
+	 */
676
+	public static function process_resend($req_data)
677
+	{
678
+		self::_load_controller();
679
+
680
+		//if $msgID in this request then skip to the new resend_message
681
+		if (EE_Registry::instance()->REQ->get('MSG_ID')) {
682
+			return self::resend_message();
683
+		}
684
+
685
+		//make sure any incoming request data is set on the REQ so that it gets picked up later.
686
+		$req_data = (array)$req_data;
687
+		foreach ($req_data as $request_key => $request_value) {
688
+			EE_Registry::instance()->REQ->set($request_key, $request_value);
689
+		}
690
+
691
+		if (! $messages_to_send = self::$_MSG_PROCESSOR->setup_messages_to_generate_from_registration_ids_in_request()) {
692
+			return false;
693
+		}
694
+
695
+		try {
696
+			self::$_MSG_PROCESSOR->batch_queue_for_generation_and_persist($messages_to_send);
697
+			self::$_MSG_PROCESSOR->get_queue()->initiate_request_by_priority();
698
+		} catch (EE_Error $e) {
699
+			EE_Error::add_error($e->getMessage(), __FILE__, __FUNCTION__, __LINE__);
700
+			return false;
701
+		}
702
+		EE_Error::add_success(
703
+			__('Messages have been successfully queued for generation and sending.', 'event_espresso')
704
+		);
705
+		return true; //everything got queued.
706
+	}
707
+
708
+
709
+	/**
710
+	 * Message triggers for a resending already sent message(s) (via EE_Message list table)
711
+	 *
712
+	 * @return bool
713
+	 * @throws EE_Error
714
+	 * @throws InvalidArgumentException
715
+	 * @throws InvalidDataTypeException
716
+	 * @throws InvalidInterfaceException
717
+	 * @throws ReflectionException
718
+	 */
719
+	public static function resend_message()
720
+	{
721
+		self::_load_controller();
722
+
723
+		$msgID = EE_Registry::instance()->REQ->get('MSG_ID');
724
+		if (! $msgID) {
725
+			EE_Error::add_error(__('Something went wrong because there is no "MSG_ID" value in the request',
726
+				'event_espresso'), __FILE__, __FUNCTION__, __LINE__);
727
+			return false;
728
+		}
729
+
730
+		self::$_MSG_PROCESSOR->setup_messages_from_ids_and_send((array)$msgID);
731
+
732
+		//setup success message.
733
+		$count_ready_for_resend = self::$_MSG_PROCESSOR->get_queue()->count_STS_in_queue(EEM_Message::status_resend);
734
+		EE_Error::add_success(sprintf(
735
+			_n(
736
+				'There was %d message queued for resending.',
737
+				'There were %d messages queued for resending.',
738
+				$count_ready_for_resend,
739
+				'event_espresso'
740
+			),
741
+			$count_ready_for_resend
742
+		));
743
+		return true;
744
+	}
745
+
746
+
747
+	/**
748
+	 * Message triggers for manual payment applied by admin
749
+	 *
750
+	 * @param  EE_Payment $payment EE_payment object
751
+	 * @return bool success/fail
752
+	 * @throws EE_Error
753
+	 * @throws InvalidArgumentException
754
+	 * @throws ReflectionException
755
+	 * @throws InvalidDataTypeException
756
+	 * @throws InvalidInterfaceException
757
+	 */
758
+	public static function process_admin_payment(EE_Payment $payment)
759
+	{
760
+		EE_Registry::instance()->load_helper('MSG_Template');
761
+		//we need to get the transaction object
762
+		$transaction = $payment->transaction();
763
+		if ($transaction instanceof EE_Transaction) {
764
+			$data         = array($transaction, $payment);
765
+			$message_type = EEH_MSG_Template::convert_payment_status_to_message_type($payment->STS_ID());
766
+
767
+			//if payment amount is less than 0 then switch to payment_refund message type.
768
+			$message_type = $payment->amount() < 0 ? 'payment_refund' : $message_type;
769
+
770
+			//if payment_refund is selected, but the status is NOT accepted.  Then change message type to false so NO message notification goes out.
771
+			$message_type = $message_type == 'payment_refund' && $payment->STS_ID() != EEM_Payment::status_id_approved ? false : $message_type;
772
+
773
+			self::_load_controller();
774
+
775
+			self::$_MSG_PROCESSOR->generate_for_all_active_messengers($message_type, $data);
776
+
777
+			//get count of queued for generation
778
+			$count_to_generate = self::$_MSG_PROCESSOR->get_queue()->count_STS_in_queue(array(
779
+				EEM_Message::status_incomplete,
780
+				EEM_Message::status_idle,
781
+			));
782
+
783
+			if ($count_to_generate > 0 && self::$_MSG_PROCESSOR->get_queue()->get_message_repository()->count() !== 0) {
784
+				add_filter('FHEE__EE_Admin_Page___process_admin_payment_notification__success', '__return_true');
785
+				return true;
786
+			} else {
787
+				$count_failed = self::$_MSG_PROCESSOR->get_queue()->count_STS_in_queue(EEM_Message::instance()->stati_indicating_failed_sending());
788
+				/**
789
+				 * Verify that there are actually errors.  If not then we return a success message because the queue might have been emptied due to successful
790
+				 * IMMEDIATE generation.
791
+				 */
792
+				if ($count_failed > 0) {
793
+					EE_Error::add_error(sprintf(
794
+						_n(
795
+							'The payment notification generation failed.',
796
+							'%d payment notifications failed being sent.',
797
+							$count_failed,
798
+							'event_espresso'
799
+						),
800
+						$count_failed
801
+					), __FILE__, __FUNCTION__, __LINE__);
802
+
803
+					return false;
804
+				} else {
805
+					add_filter('FHEE__EE_Admin_Page___process_admin_payment_notification__success', '__return_true');
806
+					return true;
807
+				}
808
+			}
809
+		} else {
810
+			EE_Error::add_error(
811
+				'Unable to generate the payment notification because the given value for the transaction is invalid.',
812
+				'event_espresso'
813
+			);
814
+			return false;
815
+		}
816
+	}
817
+
818
+
819
+	/**
820
+	 * Callback for AHEE__Extend_Registrations_Admin_Page___newsletter_selected_send_with_registrations trigger
821
+	 *
822
+	 * @since   4.3.0
823
+	 * @param  EE_Registration[] $registrations an array of EE_Registration objects
824
+	 * @param  int               $grp_id        a specific message template group id.
825
+	 * @return void
826
+	 * @throws EE_Error
827
+	 * @throws InvalidArgumentException
828
+	 * @throws InvalidDataTypeException
829
+	 * @throws InvalidInterfaceException
830
+	 * @throws ReflectionException
831
+	 */
832
+	public static function send_newsletter_message($registrations, $grp_id)
833
+	{
834
+		//make sure mtp is id and set it in the EE_Request Handler later messages setup.
835
+		EE_Registry::instance()->REQ->set('GRP_ID', (int)$grp_id);
836
+		self::_load_controller();
837
+		self::$_MSG_PROCESSOR->generate_for_all_active_messengers('newsletter', $registrations);
838
+	}
839
+
840
+
841
+	/**
842
+	 * Callback for FHEE__EE_Registration__invoice_url__invoice_url or FHEE__EE_Registration__receipt_url__receipt_url
843
+	 *
844
+	 * @since   4.3.0
845
+	 * @param    string          $registration_message_trigger_url
846
+	 * @param    EE_Registration $registration
847
+	 * @param string             $messenger
848
+	 * @param string             $message_type
849
+	 * @return string
850
+	 * @throws EE_Error
851
+	 * @throws InvalidArgumentException
852
+	 * @throws InvalidDataTypeException
853
+	 * @throws InvalidInterfaceException
854
+	 */
855
+	public static function registration_message_trigger_url(
856
+		$registration_message_trigger_url,
857
+		EE_Registration $registration,
858
+		$messenger = 'html',
859
+		$message_type = 'invoice'
860
+	) {
861
+		// whitelist $messenger
862
+		switch ($messenger) {
863
+			case 'pdf' :
864
+				$sending_messenger    = 'pdf';
865
+				$generating_messenger = 'html';
866
+				break;
867
+			case 'html' :
868
+			default :
869
+				$sending_messenger    = 'html';
870
+				$generating_messenger = 'html';
871
+				break;
872
+		}
873
+		// whitelist $message_type
874
+		switch ($message_type) {
875
+			case 'receipt' :
876
+				$message_type = 'receipt';
877
+				break;
878
+			case 'invoice' :
879
+			default :
880
+				$message_type = 'invoice';
881
+				break;
882
+		}
883
+		// verify that both the messenger AND the message type are active
884
+		if (EEH_MSG_Template::is_messenger_active($sending_messenger) && EEH_MSG_Template::is_mt_active($message_type)) {
885
+			//need to get the correct message template group for this (i.e. is there a custom invoice for the event this registration is registered for?)
886
+			$template_query_params = array(
887
+				'MTP_is_active'    => true,
888
+				'MTP_messenger'    => $generating_messenger,
889
+				'MTP_message_type' => $message_type,
890
+				'Event.EVT_ID'     => $registration->event_ID(),
891
+			);
892
+			//get the message template group.
893
+			$msg_template_group = EEM_Message_Template_Group::instance()->get_one(array($template_query_params));
894
+			//if we don't have an EE_Message_Template_Group then return
895
+			if (! $msg_template_group instanceof EE_Message_Template_Group) {
896
+				// remove EVT_ID from query params so that global templates get picked up
897
+				unset($template_query_params['Event.EVT_ID']);
898
+				//get global template as the fallback
899
+				$msg_template_group = EEM_Message_Template_Group::instance()->get_one(array($template_query_params));
900
+			}
901
+			//if we don't have an EE_Message_Template_Group then return
902
+			if (! $msg_template_group instanceof EE_Message_Template_Group) {
903
+				return '';
904
+			}
905
+			// generate the URL
906
+			$registration_message_trigger_url = EEH_MSG_Template::generate_url_trigger(
907
+				$sending_messenger,
908
+				$generating_messenger,
909
+				'purchaser',
910
+				$message_type,
911
+				$registration,
912
+				$msg_template_group->ID(),
913
+				$registration->transaction_ID()
914
+			);
915
+
916
+		}
917
+		return $registration_message_trigger_url;
918
+	}
919
+
920
+
921
+	/**
922
+	 * Use to generate and return a message preview!
923
+	 *
924
+	 * @param  string $type      This should correspond with a valid message type
925
+	 * @param  string $context   This should correspond with a valid context for the message type
926
+	 * @param  string $messenger This should correspond with a valid messenger.
927
+	 * @param bool    $send      true we will do a test send using the messenger delivery, false we just do a regular
928
+	 *                           preview
929
+	 * @return bool|string The body of the message or if send is requested, sends.
930
+	 * @throws EE_Error
931
+	 * @throws InvalidArgumentException
932
+	 * @throws InvalidDataTypeException
933
+	 * @throws InvalidInterfaceException
934
+	 * @throws ReflectionException
935
+	 */
936
+	public static function preview_message($type, $context, $messenger, $send = false)
937
+	{
938
+		self::_load_controller();
939
+		$mtg                     = new EE_Message_To_Generate(
940
+			$messenger,
941
+			$type,
942
+			array(),
943
+			$context,
944
+			true
945
+		);
946
+		$generated_preview_queue = self::$_MSG_PROCESSOR->generate_for_preview($mtg, $send);
947
+		if ($generated_preview_queue instanceof EE_Messages_Queue) {
948
+			//loop through all content for the preview and remove any persisted records.
949
+			$content = '';
950
+			foreach ($generated_preview_queue->get_message_repository() as $message) {
951
+				$content = $message->content();
952
+				if ($message->ID() > 0 && $message->STS_ID() !== EEM_Message::status_failed) {
953
+					$message->delete();
954
+				}
955
+			}
956
+			return $content;
957
+		} else {
958
+			return $generated_preview_queue;
959
+		}
960
+	}
961
+
962
+
963
+	/**
964
+	 * This is a method that allows for sending a message using a messenger matching the string given and the provided
965
+	 * EE_Message_Queue object.  The EE_Message_Queue object is used to create a single aggregate EE_Message via the
966
+	 * content found in the EE_Message objects in the queue.
967
+	 *
968
+	 * @since 4.9.0
969
+	 * @param string            $messenger            a string matching a valid active messenger in the system
970
+	 * @param string            $message_type         Although it seems contrary to the name of the method, a message
971
+	 *                                                type name is still required to send along the message type to the
972
+	 *                                                messenger because this is used for determining what specific
973
+	 *                                                variations might be loaded for the generated message.
974
+	 * @param EE_Messages_Queue $queue
975
+	 * @param string            $custom_subject       Can be used to set what the custom subject string will be on the
976
+	 *                                                aggregate EE_Message object.
977
+	 * @return bool success or fail.
978
+	 * @throws EE_Error
979
+	 * @throws InvalidArgumentException
980
+	 * @throws ReflectionException
981
+	 * @throws InvalidDataTypeException
982
+	 * @throws InvalidInterfaceException
983
+	 */
984
+	public static function send_message_with_messenger_only(
985
+		$messenger,
986
+		$message_type,
987
+		EE_Messages_Queue $queue,
988
+		$custom_subject = ''
989
+	) {
990
+		self::_load_controller();
991
+		/** @type EE_Message_To_Generate_From_Queue $message_to_generate */
992
+		$message_to_generate = EE_Registry::instance()->load_lib(
993
+			'Message_To_Generate_From_Queue',
994
+			array(
995
+				$messenger,
996
+				$message_type,
997
+				$queue,
998
+				$custom_subject,
999
+			)
1000
+		);
1001
+		return self::$_MSG_PROCESSOR->queue_for_sending($message_to_generate);
1002
+	}
1003
+
1004
+
1005
+	/**
1006
+	 * Generates Messages immediately for EE_Message IDs (but only for the correct status for generation)
1007
+	 *
1008
+	 * @since 4.9.0
1009
+	 * @param array $message_ids An array of message ids
1010
+	 * @return bool|EE_Messages_Queue false if nothing was generated, EE_Messages_Queue containing generated
1011
+	 *                           messages.
1012
+	 * @throws EE_Error
1013
+	 * @throws InvalidArgumentException
1014
+	 * @throws InvalidDataTypeException
1015
+	 * @throws InvalidInterfaceException
1016
+	 * @throws ReflectionException
1017
+	 */
1018
+	public static function generate_now($message_ids)
1019
+	{
1020
+		self::_load_controller();
1021
+		$messages        = EEM_Message::instance()->get_all(
1022
+			array(
1023
+				0 => array(
1024
+					'MSG_ID' => array('IN', $message_ids),
1025
+					'STS_ID' => EEM_Message::status_incomplete,
1026
+				),
1027
+			)
1028
+		);
1029
+		$generated_queue = false;
1030
+		if ($messages) {
1031
+			$generated_queue = self::$_MSG_PROCESSOR->batch_generate_from_queue($messages);
1032
+		}
1033
+
1034
+		if (! $generated_queue instanceof EE_Messages_Queue) {
1035
+			EE_Error::add_error(
1036
+				__('The messages were not generated. This could mean there is already a batch being generated on a separate request, or because the selected messages are not ready for generation. Please wait a minute or two and try again.',
1037
+					'event_espresso'),
1038
+				__FILE__, __FUNCTION__, __LINE__
1039
+			);
1040
+		}
1041
+		return $generated_queue;
1042
+	}
1043
+
1044
+
1045
+	/**
1046
+	 * Sends messages immediately for the incoming message_ids that have the status of EEM_Message::status_resend or,
1047
+	 * EEM_Message::status_idle
1048
+	 *
1049
+	 * @since 4.9.0
1050
+	 * @param $message_ids
1051
+	 * @return bool|EE_Messages_Queue false if no messages sent.
1052
+	 * @throws EE_Error
1053
+	 * @throws InvalidArgumentException
1054
+	 * @throws InvalidDataTypeException
1055
+	 * @throws InvalidInterfaceException
1056
+	 * @throws ReflectionException
1057
+	 */
1058
+	public static function send_now($message_ids)
1059
+	{
1060
+		self::_load_controller();
1061
+		$messages   = EEM_Message::instance()->get_all(
1062
+			array(
1063
+				0 => array(
1064
+					'MSG_ID' => array('IN', $message_ids),
1065
+					'STS_ID' => array(
1066
+						'IN',
1067
+						array(EEM_Message::status_idle, EEM_Message::status_resend, EEM_Message::status_retry),
1068
+					),
1069
+				),
1070
+			)
1071
+		);
1072
+		$sent_queue = false;
1073
+		if ($messages) {
1074
+			$sent_queue = self::$_MSG_PROCESSOR->batch_send_from_queue($messages);
1075
+		}
1076
+
1077
+		if (! $sent_queue instanceof EE_Messages_Queue) {
1078
+			EE_Error::add_error(
1079
+				__('The messages were not sent. This could mean there is already a batch being sent on a separate request, or because the selected messages are not sendable. Please wait a minute or two and try again.',
1080
+					'event_espresso'),
1081
+				__FILE__, __FUNCTION__, __LINE__
1082
+			);
1083
+		} else {
1084
+			//can count how many sent by using the messages in the queue
1085
+			$sent_count = $sent_queue->count_STS_in_queue(EEM_Message::instance()->stati_indicating_sent());
1086
+			if ($sent_count > 0) {
1087
+				EE_Error::add_success(
1088
+					sprintf(
1089
+						_n(
1090
+							'There was %d message successfully sent.',
1091
+							'There were %d messages successfully sent.',
1092
+							$sent_count,
1093
+							'event_espresso'
1094
+						),
1095
+						$sent_count
1096
+					)
1097
+				);
1098
+			} else {
1099
+				EE_Error::overwrite_errors();
1100
+				EE_Error::add_error(
1101
+					__('No message was sent because of problems with sending. Either all the messages you selected were not a sendable message, they were ALREADY sent on a different scheduled task, or there was an error.
1102 1102
 					If there was an error, you can look at the messages in the message activity list table for any error messages.',
1103
-                        'event_espresso'),
1104
-                    __FILE__, __FUNCTION__, __LINE__
1105
-                );
1106
-            }
1107
-        }
1108
-        return $sent_queue;
1109
-    }
1110
-
1111
-
1112
-    /**
1113
-     * Generate and send immediately from the given $message_ids
1114
-     *
1115
-     * @param array $message_ids EE_Message entity ids.
1116
-     * @throws EE_Error
1117
-     * @throws InvalidArgumentException
1118
-     * @throws InvalidDataTypeException
1119
-     * @throws InvalidInterfaceException
1120
-     * @throws ReflectionException
1121
-     */
1122
-    public static function generate_and_send_now(array $message_ids)
1123
-    {
1124
-        $generated_queue = self::generate_now($message_ids);
1125
-        //now let's just trigger sending immediately from this queue.
1126
-        $messages_sent = $generated_queue instanceof EE_Messages_Queue
1127
-            ? $generated_queue->execute()
1128
-            : 0;
1129
-        if ($messages_sent) {
1130
-            EE_Error::add_success(
1131
-                esc_html(
1132
-                    sprintf(
1133
-                        _n(
1134
-                            'There was %d message successfully generated and sent.',
1135
-                            'There were %d messages successfully generated and sent.',
1136
-                            $messages_sent,
1137
-                            'event_espresso'
1138
-                        ),
1139
-                        $messages_sent
1140
-                    )
1141
-                )
1142
-            );
1143
-            //errors would be added via the generate_now method.
1144
-        }
1145
-    }
1146
-
1147
-
1148
-    /**
1149
-     * This will queue the incoming message ids for resending.
1150
-     * Note, only message_ids corresponding to messages with the status of EEM_Message::sent will be queued.
1151
-     *
1152
-     * @since 4.9.0
1153
-     * @param array $message_ids An array of EE_Message IDs
1154
-     * @return bool true means messages were successfully queued for resending, false means none were queued for
1155
-     *                           resending.
1156
-     * @throws EE_Error
1157
-     * @throws InvalidArgumentException
1158
-     * @throws InvalidDataTypeException
1159
-     * @throws InvalidInterfaceException
1160
-     * @throws ReflectionException
1161
-     */
1162
-    public static function queue_for_resending($message_ids)
1163
-    {
1164
-        self::_load_controller();
1165
-        self::$_MSG_PROCESSOR->setup_messages_from_ids_and_send($message_ids);
1166
-
1167
-        //get queue and count
1168
-        $queue_count = self::$_MSG_PROCESSOR->get_queue()->count_STS_in_queue(EEM_Message::status_resend);
1169
-
1170
-        if (
1171
-            $queue_count > 0
1172
-        ) {
1173
-            EE_Error::add_success(
1174
-                sprintf(
1175
-                    _n(
1176
-                        '%d message successfully queued for resending.',
1177
-                        '%d messages successfully queued for resending.',
1178
-                        $queue_count,
1179
-                        'event_espresso'
1180
-                    ),
1181
-                    $queue_count
1182
-                )
1183
-            );
1184
-            /**
1185
-             * @see filter usage in EE_Messages_Queue::initiate_request_by_priority
1186
-             */
1187
-        } elseif (
1188
-            apply_filters('FHEE__EE_Messages_Processor__initiate_request_by_priority__do_immediate_processing', true)
1189
-            || EE_Registry::instance()->NET_CFG->core->do_messages_on_same_request
1190
-        ) {
1191
-            $queue_count = self::$_MSG_PROCESSOR->get_queue()->count_STS_in_queue(EEM_Message::status_sent);
1192
-            if ($queue_count > 0) {
1193
-                EE_Error::add_success(
1194
-                    sprintf(
1195
-                        _n(
1196
-                            '%d message successfully sent.',
1197
-                            '%d messages successfully sent.',
1198
-                            $queue_count,
1199
-                            'event_espresso'
1200
-                        ),
1201
-                        $queue_count
1202
-                    )
1203
-                );
1204
-            } else {
1205
-                EE_Error::add_error(
1206
-                    __('No messages were queued for resending. This usually only happens when all the messages flagged for resending are not a status that can be resent.',
1207
-                        'event_espresso'),
1208
-                    __FILE__, __FUNCTION__, __LINE__
1209
-                );
1210
-            }
1211
-        } else {
1212
-            EE_Error::add_error(
1213
-                __('No messages were queued for resending. This usually only happens when all the messages flagged for resending are not a status that can be resent.',
1214
-                    'event_espresso'),
1215
-                __FILE__, __FUNCTION__, __LINE__
1216
-            );
1217
-        }
1218
-        return (bool)$queue_count;
1219
-    }
1220
-
1221
-
1222
-    /**
1223
-     * debug
1224
-     *
1225
-     * @param string          $class
1226
-     * @param string          $func
1227
-     * @param string          $line
1228
-     * @param \EE_Transaction $transaction
1229
-     * @param array           $info
1230
-     * @param bool            $display_request
1231
-     * @throws EE_Error
1232
-     * @throws \EventEspresso\core\exceptions\InvalidSessionDataException
1233
-     */
1234
-    protected static function log(
1235
-        $class = '',
1236
-        $func = '',
1237
-        $line = '',
1238
-        EE_Transaction $transaction,
1239
-        $info = array(),
1240
-        $display_request = false
1241
-    ) {
1242
-        if (defined('EE_DEBUG') && EE_DEBUG) {
1243
-            if ($transaction instanceof EE_Transaction) {
1244
-                // don't serialize objects
1245
-                $info                  = EEH_Debug_Tools::strip_objects($info);
1246
-                $info['TXN_status']    = $transaction->status_ID();
1247
-                $info['TXN_reg_steps'] = $transaction->reg_steps();
1248
-                if ($transaction->ID()) {
1249
-                    $index = 'EE_Transaction: ' . $transaction->ID();
1250
-                    EEH_Debug_Tools::log($class, $func, $line, $info, $display_request, $index);
1251
-                }
1252
-            }
1253
-        }
1254
-
1255
-    }
1256
-
1257
-
1258
-    /**
1259
-     *  Resets all the static properties in this class when called.
1260
-     */
1261
-    public static function reset()
1262
-    {
1263
-        self::$_EEMSG                    = null;
1264
-        self::$_message_resource_manager = null;
1265
-        self::$_MSG_PROCESSOR            = null;
1266
-        self::$_MSG_PATHS                = null;
1267
-        self::$_TMP_PACKS                = array();
1268
-    }
1103
+						'event_espresso'),
1104
+					__FILE__, __FUNCTION__, __LINE__
1105
+				);
1106
+			}
1107
+		}
1108
+		return $sent_queue;
1109
+	}
1110
+
1111
+
1112
+	/**
1113
+	 * Generate and send immediately from the given $message_ids
1114
+	 *
1115
+	 * @param array $message_ids EE_Message entity ids.
1116
+	 * @throws EE_Error
1117
+	 * @throws InvalidArgumentException
1118
+	 * @throws InvalidDataTypeException
1119
+	 * @throws InvalidInterfaceException
1120
+	 * @throws ReflectionException
1121
+	 */
1122
+	public static function generate_and_send_now(array $message_ids)
1123
+	{
1124
+		$generated_queue = self::generate_now($message_ids);
1125
+		//now let's just trigger sending immediately from this queue.
1126
+		$messages_sent = $generated_queue instanceof EE_Messages_Queue
1127
+			? $generated_queue->execute()
1128
+			: 0;
1129
+		if ($messages_sent) {
1130
+			EE_Error::add_success(
1131
+				esc_html(
1132
+					sprintf(
1133
+						_n(
1134
+							'There was %d message successfully generated and sent.',
1135
+							'There were %d messages successfully generated and sent.',
1136
+							$messages_sent,
1137
+							'event_espresso'
1138
+						),
1139
+						$messages_sent
1140
+					)
1141
+				)
1142
+			);
1143
+			//errors would be added via the generate_now method.
1144
+		}
1145
+	}
1146
+
1147
+
1148
+	/**
1149
+	 * This will queue the incoming message ids for resending.
1150
+	 * Note, only message_ids corresponding to messages with the status of EEM_Message::sent will be queued.
1151
+	 *
1152
+	 * @since 4.9.0
1153
+	 * @param array $message_ids An array of EE_Message IDs
1154
+	 * @return bool true means messages were successfully queued for resending, false means none were queued for
1155
+	 *                           resending.
1156
+	 * @throws EE_Error
1157
+	 * @throws InvalidArgumentException
1158
+	 * @throws InvalidDataTypeException
1159
+	 * @throws InvalidInterfaceException
1160
+	 * @throws ReflectionException
1161
+	 */
1162
+	public static function queue_for_resending($message_ids)
1163
+	{
1164
+		self::_load_controller();
1165
+		self::$_MSG_PROCESSOR->setup_messages_from_ids_and_send($message_ids);
1166
+
1167
+		//get queue and count
1168
+		$queue_count = self::$_MSG_PROCESSOR->get_queue()->count_STS_in_queue(EEM_Message::status_resend);
1169
+
1170
+		if (
1171
+			$queue_count > 0
1172
+		) {
1173
+			EE_Error::add_success(
1174
+				sprintf(
1175
+					_n(
1176
+						'%d message successfully queued for resending.',
1177
+						'%d messages successfully queued for resending.',
1178
+						$queue_count,
1179
+						'event_espresso'
1180
+					),
1181
+					$queue_count
1182
+				)
1183
+			);
1184
+			/**
1185
+			 * @see filter usage in EE_Messages_Queue::initiate_request_by_priority
1186
+			 */
1187
+		} elseif (
1188
+			apply_filters('FHEE__EE_Messages_Processor__initiate_request_by_priority__do_immediate_processing', true)
1189
+			|| EE_Registry::instance()->NET_CFG->core->do_messages_on_same_request
1190
+		) {
1191
+			$queue_count = self::$_MSG_PROCESSOR->get_queue()->count_STS_in_queue(EEM_Message::status_sent);
1192
+			if ($queue_count > 0) {
1193
+				EE_Error::add_success(
1194
+					sprintf(
1195
+						_n(
1196
+							'%d message successfully sent.',
1197
+							'%d messages successfully sent.',
1198
+							$queue_count,
1199
+							'event_espresso'
1200
+						),
1201
+						$queue_count
1202
+					)
1203
+				);
1204
+			} else {
1205
+				EE_Error::add_error(
1206
+					__('No messages were queued for resending. This usually only happens when all the messages flagged for resending are not a status that can be resent.',
1207
+						'event_espresso'),
1208
+					__FILE__, __FUNCTION__, __LINE__
1209
+				);
1210
+			}
1211
+		} else {
1212
+			EE_Error::add_error(
1213
+				__('No messages were queued for resending. This usually only happens when all the messages flagged for resending are not a status that can be resent.',
1214
+					'event_espresso'),
1215
+				__FILE__, __FUNCTION__, __LINE__
1216
+			);
1217
+		}
1218
+		return (bool)$queue_count;
1219
+	}
1220
+
1221
+
1222
+	/**
1223
+	 * debug
1224
+	 *
1225
+	 * @param string          $class
1226
+	 * @param string          $func
1227
+	 * @param string          $line
1228
+	 * @param \EE_Transaction $transaction
1229
+	 * @param array           $info
1230
+	 * @param bool            $display_request
1231
+	 * @throws EE_Error
1232
+	 * @throws \EventEspresso\core\exceptions\InvalidSessionDataException
1233
+	 */
1234
+	protected static function log(
1235
+		$class = '',
1236
+		$func = '',
1237
+		$line = '',
1238
+		EE_Transaction $transaction,
1239
+		$info = array(),
1240
+		$display_request = false
1241
+	) {
1242
+		if (defined('EE_DEBUG') && EE_DEBUG) {
1243
+			if ($transaction instanceof EE_Transaction) {
1244
+				// don't serialize objects
1245
+				$info                  = EEH_Debug_Tools::strip_objects($info);
1246
+				$info['TXN_status']    = $transaction->status_ID();
1247
+				$info['TXN_reg_steps'] = $transaction->reg_steps();
1248
+				if ($transaction->ID()) {
1249
+					$index = 'EE_Transaction: ' . $transaction->ID();
1250
+					EEH_Debug_Tools::log($class, $func, $line, $info, $display_request, $index);
1251
+				}
1252
+			}
1253
+		}
1254
+
1255
+	}
1256
+
1257
+
1258
+	/**
1259
+	 *  Resets all the static properties in this class when called.
1260
+	 */
1261
+	public static function reset()
1262
+	{
1263
+		self::$_EEMSG                    = null;
1264
+		self::$_message_resource_manager = null;
1265
+		self::$_MSG_PROCESSOR            = null;
1266
+		self::$_MSG_PATHS                = null;
1267
+		self::$_TMP_PACKS                = array();
1268
+	}
1269 1269
 
1270 1270
 }
1271 1271
 // End of file EED_Messages.module.php
Please login to merge, or discard this patch.
Spacing   +25 added lines, -25 removed lines patch added patch discarded remove patch
@@ -160,7 +160,7 @@  discard block
 block discarded – undo
160 160
             $error_msg = __('Please note that a system message failed to send due to a technical issue.',
161 161
                 'event_espresso');
162 162
             // add specific message for developers if WP_DEBUG in on
163
-            $error_msg .= '||' . $e->getMessage();
163
+            $error_msg .= '||'.$e->getMessage();
164 164
             EE_Error::add_error($error_msg, __FILE__, __FUNCTION__, __LINE__);
165 165
         }
166 166
     }
@@ -243,7 +243,7 @@  discard block
 block discarded – undo
243 243
             $error_msg = __('Please note that a system message failed to send due to a technical issue.',
244 244
                 'event_espresso');
245 245
             // add specific message for developers if WP_DEBUG in on
246
-            $error_msg .= '||' . $e->getMessage();
246
+            $error_msg .= '||'.$e->getMessage();
247 247
             EE_Error::add_error($error_msg, __FILE__, __FUNCTION__, __LINE__);
248 248
         }
249 249
     }
@@ -274,7 +274,7 @@  discard block
 block discarded – undo
274 274
         $transient_key = EE_Registry::instance()->REQ->get('key');
275 275
 
276 276
         //now let's verify transient, if not valid exit immediately
277
-        if (! get_transient($transient_key)) {
277
+        if ( ! get_transient($transient_key)) {
278 278
             /**
279 279
              * trigger error so this gets in the error logs.  This is important because it happens on a non-user
280 280
              * request.
@@ -287,7 +287,7 @@  discard block
 block discarded – undo
287 287
 
288 288
         if (apply_filters('FHEE__EED_Messages__run_cron__use_wp_cron', true)) {
289 289
 
290
-            $method = 'batch_' . $cron_type . '_from_queue';
290
+            $method = 'batch_'.$cron_type.'_from_queue';
291 291
             if (method_exists(self::$_MSG_PROCESSOR, $method)) {
292 292
                 self::$_MSG_PROCESSOR->$method();
293 293
             } else {
@@ -396,9 +396,9 @@  discard block
 block discarded – undo
396 396
             'messages/validators/html',
397 397
             'shortcodes',
398 398
         );
399
-        $paths   = array();
399
+        $paths = array();
400 400
         foreach ($dir_ref as $index => $dir) {
401
-            $paths[$index] = EE_LIBRARIES . $dir;
401
+            $paths[$index] = EE_LIBRARIES.$dir;
402 402
         }
403 403
         self::$_MSG_PATHS = apply_filters('FHEE__EED_Messages___set_messages_paths___MSG_PATHS', $paths);
404 404
     }
@@ -417,7 +417,7 @@  discard block
 block discarded – undo
417 417
      */
418 418
     protected static function _load_controller()
419 419
     {
420
-        if (! self::$_MSG_PROCESSOR instanceof EE_Messages_Processor) {
420
+        if ( ! self::$_MSG_PROCESSOR instanceof EE_Messages_Processor) {
421 421
             EE_Registry::instance()->load_core('Request_Handler');
422 422
             self::set_autoloaders();
423 423
             self::$_EEMSG                    = EE_Registry::instance()->load_lib('messages');
@@ -458,7 +458,7 @@  discard block
 block discarded – undo
458 458
     public static function payment(EE_Transaction $transaction, EE_Payment $payment = null)
459 459
     {
460 460
         //if there's no payment object, then we cannot do a payment type message!
461
-        if (! $payment instanceof EE_Payment) {
461
+        if ( ! $payment instanceof EE_Payment) {
462 462
             return;
463 463
         }
464 464
         self::_load_controller();
@@ -506,7 +506,7 @@  discard block
 block discarded – undo
506 506
     public static function maybe_registration(EE_Registration $registration, $extra_details = array())
507 507
     {
508 508
 
509
-        if (! self::_verify_registration_notification_send($registration, $extra_details)) {
509
+        if ( ! self::_verify_registration_notification_send($registration, $extra_details)) {
510 510
             //no messages please
511 511
             return;
512 512
         }
@@ -580,7 +580,7 @@  discard block
 block discarded – undo
580 580
         //	array( '$extra_details' => $extra_details )
581 581
         //);
582 582
         // currently only using this to send messages for the primary registrant
583
-        if (! $registration->is_primary_registrant()) {
583
+        if ( ! $registration->is_primary_registrant()) {
584 584
             return false;
585 585
         }
586 586
         // first we check if we're in admin and not doing front ajax
@@ -593,7 +593,7 @@  discard block
 block discarded – undo
593 593
         } else {
594 594
             // frontend request (either regular or via AJAX)
595 595
             // TXN is NOT finalized ?
596
-            if (! isset($extra_details['finalized']) || $extra_details['finalized'] === false) {
596
+            if ( ! isset($extra_details['finalized']) || $extra_details['finalized'] === false) {
597 597
                 return false;
598 598
             }
599 599
             // return visit but nothing changed ???
@@ -683,12 +683,12 @@  discard block
 block discarded – undo
683 683
         }
684 684
 
685 685
         //make sure any incoming request data is set on the REQ so that it gets picked up later.
686
-        $req_data = (array)$req_data;
686
+        $req_data = (array) $req_data;
687 687
         foreach ($req_data as $request_key => $request_value) {
688 688
             EE_Registry::instance()->REQ->set($request_key, $request_value);
689 689
         }
690 690
 
691
-        if (! $messages_to_send = self::$_MSG_PROCESSOR->setup_messages_to_generate_from_registration_ids_in_request()) {
691
+        if ( ! $messages_to_send = self::$_MSG_PROCESSOR->setup_messages_to_generate_from_registration_ids_in_request()) {
692 692
             return false;
693 693
         }
694 694
 
@@ -721,13 +721,13 @@  discard block
 block discarded – undo
721 721
         self::_load_controller();
722 722
 
723 723
         $msgID = EE_Registry::instance()->REQ->get('MSG_ID');
724
-        if (! $msgID) {
724
+        if ( ! $msgID) {
725 725
             EE_Error::add_error(__('Something went wrong because there is no "MSG_ID" value in the request',
726 726
                 'event_espresso'), __FILE__, __FUNCTION__, __LINE__);
727 727
             return false;
728 728
         }
729 729
 
730
-        self::$_MSG_PROCESSOR->setup_messages_from_ids_and_send((array)$msgID);
730
+        self::$_MSG_PROCESSOR->setup_messages_from_ids_and_send((array) $msgID);
731 731
 
732 732
         //setup success message.
733 733
         $count_ready_for_resend = self::$_MSG_PROCESSOR->get_queue()->count_STS_in_queue(EEM_Message::status_resend);
@@ -832,7 +832,7 @@  discard block
 block discarded – undo
832 832
     public static function send_newsletter_message($registrations, $grp_id)
833 833
     {
834 834
         //make sure mtp is id and set it in the EE_Request Handler later messages setup.
835
-        EE_Registry::instance()->REQ->set('GRP_ID', (int)$grp_id);
835
+        EE_Registry::instance()->REQ->set('GRP_ID', (int) $grp_id);
836 836
         self::_load_controller();
837 837
         self::$_MSG_PROCESSOR->generate_for_all_active_messengers('newsletter', $registrations);
838 838
     }
@@ -892,14 +892,14 @@  discard block
 block discarded – undo
892 892
             //get the message template group.
893 893
             $msg_template_group = EEM_Message_Template_Group::instance()->get_one(array($template_query_params));
894 894
             //if we don't have an EE_Message_Template_Group then return
895
-            if (! $msg_template_group instanceof EE_Message_Template_Group) {
895
+            if ( ! $msg_template_group instanceof EE_Message_Template_Group) {
896 896
                 // remove EVT_ID from query params so that global templates get picked up
897 897
                 unset($template_query_params['Event.EVT_ID']);
898 898
                 //get global template as the fallback
899 899
                 $msg_template_group = EEM_Message_Template_Group::instance()->get_one(array($template_query_params));
900 900
             }
901 901
             //if we don't have an EE_Message_Template_Group then return
902
-            if (! $msg_template_group instanceof EE_Message_Template_Group) {
902
+            if ( ! $msg_template_group instanceof EE_Message_Template_Group) {
903 903
                 return '';
904 904
             }
905 905
             // generate the URL
@@ -936,7 +936,7 @@  discard block
 block discarded – undo
936 936
     public static function preview_message($type, $context, $messenger, $send = false)
937 937
     {
938 938
         self::_load_controller();
939
-        $mtg                     = new EE_Message_To_Generate(
939
+        $mtg = new EE_Message_To_Generate(
940 940
             $messenger,
941 941
             $type,
942 942
             array(),
@@ -1018,7 +1018,7 @@  discard block
 block discarded – undo
1018 1018
     public static function generate_now($message_ids)
1019 1019
     {
1020 1020
         self::_load_controller();
1021
-        $messages        = EEM_Message::instance()->get_all(
1021
+        $messages = EEM_Message::instance()->get_all(
1022 1022
             array(
1023 1023
                 0 => array(
1024 1024
                     'MSG_ID' => array('IN', $message_ids),
@@ -1031,7 +1031,7 @@  discard block
 block discarded – undo
1031 1031
             $generated_queue = self::$_MSG_PROCESSOR->batch_generate_from_queue($messages);
1032 1032
         }
1033 1033
 
1034
-        if (! $generated_queue instanceof EE_Messages_Queue) {
1034
+        if ( ! $generated_queue instanceof EE_Messages_Queue) {
1035 1035
             EE_Error::add_error(
1036 1036
                 __('The messages were not generated. This could mean there is already a batch being generated on a separate request, or because the selected messages are not ready for generation. Please wait a minute or two and try again.',
1037 1037
                     'event_espresso'),
@@ -1058,7 +1058,7 @@  discard block
 block discarded – undo
1058 1058
     public static function send_now($message_ids)
1059 1059
     {
1060 1060
         self::_load_controller();
1061
-        $messages   = EEM_Message::instance()->get_all(
1061
+        $messages = EEM_Message::instance()->get_all(
1062 1062
             array(
1063 1063
                 0 => array(
1064 1064
                     'MSG_ID' => array('IN', $message_ids),
@@ -1074,7 +1074,7 @@  discard block
 block discarded – undo
1074 1074
             $sent_queue = self::$_MSG_PROCESSOR->batch_send_from_queue($messages);
1075 1075
         }
1076 1076
 
1077
-        if (! $sent_queue instanceof EE_Messages_Queue) {
1077
+        if ( ! $sent_queue instanceof EE_Messages_Queue) {
1078 1078
             EE_Error::add_error(
1079 1079
                 __('The messages were not sent. This could mean there is already a batch being sent on a separate request, or because the selected messages are not sendable. Please wait a minute or two and try again.',
1080 1080
                     'event_espresso'),
@@ -1215,7 +1215,7 @@  discard block
 block discarded – undo
1215 1215
                 __FILE__, __FUNCTION__, __LINE__
1216 1216
             );
1217 1217
         }
1218
-        return (bool)$queue_count;
1218
+        return (bool) $queue_count;
1219 1219
     }
1220 1220
 
1221 1221
 
@@ -1246,7 +1246,7 @@  discard block
 block discarded – undo
1246 1246
                 $info['TXN_status']    = $transaction->status_ID();
1247 1247
                 $info['TXN_reg_steps'] = $transaction->reg_steps();
1248 1248
                 if ($transaction->ID()) {
1249
-                    $index = 'EE_Transaction: ' . $transaction->ID();
1249
+                    $index = 'EE_Transaction: '.$transaction->ID();
1250 1250
                     EEH_Debug_Tools::log($class, $func, $line, $info, $display_request, $index);
1251 1251
                 }
1252 1252
             }
Please login to merge, or discard this patch.
core/libraries/messages/validators/EE_Messages_Validator.core.php 3 patches
Doc Comments   +1 added lines, -1 removed lines patch added patch discarded remove patch
@@ -505,7 +505,7 @@
 block discarded – undo
505 505
      *
506 506
      * @param  string $value            string to evaluate
507 507
      * @param  array  $valid_shortcodes array of shortcodes that are acceptable.
508
-     * @return mixed (bool|string)  return either a list of invalid shortcodes OR false if the shortcodes validate.
508
+     * @return false|string (bool|string)  return either a list of invalid shortcodes OR false if the shortcodes validate.
509 509
      */
510 510
     protected function _invalid_shortcodes($value, $valid_shortcodes)
511 511
     {
Please login to merge, or discard this patch.
Indentation   +626 added lines, -626 removed lines patch added patch discarded remove patch
@@ -1,7 +1,7 @@  discard block
 block discarded – undo
1 1
 <?php
2 2
 
3 3
 if (! defined('EVENT_ESPRESSO_VERSION')) {
4
-    exit('NO direct script access allowed');
4
+	exit('NO direct script access allowed');
5 5
 }
6 6
 
7 7
 /**
@@ -22,630 +22,630 @@  discard block
 block discarded – undo
22 22
 {
23 23
 
24 24
 
25
-    /**
26
-     * These properties just hold the name for the Messenger and Message Type (defined by child classes).
27
-     * These are used for retrieving objects etc.
28
-     *
29
-     * @var string
30
-     */
31
-    protected $_m_name;
32
-    protected $_mt_name;
33
-
34
-
35
-    /**
36
-     * This will hold any error messages from the validation process.
37
-     * The _errors property holds an associative array of error messages
38
-     * listing the field as the key and the message as the value.
39
-     *
40
-     * @var array()
41
-     */
42
-    private $_errors = array();
43
-
44
-
45
-    /**
46
-     * holds an array of fields being validated
47
-     *
48
-     * @var string
49
-     */
50
-    protected $_fields;
51
-
52
-
53
-    /**
54
-     * this will hold the incoming context
55
-     *
56
-     * @var string
57
-     */
58
-    protected $_context;
59
-
60
-
61
-    /**
62
-     * this holds an array of fields and the relevant validation information
63
-     * that the incoming fields data get validated against.
64
-     * This gets setup in the _set_props() method.
65
-     *
66
-     * @var array
67
-     */
68
-    protected $_validators;
69
-
70
-
71
-    /**
72
-     * holds the messenger object
73
-     *
74
-     * @var object
75
-     */
76
-    protected $_messenger;
77
-
78
-
79
-    /**
80
-     * holds the message type object
81
-     *
82
-     * @var object
83
-     */
84
-    protected $_message_type;
85
-
86
-
87
-    /**
88
-     * will hold any valid_shortcode modifications made by the _modify_validator() method.
89
-     *
90
-     * @var array
91
-     */
92
-    protected $_valid_shortcodes_modifier;
93
-
94
-
95
-    /**
96
-     * There may be times where a message type wants to include a shortcode group but exclude specific
97
-     * shortcodes.  If that's the case then it can set this property as an array of shortcodes to exclude and
98
-     * they will not be allowed.
99
-     * Array should be indexed by field and values are an array of specific shortcodes to exclude.
100
-     *
101
-     * @var array
102
-     */
103
-    protected $_specific_shortcode_excludes = array();
104
-
105
-
106
-    /**
107
-     * Runs the validator using the incoming fields array as the fields/values to check.
108
-     *
109
-     * @param array $fields The fields sent by the EEM object.
110
-     * @param       $context
111
-     * @throws \EE_Error
112
-     */
113
-    public function __construct($fields, $context)
114
-    {
115
-        //check that _m_name and _mt_name have been set by child class otherwise we get out.
116
-        if (empty($this->_m_name) || empty($this->_mt_name)) {
117
-            throw new EE_Error(
118
-                __(
119
-                    'EE_Messages_Validator child classes MUST set the $_m_name and $_mt_name property.  Check that the child class is doing this',
120
-                    'event_espresso'
121
-                )
122
-            );
123
-        }
124
-        $this->_fields  = $fields;
125
-        $this->_context = $context;
126
-
127
-        //load messenger and message_type objects and the related shortcode objects.
128
-        $this->_load_objects();
129
-
130
-
131
-        //modify any messenger/message_type specific validation instructions.  This is what child classes define.
132
-        $this->_modify_validator();
133
-
134
-
135
-        //let's set validators property
136
-        $this->_set_validators();
137
-    }
138
-
139
-
140
-    /**
141
-     * Child classes instantiate this and use it to modify the _validator_config array property
142
-     * for the messenger using messengers set_validate_config() method.
143
-     * This is so we can specify specific validation instructions for a messenger/message_type combo
144
-     * that aren't handled by the defaults setup in the messenger.
145
-     *
146
-     * @abstract
147
-     * @access protected
148
-     * @return void
149
-     */
150
-    abstract protected function _modify_validator();
151
-
152
-
153
-    /**
154
-     * loads all objects used by validator
155
-     *
156
-     * @access private
157
-     * @throws \EE_Error
158
-     */
159
-    private function _load_objects()
160
-    {
161
-        //load messenger
162
-        $messenger = ucwords(str_replace('_', ' ', $this->_m_name));
163
-        $messenger = str_replace(' ', '_', $messenger);
164
-        $messenger = 'EE_' . $messenger . '_messenger';
165
-
166
-        if (! class_exists($messenger)) {
167
-            throw new EE_Error(
168
-                sprintf(
169
-                    __('There is no messenger class for the given string (%s)', 'event_espresso'),
170
-                    $this->_m_name
171
-                )
172
-            );
173
-        }
174
-
175
-        $this->_messenger = new $messenger();
176
-
177
-        //load message type
178
-        $message_type = ucwords(str_replace('_', ' ', $this->_mt_name));
179
-        $message_type = str_replace(' ', '_', $message_type);
180
-        $message_type = 'EE_' . $message_type . '_message_type';
181
-
182
-        if (! class_exists($message_type)) {
183
-            throw new EE_Error(
184
-                sprintf(
185
-                    __('There is no message type class for the given string (%s)', 'event_espresso'),
186
-                    $this->_mt_name
187
-                )
188
-            );
189
-        }
190
-
191
-        $this->_message_type = new $message_type();
192
-
193
-    }
194
-
195
-
196
-    /**
197
-     * used to set the $_validators property
198
-     *
199
-     * @access private
200
-     * @return void
201
-     */
202
-    private function _set_validators()
203
-    {
204
-        // let's get all valid shortcodes from mt and message type
205
-        // (messenger will have its set in the _validator_config property for the messenger)
206
-        $mt_codes = $this->_message_type->get_valid_shortcodes();
207
-
208
-
209
-        //get messenger validator_config
210
-        $msgr_validator = $this->_messenger->get_validator_config();
211
-
212
-
213
-        //we only want the valid shortcodes for the given context!
214
-        $context  = $this->_context;
215
-        $mt_codes = $mt_codes[$context];
216
-
217
-        // in this first loop we're just getting all shortcode group indexes from the msgr_validator
218
-        // into a single array (so we can get the appropriate shortcode objects for the groups)
219
-        $shortcode_groups = $mt_codes;
220
-        $groups_per_field = array();
221
-
222
-        foreach ($msgr_validator as $field => $config) {
223
-            if (empty($config) || ! isset($config['shortcodes'])) {
224
-                continue;
225
-            }  //Nothing to see here.
226
-            $groups_per_field[$field] = array_intersect($config['shortcodes'], $mt_codes);
227
-            $shortcode_groups         = array_merge($config['shortcodes'], $shortcode_groups);
228
-        }
229
-
230
-        $shortcode_groups = array_unique($shortcode_groups);
231
-
232
-        // okay now we've got our groups.
233
-        // Let's get the codes from the objects into an array indexed by group for easy retrieval later.
234
-        $codes_from_objs = array();
235
-
236
-        foreach ($shortcode_groups as $group) {
237
-            $ref       = ucwords(str_replace('_', ' ', $group));
238
-            $ref       = str_replace(' ', '_', $ref);
239
-            $classname = 'EE_' . $ref . '_Shortcodes';
240
-            if (class_exists($classname)) {
241
-                $a                       = new ReflectionClass($classname);
242
-                $obj                     = $a->newInstance();
243
-                $codes_from_objs[$group] = $obj->get_shortcodes();
244
-            }
245
-        }
246
-
247
-
248
-        //let's just replace the $mt shortcode group indexes with the actual shortcodes (unique)
249
-        $final_mt_codes = array();
250
-        foreach ($mt_codes as $group) {
251
-            $final_mt_codes = array_merge($final_mt_codes, $codes_from_objs[$group]);
252
-        }
253
-
254
-        $mt_codes = $final_mt_codes;
255
-
256
-
257
-        // k now in this next loop we're going to loop through $msgr_validator again
258
-        // and setup the _validators property from the data we've setup so far.
259
-        foreach ($msgr_validator as $field => $config) {
260
-            //if required shortcode is not in our list of codes for the given field, then we skip this field.
261
-            $required = isset($config['required'])
262
-                ? array_intersect($config['required'], array_keys($mt_codes))
263
-                : true;
264
-            if (empty($required)) {
265
-                continue;
266
-            }
267
-
268
-            //If we have an override then we use it to indicate the codes we want.
269
-            if (isset($this->_valid_shortcodes_modifier[$context][$field])) {
270
-                $this->_validators[$field]['shortcodes'] = $this->_reassemble_valid_shortcodes_from_group(
271
-                    $this->_valid_shortcodes_modifier[$context][$field],
272
-                    $codes_from_objs
273
-                );
274
-            } //if we have specific shortcodes for a field then we need to use them
275
-            else if (isset($groups_per_field[$field])) {
276
-                $this->_validators[$field]['shortcodes'] = $this->_reassemble_valid_shortcodes_from_group(
277
-                    $groups_per_field[$field],
278
-                    $codes_from_objs
279
-                );
280
-            } //if empty config then we're assuming we're just going to use the shortcodes from the message type context
281
-            else if (empty($config)) {
282
-                $this->_validators[$field]['shortcodes'] = $mt_codes;
283
-            } //if we have specific shortcodes then we need to use them
284
-            else if (isset($config['specific_shortcodes'])) {
285
-                $this->_validators[$field]['shortcodes'] = $config['specific_shortcodes'];
286
-            } //otherwise the shortcodes are what is set by the messenger for that field
287
-            else {
288
-                foreach ($config['shortcodes'] as $group) {
289
-                    $this->_validators[$field]['shortcodes'] = isset($this->_validators[$field]['shortcodes'])
290
-                        ? array_merge($this->_validators[$field]['shortcodes'], $codes_from_objs[$group])
291
-                        : $codes_from_objs[$group];
292
-                }
293
-            }
294
-
295
-            //now let's just make sure that any excluded specific shortcodes are removed.
296
-            $specific_excludes = $this->get_specific_shortcode_excludes();
297
-            if (isset($specific_excludes[$field])) {
298
-                foreach ($specific_excludes[$field] as $sex) {
299
-                    if (isset($this->_validators[$field]['shortcodes'][$sex])) {
300
-                        unset($this->_validators[$field]['shortcodes'][$sex]);
301
-                    }
302
-                }
303
-            }
304
-
305
-            //hey! don't forget to include the type if present!
306
-            $this->_validators[$field]['type'] = isset($config['type']) ? $config['type'] : null;
307
-        }
308
-    }
309
-
310
-
311
-    /**
312
-     * This just returns the validators property that contains information
313
-     * about the various shortcodes and their availability with each field
314
-     *
315
-     * @return array
316
-     */
317
-    public function get_validators()
318
-    {
319
-        return $this->_validators;
320
-    }
321
-
322
-
323
-    /**
324
-     * This simply returns the specific shortcode_excludes property that is set.
325
-     *
326
-     * @since 4.5.0
327
-     * @return array
328
-     */
329
-    public function get_specific_shortcode_excludes()
330
-    {
331
-        //specific validator filter
332
-        $shortcode_excludes = apply_filters(
333
-            'FHEE__' . get_class($this) . '__get_specific_shortcode_excludes;',
334
-            $this->_specific_shortcode_excludes,
335
-            $this->_context
336
-        );
337
-        //global filter
338
-        return apply_filters(
339
-            'FHEE__EE_Messages_Validator__get_specific_shortcode_excludes',
340
-            $shortcode_excludes,
341
-            $this->_context,
342
-            $this
343
-        );
344
-    }
345
-
346
-
347
-    /**
348
-     * This is the main method that handles validation
349
-     * What it does is loop through the _fields (the ones that get validated)
350
-     * and checks them against the shortcodes array for the field and the 'type' indicated by the
351
-     *
352
-     * @access public
353
-     * @return mixed (bool|array)  if errors present we return the array otherwise true
354
-     */
355
-    public function validate()
356
-    {
357
-        //some defaults
358
-        $template_fields = $this->_messenger->get_template_fields();
359
-        //loop through the fields and check!
360
-        foreach ($this->_fields as $field => $value) {
361
-            $this->_errors[$field] = array();
362
-            $err_msg               = '';
363
-            $field_label           = '';
364
-            //if field is not present in the _validators array then we continue
365
-            if (! isset($this->_validators[$field])) {
366
-                unset($this->_errors[$field]);
367
-                continue;
368
-            }
369
-
370
-            //get the translated field label!
371
-            //first check if it's in the main fields list
372
-            if (isset($template_fields[$field])) {
373
-                if (empty($template_fields[$field])) {
374
-                    $field_label = $field;
375
-                } //most likely the field is found in the 'extra' array.
376
-                else {
377
-                    $field_label = $template_fields[$field]['label'];
378
-                }
379
-            }
380
-
381
-            // if field label is empty OR is equal to the current field
382
-            // then we need to loop through the 'extra' fields in the template_fields config (if present)
383
-            if (isset($template_fields['extra']) && (empty($field_label)) || $field_label == $field) {
384
-                foreach ($template_fields['extra'] as $main_field => $secondary_field) {
385
-                    foreach ($secondary_field as $name => $values) {
386
-                        if ($name == $field) {
387
-                            $field_label = $values['label'];
388
-                        }
389
-
390
-                        // if we've got a 'main' secondary field, let's see if that matches what field we're on
391
-                        // which means it contains the label for this field.
392
-                        if ($name == 'main' && $main_field == $field_label) {
393
-                            $field_label = $values['label'];
394
-                        }
395
-                    }
396
-                }
397
-            }
398
-
399
-            //field is present. Let's validate shortcodes first (but only if shortcodes present).
400
-            if (
401
-                isset($this->_validators[$field]['shortcodes'])
402
-                && ! empty($this->_validators[$field]['shortcodes'])
403
-            ) {
404
-                $invalid_shortcodes = $this->_invalid_shortcodes($value, $this->_validators[$field]['shortcodes']);
405
-                // if true then that means there is a returned error message
406
-                // that we'll need to add to the _errors array for this field.
407
-                if ($invalid_shortcodes) {
408
-                    $v_s     = array_keys($this->_validators[$field]['shortcodes']);
409
-                    $err_msg = sprintf(
410
-                        __(
411
-                            '%3$sThe following shortcodes were found in the "%1$s" field that ARE not valid: %2$s%4$s',
412
-                            'event_espresso'
413
-                        ),
414
-                        '<strong>' . $field_label . '</strong>',
415
-                        $invalid_shortcodes,
416
-                        '<p>',
417
-                        '</p >'
418
-                    );
419
-                    $err_msg .= sprintf(
420
-                        __('%2$sValid shortcodes for this field are: %1$s%3$s', 'event_espresso'),
421
-                        implode(', ', $v_s),
422
-                        '<strong>',
423
-                        '</strong>'
424
-                    );
425
-                }
426
-            }
427
-
428
-            //if there's a "type" to be validated then let's do that too.
429
-            if (isset($this->_validators[$field]['type']) && ! empty($this->_validators[$field]['type'])) {
430
-                switch ($this->_validators[$field]['type']) {
431
-                    case 'number' :
432
-                        if (! is_numeric($value)) {
433
-                            $err_msg .= sprintf(
434
-                                __(
435
-                                    '%3$sThe %1$s field is supposed to be a number. The value given (%2$s)  is not.  Please double-check and make sure the field contains a number%4$s',
436
-                                    'event_espresso'
437
-                                ),
438
-                                $field_label,
439
-                                $value,
440
-                                '<p>',
441
-                                '</p >'
442
-                            );
443
-                        }
444
-                        break;
445
-                    case 'email' :
446
-                        $valid_email = $this->_validate_email($value);
447
-                        if (! $valid_email) {
448
-                            $err_msg .= htmlentities(
449
-                                sprintf(
450
-                                    __(
451
-                                        'The %1$s field has at least one string that is not a valid email address record.  Valid emails are in the format: "Name <[email protected]>" or "[email protected]" and multiple emails can be separated by a comma.'
452
-                                    ),
453
-                                    $field_label
454
-
455
-                                )
456
-                            );
457
-                        }
458
-                        break;
459
-                    default :
460
-                        break;
461
-                }
462
-            }
463
-
464
-            //if $err_msg isn't empty let's setup the _errors array for this field.
465
-            if (! empty($err_msg)) {
466
-                $this->_errors[$field]['msg'] = $err_msg;
467
-            } else {
468
-                unset($this->_errors[$field]);
469
-            }
470
-        }
471
-
472
-        // if we have ANY errors, then we want to make sure we return the values
473
-        // for ALL the fields so the user doesn't have to retype them all.
474
-        if (! empty($this->_errors)) {
475
-            foreach ($this->_fields as $field => $value) {
476
-                $this->_errors[$field]['value'] = stripslashes($value);
477
-            }
478
-        }
479
-
480
-        //return any errors or just TRUE if everything validates
481
-        return empty($this->_errors) ? true : $this->_errors;
482
-    }
483
-
484
-
485
-    /**
486
-     * Reassembles and returns an array of valid shortcodes
487
-     * given the array of groups and array of shortcodes indexed by group.
488
-     *
489
-     * @param  array $groups          array of shortcode groups that we want shortcodes for
490
-     * @param  array $codes_from_objs All the codes available.
491
-     * @return array                   an array of actual shortcodes (that will be used for validation).
492
-     */
493
-    private function _reassemble_valid_shortcodes_from_group($groups, $codes_from_objs)
494
-    {
495
-        $shortcodes = array();
496
-        foreach ($groups as $group) {
497
-            $shortcodes = array_merge($shortcodes, $codes_from_objs[$group]);
498
-        }
499
-        return $shortcodes;
500
-    }
501
-
502
-
503
-    /**
504
-     * Validates a string against a list of accepted shortcodes
505
-     * This function takes in an array of shortcodes
506
-     * and makes sure that the given string ONLY contains shortcodes in that array.
507
-     *
508
-     * @param  string $value            string to evaluate
509
-     * @param  array  $valid_shortcodes array of shortcodes that are acceptable.
510
-     * @return mixed (bool|string)  return either a list of invalid shortcodes OR false if the shortcodes validate.
511
-     */
512
-    protected function _invalid_shortcodes($value, $valid_shortcodes)
513
-    {
514
-        //first we need to go through the string and get the shortcodes in the string
515
-        preg_match_all('/(\[.+?\])/', $value, $matches);
516
-        $incoming_shortcodes = (array)$matches[0];
517
-
518
-        //get a diff of the shortcodes in the string vs the valid shortcodes
519
-        $diff = array_diff($incoming_shortcodes, array_keys($valid_shortcodes));
520
-
521
-        //we need to account for custom codes so let's loop through the diff and remove any of those type of codes
522
-        foreach ($diff as $ind => $code) {
523
-            if (preg_match('/(\[[A-Za-z0-9\_]+_\*)/', $code)) {
524
-                //strip the shortcode so we just have the BASE string (i.e. [ANSWER_*] )
525
-                $dynamic_sc = preg_replace('/(_\*+.+)/', '_*]', $code);
526
-                //does this exist in the $valid_shortcodes?  If so then unset.
527
-                if (isset($valid_shortcodes[$dynamic_sc])) {
528
-                    unset($diff[$ind]);
529
-                }
530
-            }
531
-        }
532
-
533
-        if (empty($diff)) {
534
-            return false;
535
-        } //there is no diff, we have no invalid shortcodes, so return
536
-
537
-        //made it here? then let's assemble the error message
538
-        $invalid_shortcodes = implode('</strong>,<strong>', $diff);
539
-        $invalid_shortcodes = '<strong>' . $invalid_shortcodes . '</strong>';
540
-        return $invalid_shortcodes;
541
-    }
542
-
543
-
544
-    /**
545
-     * Validates an incoming string and makes sure we have valid emails in the string.
546
-     *
547
-     * @param  string $value incoming value to validate
548
-     * @return bool        true if the string validates, false if it doesn't
549
-     */
550
-    protected function _validate_email($value)
551
-    {
552
-        $validate = true;
553
-        $or_val   = $value;
554
-
555
-        // empty strings will validate because this is how a message template
556
-        // for a particular context can be "turned off" (if there is no email then no message)
557
-        if (empty($value)) {
558
-            return $validate;
559
-        }
560
-
561
-        // first determine if there ARE any shortcodes.
562
-        // If there are shortcodes and then later we find that there were no other valid emails
563
-        // but the field isn't empty...
564
-        // that means we've got extra commas that were left after stripping out shortcodes so probably still valid.
565
-        $has_shortcodes = preg_match('/(\[.+?\])/', $value);
566
-
567
-        //first we need to strip out all the shortcodes!
568
-        $value = preg_replace('/(\[.+?\])/', '', $value);
569
-
570
-        // if original value is not empty and new value is, then we've parsed out a shortcode
571
-        // and we now have an empty string which DOES validate.
572
-        // We also validate complete empty field for email because
573
-        // its possible that this message is being "turned off" for a particular context
574
-
575
-
576
-        if (! empty($or_val) && empty($value)) {
577
-            return $validate;
578
-        }
579
-
580
-        //trim any commas from beginning and end of string ( after whitespace trimmed );
581
-        $value = trim(trim($value), ',');
582
-
583
-
584
-        //next we need to split up the string if its comma delimited.
585
-        $emails = explode(',', $value);
586
-        $empty  = false; //used to indicate that there is an empty comma.
587
-        //now let's loop through the emails and do our checks
588
-        foreach ($emails as $email) {
589
-            if (empty($email)) {
590
-                $empty = true;
591
-                continue;
592
-            }
593
-
594
-            //trim whitespace
595
-            $email = trim($email);
596
-            //either its of type "[email protected]", or its of type "fname lname <[email protected]>"
597
-            if (is_email($email)) {
598
-                continue;
599
-            } else {
600
-                $matches  = array();
601
-                $validate = preg_match('/(.*)<(.+)>/', $email, $matches) ? true : false;
602
-                if ($validate && is_email($matches[2])) {
603
-                    continue;
604
-                } else {
605
-                    return false;
606
-                }
607
-            }
608
-        }
609
-
610
-        $validate = $empty && ! $has_shortcodes ? false : $validate;
611
-
612
-        return $validate;
613
-
614
-    }
615
-
616
-
617
-    /**
618
-     * Magic getter
619
-     * Using this to provide back compat with add-ons referencing deprecated properties.
620
-     *
621
-     * @param string $property Property being requested
622
-     * @throws Exception
623
-     * @return mixed
624
-     */
625
-    public function __get($property)
626
-    {
627
-        $expected_properties_map = array(
628
-            /**
629
-             * @deprecated 4.9.0
630
-             */
631
-            '_MSGR'   => '_messenger',
632
-            /**
633
-             * @deprecated 4.9.0
634
-             */
635
-            '_MSGTYP' => '_message_type',
636
-        );
637
-
638
-        if (isset($expected_properties_map[$property])) {
639
-            return $this->{$expected_properties_map[$property]};
640
-        }
641
-
642
-        throw new Exception(
643
-            sprintf(
644
-                __('The property %1$s being requested on %2$s does not exist', 'event_espresso'),
645
-                $property,
646
-                get_class($this)
647
-            )
648
-        );
649
-    }
25
+	/**
26
+	 * These properties just hold the name for the Messenger and Message Type (defined by child classes).
27
+	 * These are used for retrieving objects etc.
28
+	 *
29
+	 * @var string
30
+	 */
31
+	protected $_m_name;
32
+	protected $_mt_name;
33
+
34
+
35
+	/**
36
+	 * This will hold any error messages from the validation process.
37
+	 * The _errors property holds an associative array of error messages
38
+	 * listing the field as the key and the message as the value.
39
+	 *
40
+	 * @var array()
41
+	 */
42
+	private $_errors = array();
43
+
44
+
45
+	/**
46
+	 * holds an array of fields being validated
47
+	 *
48
+	 * @var string
49
+	 */
50
+	protected $_fields;
51
+
52
+
53
+	/**
54
+	 * this will hold the incoming context
55
+	 *
56
+	 * @var string
57
+	 */
58
+	protected $_context;
59
+
60
+
61
+	/**
62
+	 * this holds an array of fields and the relevant validation information
63
+	 * that the incoming fields data get validated against.
64
+	 * This gets setup in the _set_props() method.
65
+	 *
66
+	 * @var array
67
+	 */
68
+	protected $_validators;
69
+
70
+
71
+	/**
72
+	 * holds the messenger object
73
+	 *
74
+	 * @var object
75
+	 */
76
+	protected $_messenger;
77
+
78
+
79
+	/**
80
+	 * holds the message type object
81
+	 *
82
+	 * @var object
83
+	 */
84
+	protected $_message_type;
85
+
86
+
87
+	/**
88
+	 * will hold any valid_shortcode modifications made by the _modify_validator() method.
89
+	 *
90
+	 * @var array
91
+	 */
92
+	protected $_valid_shortcodes_modifier;
93
+
94
+
95
+	/**
96
+	 * There may be times where a message type wants to include a shortcode group but exclude specific
97
+	 * shortcodes.  If that's the case then it can set this property as an array of shortcodes to exclude and
98
+	 * they will not be allowed.
99
+	 * Array should be indexed by field and values are an array of specific shortcodes to exclude.
100
+	 *
101
+	 * @var array
102
+	 */
103
+	protected $_specific_shortcode_excludes = array();
104
+
105
+
106
+	/**
107
+	 * Runs the validator using the incoming fields array as the fields/values to check.
108
+	 *
109
+	 * @param array $fields The fields sent by the EEM object.
110
+	 * @param       $context
111
+	 * @throws \EE_Error
112
+	 */
113
+	public function __construct($fields, $context)
114
+	{
115
+		//check that _m_name and _mt_name have been set by child class otherwise we get out.
116
+		if (empty($this->_m_name) || empty($this->_mt_name)) {
117
+			throw new EE_Error(
118
+				__(
119
+					'EE_Messages_Validator child classes MUST set the $_m_name and $_mt_name property.  Check that the child class is doing this',
120
+					'event_espresso'
121
+				)
122
+			);
123
+		}
124
+		$this->_fields  = $fields;
125
+		$this->_context = $context;
126
+
127
+		//load messenger and message_type objects and the related shortcode objects.
128
+		$this->_load_objects();
129
+
130
+
131
+		//modify any messenger/message_type specific validation instructions.  This is what child classes define.
132
+		$this->_modify_validator();
133
+
134
+
135
+		//let's set validators property
136
+		$this->_set_validators();
137
+	}
138
+
139
+
140
+	/**
141
+	 * Child classes instantiate this and use it to modify the _validator_config array property
142
+	 * for the messenger using messengers set_validate_config() method.
143
+	 * This is so we can specify specific validation instructions for a messenger/message_type combo
144
+	 * that aren't handled by the defaults setup in the messenger.
145
+	 *
146
+	 * @abstract
147
+	 * @access protected
148
+	 * @return void
149
+	 */
150
+	abstract protected function _modify_validator();
151
+
152
+
153
+	/**
154
+	 * loads all objects used by validator
155
+	 *
156
+	 * @access private
157
+	 * @throws \EE_Error
158
+	 */
159
+	private function _load_objects()
160
+	{
161
+		//load messenger
162
+		$messenger = ucwords(str_replace('_', ' ', $this->_m_name));
163
+		$messenger = str_replace(' ', '_', $messenger);
164
+		$messenger = 'EE_' . $messenger . '_messenger';
165
+
166
+		if (! class_exists($messenger)) {
167
+			throw new EE_Error(
168
+				sprintf(
169
+					__('There is no messenger class for the given string (%s)', 'event_espresso'),
170
+					$this->_m_name
171
+				)
172
+			);
173
+		}
174
+
175
+		$this->_messenger = new $messenger();
176
+
177
+		//load message type
178
+		$message_type = ucwords(str_replace('_', ' ', $this->_mt_name));
179
+		$message_type = str_replace(' ', '_', $message_type);
180
+		$message_type = 'EE_' . $message_type . '_message_type';
181
+
182
+		if (! class_exists($message_type)) {
183
+			throw new EE_Error(
184
+				sprintf(
185
+					__('There is no message type class for the given string (%s)', 'event_espresso'),
186
+					$this->_mt_name
187
+				)
188
+			);
189
+		}
190
+
191
+		$this->_message_type = new $message_type();
192
+
193
+	}
194
+
195
+
196
+	/**
197
+	 * used to set the $_validators property
198
+	 *
199
+	 * @access private
200
+	 * @return void
201
+	 */
202
+	private function _set_validators()
203
+	{
204
+		// let's get all valid shortcodes from mt and message type
205
+		// (messenger will have its set in the _validator_config property for the messenger)
206
+		$mt_codes = $this->_message_type->get_valid_shortcodes();
207
+
208
+
209
+		//get messenger validator_config
210
+		$msgr_validator = $this->_messenger->get_validator_config();
211
+
212
+
213
+		//we only want the valid shortcodes for the given context!
214
+		$context  = $this->_context;
215
+		$mt_codes = $mt_codes[$context];
216
+
217
+		// in this first loop we're just getting all shortcode group indexes from the msgr_validator
218
+		// into a single array (so we can get the appropriate shortcode objects for the groups)
219
+		$shortcode_groups = $mt_codes;
220
+		$groups_per_field = array();
221
+
222
+		foreach ($msgr_validator as $field => $config) {
223
+			if (empty($config) || ! isset($config['shortcodes'])) {
224
+				continue;
225
+			}  //Nothing to see here.
226
+			$groups_per_field[$field] = array_intersect($config['shortcodes'], $mt_codes);
227
+			$shortcode_groups         = array_merge($config['shortcodes'], $shortcode_groups);
228
+		}
229
+
230
+		$shortcode_groups = array_unique($shortcode_groups);
231
+
232
+		// okay now we've got our groups.
233
+		// Let's get the codes from the objects into an array indexed by group for easy retrieval later.
234
+		$codes_from_objs = array();
235
+
236
+		foreach ($shortcode_groups as $group) {
237
+			$ref       = ucwords(str_replace('_', ' ', $group));
238
+			$ref       = str_replace(' ', '_', $ref);
239
+			$classname = 'EE_' . $ref . '_Shortcodes';
240
+			if (class_exists($classname)) {
241
+				$a                       = new ReflectionClass($classname);
242
+				$obj                     = $a->newInstance();
243
+				$codes_from_objs[$group] = $obj->get_shortcodes();
244
+			}
245
+		}
246
+
247
+
248
+		//let's just replace the $mt shortcode group indexes with the actual shortcodes (unique)
249
+		$final_mt_codes = array();
250
+		foreach ($mt_codes as $group) {
251
+			$final_mt_codes = array_merge($final_mt_codes, $codes_from_objs[$group]);
252
+		}
253
+
254
+		$mt_codes = $final_mt_codes;
255
+
256
+
257
+		// k now in this next loop we're going to loop through $msgr_validator again
258
+		// and setup the _validators property from the data we've setup so far.
259
+		foreach ($msgr_validator as $field => $config) {
260
+			//if required shortcode is not in our list of codes for the given field, then we skip this field.
261
+			$required = isset($config['required'])
262
+				? array_intersect($config['required'], array_keys($mt_codes))
263
+				: true;
264
+			if (empty($required)) {
265
+				continue;
266
+			}
267
+
268
+			//If we have an override then we use it to indicate the codes we want.
269
+			if (isset($this->_valid_shortcodes_modifier[$context][$field])) {
270
+				$this->_validators[$field]['shortcodes'] = $this->_reassemble_valid_shortcodes_from_group(
271
+					$this->_valid_shortcodes_modifier[$context][$field],
272
+					$codes_from_objs
273
+				);
274
+			} //if we have specific shortcodes for a field then we need to use them
275
+			else if (isset($groups_per_field[$field])) {
276
+				$this->_validators[$field]['shortcodes'] = $this->_reassemble_valid_shortcodes_from_group(
277
+					$groups_per_field[$field],
278
+					$codes_from_objs
279
+				);
280
+			} //if empty config then we're assuming we're just going to use the shortcodes from the message type context
281
+			else if (empty($config)) {
282
+				$this->_validators[$field]['shortcodes'] = $mt_codes;
283
+			} //if we have specific shortcodes then we need to use them
284
+			else if (isset($config['specific_shortcodes'])) {
285
+				$this->_validators[$field]['shortcodes'] = $config['specific_shortcodes'];
286
+			} //otherwise the shortcodes are what is set by the messenger for that field
287
+			else {
288
+				foreach ($config['shortcodes'] as $group) {
289
+					$this->_validators[$field]['shortcodes'] = isset($this->_validators[$field]['shortcodes'])
290
+						? array_merge($this->_validators[$field]['shortcodes'], $codes_from_objs[$group])
291
+						: $codes_from_objs[$group];
292
+				}
293
+			}
294
+
295
+			//now let's just make sure that any excluded specific shortcodes are removed.
296
+			$specific_excludes = $this->get_specific_shortcode_excludes();
297
+			if (isset($specific_excludes[$field])) {
298
+				foreach ($specific_excludes[$field] as $sex) {
299
+					if (isset($this->_validators[$field]['shortcodes'][$sex])) {
300
+						unset($this->_validators[$field]['shortcodes'][$sex]);
301
+					}
302
+				}
303
+			}
304
+
305
+			//hey! don't forget to include the type if present!
306
+			$this->_validators[$field]['type'] = isset($config['type']) ? $config['type'] : null;
307
+		}
308
+	}
309
+
310
+
311
+	/**
312
+	 * This just returns the validators property that contains information
313
+	 * about the various shortcodes and their availability with each field
314
+	 *
315
+	 * @return array
316
+	 */
317
+	public function get_validators()
318
+	{
319
+		return $this->_validators;
320
+	}
321
+
322
+
323
+	/**
324
+	 * This simply returns the specific shortcode_excludes property that is set.
325
+	 *
326
+	 * @since 4.5.0
327
+	 * @return array
328
+	 */
329
+	public function get_specific_shortcode_excludes()
330
+	{
331
+		//specific validator filter
332
+		$shortcode_excludes = apply_filters(
333
+			'FHEE__' . get_class($this) . '__get_specific_shortcode_excludes;',
334
+			$this->_specific_shortcode_excludes,
335
+			$this->_context
336
+		);
337
+		//global filter
338
+		return apply_filters(
339
+			'FHEE__EE_Messages_Validator__get_specific_shortcode_excludes',
340
+			$shortcode_excludes,
341
+			$this->_context,
342
+			$this
343
+		);
344
+	}
345
+
346
+
347
+	/**
348
+	 * This is the main method that handles validation
349
+	 * What it does is loop through the _fields (the ones that get validated)
350
+	 * and checks them against the shortcodes array for the field and the 'type' indicated by the
351
+	 *
352
+	 * @access public
353
+	 * @return mixed (bool|array)  if errors present we return the array otherwise true
354
+	 */
355
+	public function validate()
356
+	{
357
+		//some defaults
358
+		$template_fields = $this->_messenger->get_template_fields();
359
+		//loop through the fields and check!
360
+		foreach ($this->_fields as $field => $value) {
361
+			$this->_errors[$field] = array();
362
+			$err_msg               = '';
363
+			$field_label           = '';
364
+			//if field is not present in the _validators array then we continue
365
+			if (! isset($this->_validators[$field])) {
366
+				unset($this->_errors[$field]);
367
+				continue;
368
+			}
369
+
370
+			//get the translated field label!
371
+			//first check if it's in the main fields list
372
+			if (isset($template_fields[$field])) {
373
+				if (empty($template_fields[$field])) {
374
+					$field_label = $field;
375
+				} //most likely the field is found in the 'extra' array.
376
+				else {
377
+					$field_label = $template_fields[$field]['label'];
378
+				}
379
+			}
380
+
381
+			// if field label is empty OR is equal to the current field
382
+			// then we need to loop through the 'extra' fields in the template_fields config (if present)
383
+			if (isset($template_fields['extra']) && (empty($field_label)) || $field_label == $field) {
384
+				foreach ($template_fields['extra'] as $main_field => $secondary_field) {
385
+					foreach ($secondary_field as $name => $values) {
386
+						if ($name == $field) {
387
+							$field_label = $values['label'];
388
+						}
389
+
390
+						// if we've got a 'main' secondary field, let's see if that matches what field we're on
391
+						// which means it contains the label for this field.
392
+						if ($name == 'main' && $main_field == $field_label) {
393
+							$field_label = $values['label'];
394
+						}
395
+					}
396
+				}
397
+			}
398
+
399
+			//field is present. Let's validate shortcodes first (but only if shortcodes present).
400
+			if (
401
+				isset($this->_validators[$field]['shortcodes'])
402
+				&& ! empty($this->_validators[$field]['shortcodes'])
403
+			) {
404
+				$invalid_shortcodes = $this->_invalid_shortcodes($value, $this->_validators[$field]['shortcodes']);
405
+				// if true then that means there is a returned error message
406
+				// that we'll need to add to the _errors array for this field.
407
+				if ($invalid_shortcodes) {
408
+					$v_s     = array_keys($this->_validators[$field]['shortcodes']);
409
+					$err_msg = sprintf(
410
+						__(
411
+							'%3$sThe following shortcodes were found in the "%1$s" field that ARE not valid: %2$s%4$s',
412
+							'event_espresso'
413
+						),
414
+						'<strong>' . $field_label . '</strong>',
415
+						$invalid_shortcodes,
416
+						'<p>',
417
+						'</p >'
418
+					);
419
+					$err_msg .= sprintf(
420
+						__('%2$sValid shortcodes for this field are: %1$s%3$s', 'event_espresso'),
421
+						implode(', ', $v_s),
422
+						'<strong>',
423
+						'</strong>'
424
+					);
425
+				}
426
+			}
427
+
428
+			//if there's a "type" to be validated then let's do that too.
429
+			if (isset($this->_validators[$field]['type']) && ! empty($this->_validators[$field]['type'])) {
430
+				switch ($this->_validators[$field]['type']) {
431
+					case 'number' :
432
+						if (! is_numeric($value)) {
433
+							$err_msg .= sprintf(
434
+								__(
435
+									'%3$sThe %1$s field is supposed to be a number. The value given (%2$s)  is not.  Please double-check and make sure the field contains a number%4$s',
436
+									'event_espresso'
437
+								),
438
+								$field_label,
439
+								$value,
440
+								'<p>',
441
+								'</p >'
442
+							);
443
+						}
444
+						break;
445
+					case 'email' :
446
+						$valid_email = $this->_validate_email($value);
447
+						if (! $valid_email) {
448
+							$err_msg .= htmlentities(
449
+								sprintf(
450
+									__(
451
+										'The %1$s field has at least one string that is not a valid email address record.  Valid emails are in the format: "Name <[email protected]>" or "[email protected]" and multiple emails can be separated by a comma.'
452
+									),
453
+									$field_label
454
+
455
+								)
456
+							);
457
+						}
458
+						break;
459
+					default :
460
+						break;
461
+				}
462
+			}
463
+
464
+			//if $err_msg isn't empty let's setup the _errors array for this field.
465
+			if (! empty($err_msg)) {
466
+				$this->_errors[$field]['msg'] = $err_msg;
467
+			} else {
468
+				unset($this->_errors[$field]);
469
+			}
470
+		}
471
+
472
+		// if we have ANY errors, then we want to make sure we return the values
473
+		// for ALL the fields so the user doesn't have to retype them all.
474
+		if (! empty($this->_errors)) {
475
+			foreach ($this->_fields as $field => $value) {
476
+				$this->_errors[$field]['value'] = stripslashes($value);
477
+			}
478
+		}
479
+
480
+		//return any errors or just TRUE if everything validates
481
+		return empty($this->_errors) ? true : $this->_errors;
482
+	}
483
+
484
+
485
+	/**
486
+	 * Reassembles and returns an array of valid shortcodes
487
+	 * given the array of groups and array of shortcodes indexed by group.
488
+	 *
489
+	 * @param  array $groups          array of shortcode groups that we want shortcodes for
490
+	 * @param  array $codes_from_objs All the codes available.
491
+	 * @return array                   an array of actual shortcodes (that will be used for validation).
492
+	 */
493
+	private function _reassemble_valid_shortcodes_from_group($groups, $codes_from_objs)
494
+	{
495
+		$shortcodes = array();
496
+		foreach ($groups as $group) {
497
+			$shortcodes = array_merge($shortcodes, $codes_from_objs[$group]);
498
+		}
499
+		return $shortcodes;
500
+	}
501
+
502
+
503
+	/**
504
+	 * Validates a string against a list of accepted shortcodes
505
+	 * This function takes in an array of shortcodes
506
+	 * and makes sure that the given string ONLY contains shortcodes in that array.
507
+	 *
508
+	 * @param  string $value            string to evaluate
509
+	 * @param  array  $valid_shortcodes array of shortcodes that are acceptable.
510
+	 * @return mixed (bool|string)  return either a list of invalid shortcodes OR false if the shortcodes validate.
511
+	 */
512
+	protected function _invalid_shortcodes($value, $valid_shortcodes)
513
+	{
514
+		//first we need to go through the string and get the shortcodes in the string
515
+		preg_match_all('/(\[.+?\])/', $value, $matches);
516
+		$incoming_shortcodes = (array)$matches[0];
517
+
518
+		//get a diff of the shortcodes in the string vs the valid shortcodes
519
+		$diff = array_diff($incoming_shortcodes, array_keys($valid_shortcodes));
520
+
521
+		//we need to account for custom codes so let's loop through the diff and remove any of those type of codes
522
+		foreach ($diff as $ind => $code) {
523
+			if (preg_match('/(\[[A-Za-z0-9\_]+_\*)/', $code)) {
524
+				//strip the shortcode so we just have the BASE string (i.e. [ANSWER_*] )
525
+				$dynamic_sc = preg_replace('/(_\*+.+)/', '_*]', $code);
526
+				//does this exist in the $valid_shortcodes?  If so then unset.
527
+				if (isset($valid_shortcodes[$dynamic_sc])) {
528
+					unset($diff[$ind]);
529
+				}
530
+			}
531
+		}
532
+
533
+		if (empty($diff)) {
534
+			return false;
535
+		} //there is no diff, we have no invalid shortcodes, so return
536
+
537
+		//made it here? then let's assemble the error message
538
+		$invalid_shortcodes = implode('</strong>,<strong>', $diff);
539
+		$invalid_shortcodes = '<strong>' . $invalid_shortcodes . '</strong>';
540
+		return $invalid_shortcodes;
541
+	}
542
+
543
+
544
+	/**
545
+	 * Validates an incoming string and makes sure we have valid emails in the string.
546
+	 *
547
+	 * @param  string $value incoming value to validate
548
+	 * @return bool        true if the string validates, false if it doesn't
549
+	 */
550
+	protected function _validate_email($value)
551
+	{
552
+		$validate = true;
553
+		$or_val   = $value;
554
+
555
+		// empty strings will validate because this is how a message template
556
+		// for a particular context can be "turned off" (if there is no email then no message)
557
+		if (empty($value)) {
558
+			return $validate;
559
+		}
560
+
561
+		// first determine if there ARE any shortcodes.
562
+		// If there are shortcodes and then later we find that there were no other valid emails
563
+		// but the field isn't empty...
564
+		// that means we've got extra commas that were left after stripping out shortcodes so probably still valid.
565
+		$has_shortcodes = preg_match('/(\[.+?\])/', $value);
566
+
567
+		//first we need to strip out all the shortcodes!
568
+		$value = preg_replace('/(\[.+?\])/', '', $value);
569
+
570
+		// if original value is not empty and new value is, then we've parsed out a shortcode
571
+		// and we now have an empty string which DOES validate.
572
+		// We also validate complete empty field for email because
573
+		// its possible that this message is being "turned off" for a particular context
574
+
575
+
576
+		if (! empty($or_val) && empty($value)) {
577
+			return $validate;
578
+		}
579
+
580
+		//trim any commas from beginning and end of string ( after whitespace trimmed );
581
+		$value = trim(trim($value), ',');
582
+
583
+
584
+		//next we need to split up the string if its comma delimited.
585
+		$emails = explode(',', $value);
586
+		$empty  = false; //used to indicate that there is an empty comma.
587
+		//now let's loop through the emails and do our checks
588
+		foreach ($emails as $email) {
589
+			if (empty($email)) {
590
+				$empty = true;
591
+				continue;
592
+			}
593
+
594
+			//trim whitespace
595
+			$email = trim($email);
596
+			//either its of type "[email protected]", or its of type "fname lname <[email protected]>"
597
+			if (is_email($email)) {
598
+				continue;
599
+			} else {
600
+				$matches  = array();
601
+				$validate = preg_match('/(.*)<(.+)>/', $email, $matches) ? true : false;
602
+				if ($validate && is_email($matches[2])) {
603
+					continue;
604
+				} else {
605
+					return false;
606
+				}
607
+			}
608
+		}
609
+
610
+		$validate = $empty && ! $has_shortcodes ? false : $validate;
611
+
612
+		return $validate;
613
+
614
+	}
615
+
616
+
617
+	/**
618
+	 * Magic getter
619
+	 * Using this to provide back compat with add-ons referencing deprecated properties.
620
+	 *
621
+	 * @param string $property Property being requested
622
+	 * @throws Exception
623
+	 * @return mixed
624
+	 */
625
+	public function __get($property)
626
+	{
627
+		$expected_properties_map = array(
628
+			/**
629
+			 * @deprecated 4.9.0
630
+			 */
631
+			'_MSGR'   => '_messenger',
632
+			/**
633
+			 * @deprecated 4.9.0
634
+			 */
635
+			'_MSGTYP' => '_message_type',
636
+		);
637
+
638
+		if (isset($expected_properties_map[$property])) {
639
+			return $this->{$expected_properties_map[$property]};
640
+		}
641
+
642
+		throw new Exception(
643
+			sprintf(
644
+				__('The property %1$s being requested on %2$s does not exist', 'event_espresso'),
645
+				$property,
646
+				get_class($this)
647
+			)
648
+		);
649
+	}
650 650
 
651 651
 }
Please login to merge, or discard this patch.
Spacing   +16 added lines, -16 removed lines patch added patch discarded remove patch
@@ -1,6 +1,6 @@  discard block
 block discarded – undo
1 1
 <?php
2 2
 
3
-if (! defined('EVENT_ESPRESSO_VERSION')) {
3
+if ( ! defined('EVENT_ESPRESSO_VERSION')) {
4 4
     exit('NO direct script access allowed');
5 5
 }
6 6
 
@@ -161,9 +161,9 @@  discard block
 block discarded – undo
161 161
         //load messenger
162 162
         $messenger = ucwords(str_replace('_', ' ', $this->_m_name));
163 163
         $messenger = str_replace(' ', '_', $messenger);
164
-        $messenger = 'EE_' . $messenger . '_messenger';
164
+        $messenger = 'EE_'.$messenger.'_messenger';
165 165
 
166
-        if (! class_exists($messenger)) {
166
+        if ( ! class_exists($messenger)) {
167 167
             throw new EE_Error(
168 168
                 sprintf(
169 169
                     __('There is no messenger class for the given string (%s)', 'event_espresso'),
@@ -177,9 +177,9 @@  discard block
 block discarded – undo
177 177
         //load message type
178 178
         $message_type = ucwords(str_replace('_', ' ', $this->_mt_name));
179 179
         $message_type = str_replace(' ', '_', $message_type);
180
-        $message_type = 'EE_' . $message_type . '_message_type';
180
+        $message_type = 'EE_'.$message_type.'_message_type';
181 181
 
182
-        if (! class_exists($message_type)) {
182
+        if ( ! class_exists($message_type)) {
183 183
             throw new EE_Error(
184 184
                 sprintf(
185 185
                     __('There is no message type class for the given string (%s)', 'event_espresso'),
@@ -236,7 +236,7 @@  discard block
 block discarded – undo
236 236
         foreach ($shortcode_groups as $group) {
237 237
             $ref       = ucwords(str_replace('_', ' ', $group));
238 238
             $ref       = str_replace(' ', '_', $ref);
239
-            $classname = 'EE_' . $ref . '_Shortcodes';
239
+            $classname = 'EE_'.$ref.'_Shortcodes';
240 240
             if (class_exists($classname)) {
241 241
                 $a                       = new ReflectionClass($classname);
242 242
                 $obj                     = $a->newInstance();
@@ -330,7 +330,7 @@  discard block
 block discarded – undo
330 330
     {
331 331
         //specific validator filter
332 332
         $shortcode_excludes = apply_filters(
333
-            'FHEE__' . get_class($this) . '__get_specific_shortcode_excludes;',
333
+            'FHEE__'.get_class($this).'__get_specific_shortcode_excludes;',
334 334
             $this->_specific_shortcode_excludes,
335 335
             $this->_context
336 336
         );
@@ -362,7 +362,7 @@  discard block
 block discarded – undo
362 362
             $err_msg               = '';
363 363
             $field_label           = '';
364 364
             //if field is not present in the _validators array then we continue
365
-            if (! isset($this->_validators[$field])) {
365
+            if ( ! isset($this->_validators[$field])) {
366 366
                 unset($this->_errors[$field]);
367 367
                 continue;
368 368
             }
@@ -411,7 +411,7 @@  discard block
 block discarded – undo
411 411
                             '%3$sThe following shortcodes were found in the "%1$s" field that ARE not valid: %2$s%4$s',
412 412
                             'event_espresso'
413 413
                         ),
414
-                        '<strong>' . $field_label . '</strong>',
414
+                        '<strong>'.$field_label.'</strong>',
415 415
                         $invalid_shortcodes,
416 416
                         '<p>',
417 417
                         '</p >'
@@ -429,7 +429,7 @@  discard block
 block discarded – undo
429 429
             if (isset($this->_validators[$field]['type']) && ! empty($this->_validators[$field]['type'])) {
430 430
                 switch ($this->_validators[$field]['type']) {
431 431
                     case 'number' :
432
-                        if (! is_numeric($value)) {
432
+                        if ( ! is_numeric($value)) {
433 433
                             $err_msg .= sprintf(
434 434
                                 __(
435 435
                                     '%3$sThe %1$s field is supposed to be a number. The value given (%2$s)  is not.  Please double-check and make sure the field contains a number%4$s',
@@ -444,7 +444,7 @@  discard block
 block discarded – undo
444 444
                         break;
445 445
                     case 'email' :
446 446
                         $valid_email = $this->_validate_email($value);
447
-                        if (! $valid_email) {
447
+                        if ( ! $valid_email) {
448 448
                             $err_msg .= htmlentities(
449 449
                                 sprintf(
450 450
                                     __(
@@ -462,7 +462,7 @@  discard block
 block discarded – undo
462 462
             }
463 463
 
464 464
             //if $err_msg isn't empty let's setup the _errors array for this field.
465
-            if (! empty($err_msg)) {
465
+            if ( ! empty($err_msg)) {
466 466
                 $this->_errors[$field]['msg'] = $err_msg;
467 467
             } else {
468 468
                 unset($this->_errors[$field]);
@@ -471,7 +471,7 @@  discard block
 block discarded – undo
471 471
 
472 472
         // if we have ANY errors, then we want to make sure we return the values
473 473
         // for ALL the fields so the user doesn't have to retype them all.
474
-        if (! empty($this->_errors)) {
474
+        if ( ! empty($this->_errors)) {
475 475
             foreach ($this->_fields as $field => $value) {
476 476
                 $this->_errors[$field]['value'] = stripslashes($value);
477 477
             }
@@ -513,7 +513,7 @@  discard block
 block discarded – undo
513 513
     {
514 514
         //first we need to go through the string and get the shortcodes in the string
515 515
         preg_match_all('/(\[.+?\])/', $value, $matches);
516
-        $incoming_shortcodes = (array)$matches[0];
516
+        $incoming_shortcodes = (array) $matches[0];
517 517
 
518 518
         //get a diff of the shortcodes in the string vs the valid shortcodes
519 519
         $diff = array_diff($incoming_shortcodes, array_keys($valid_shortcodes));
@@ -536,7 +536,7 @@  discard block
 block discarded – undo
536 536
 
537 537
         //made it here? then let's assemble the error message
538 538
         $invalid_shortcodes = implode('</strong>,<strong>', $diff);
539
-        $invalid_shortcodes = '<strong>' . $invalid_shortcodes . '</strong>';
539
+        $invalid_shortcodes = '<strong>'.$invalid_shortcodes.'</strong>';
540 540
         return $invalid_shortcodes;
541 541
     }
542 542
 
@@ -573,7 +573,7 @@  discard block
 block discarded – undo
573 573
         // its possible that this message is being "turned off" for a particular context
574 574
 
575 575
 
576
-        if (! empty($or_val) && empty($value)) {
576
+        if ( ! empty($or_val) && empty($value)) {
577 577
             return $validate;
578 578
         }
579 579
 
Please login to merge, or discard this patch.
core/libraries/rest_api/controllers/config/Read.php 2 patches
Indentation   +77 added lines, -77 removed lines patch added patch discarded remove patch
@@ -9,7 +9,7 @@  discard block
 block discarded – undo
9 9
 use EEH_DTT_Helper;
10 10
 
11 11
 if (! defined('EVENT_ESPRESSO_VERSION')) {
12
-    exit('No direct script access allowed');
12
+	exit('No direct script access allowed');
13 13
 }
14 14
 
15 15
 
@@ -25,85 +25,85 @@  discard block
 block discarded – undo
25 25
 class Read
26 26
 {
27 27
 
28
-    /**
29
-     * @param WP_REST_Request $request
30
-     * @param string           $version
31
-     * @return EE_Config|WP_Error
32
-     */
33
-    public static function handleRequest(WP_REST_Request $request, $version)
34
-    {
35
-        $cap = EE_Restriction_Generator_Base::get_default_restrictions_cap();
36
-        if (EE_Capabilities::instance()->current_user_can($cap, 'read_over_api')) {
37
-            return EE_Config::instance();
38
-        } else {
39
-            return new WP_Error(
40
-                'cannot_read_config',
41
-                sprintf(
42
-                    __(
43
-                        'You do not have the necessary capabilities (%s) to read Event Espresso Configuration data',
44
-                        'event_espresso'
45
-                    ),
46
-                    $cap
47
-                ),
48
-                array('status' => 403)
49
-            );
50
-        }
51
-    }
28
+	/**
29
+	 * @param WP_REST_Request $request
30
+	 * @param string           $version
31
+	 * @return EE_Config|WP_Error
32
+	 */
33
+	public static function handleRequest(WP_REST_Request $request, $version)
34
+	{
35
+		$cap = EE_Restriction_Generator_Base::get_default_restrictions_cap();
36
+		if (EE_Capabilities::instance()->current_user_can($cap, 'read_over_api')) {
37
+			return EE_Config::instance();
38
+		} else {
39
+			return new WP_Error(
40
+				'cannot_read_config',
41
+				sprintf(
42
+					__(
43
+						'You do not have the necessary capabilities (%s) to read Event Espresso Configuration data',
44
+						'event_espresso'
45
+					),
46
+					$cap
47
+				),
48
+				array('status' => 403)
49
+			);
50
+		}
51
+	}
52 52
 
53 53
 
54 54
 
55
-    /**
56
-     * Handles the request for public site info
57
-     *
58
-     * @global                 $wp_json_basic_auth_success       boolean set by the basic auth plugin, indicates if the
59
-     *                         current user could be authenticated using basic auth data
60
-     * @global                 $wp_json_basic_auth_received_data boolean set by the basic auth plugin, indicates if
61
-     *                         basic auth data was somehow received
62
-     * @param WP_REST_Request $request
63
-     * @param string           $version
64
-     * @return array|WP_Error
65
-     */
66
-    public static function handleRequestSiteInfo(WP_REST_Request $request, $version)
67
-    {
68
-        global $wp_json_basic_auth_success, $wp_json_basic_auth_received_data;
69
-        $insecure_usage_of_basic_auth = apply_filters(
70
-            // @codingStandardsIgnoreStart
71
-            'EventEspresso__core__libraries__rest_api__controllers__config__handle_request_site_info__insecure_usage_of_basic_auth',
72
-            // @codingStandardsIgnoreEnd
73
-            $wp_json_basic_auth_success && ! is_ssl(),
74
-            $request
75
-        );
76
-        if ($insecure_usage_of_basic_auth) {
77
-            $warning = sprintf(
78
-                esc_html__(
79
-                    // @codingStandardsIgnoreStart
80
-                    'Notice: We strongly recommend installing an SSL Certificate on your website to keep your data secure. %1$sPlease see our recommendations.%2$s',
81
-                    // @codingStandardsIgnoreEnd
82
-                    'event_espresso'
83
-                ),
84
-                '<a href="https://eventespresso.com/wiki/rest-api-security-recommendations/">',
85
-                '</a>'
86
-            );
87
-        } else {
88
-            $warning = '';
89
-        }
90
-        return apply_filters(
91
-            'FHEE__EventEspresso_core_libraries_rest_api_controllers_config__handleRequestSiteInfo__return_val',
92
-            array(
93
-                'default_timezone' => array(
94
-                    'pretty' => EEH_DTT_Helper::get_timezone_string_for_display(),
95
-                    'string' => get_option('timezone_string'),
96
-                    'offset' => EEH_DTT_Helper::get_site_timezone_gmt_offset(),
97
-                ),
98
-                'default_currency' => EE_Config::instance()->currency,
99
-                'authentication'   => array(
100
-                    'received_basic_auth_data'     => (bool)$wp_json_basic_auth_received_data,
101
-                    'insecure_usage_of_basic_auth' => (bool)$insecure_usage_of_basic_auth,
102
-                    'warning'                      => $warning
103
-                )
104
-            )
105
-        );
106
-    }
55
+	/**
56
+	 * Handles the request for public site info
57
+	 *
58
+	 * @global                 $wp_json_basic_auth_success       boolean set by the basic auth plugin, indicates if the
59
+	 *                         current user could be authenticated using basic auth data
60
+	 * @global                 $wp_json_basic_auth_received_data boolean set by the basic auth plugin, indicates if
61
+	 *                         basic auth data was somehow received
62
+	 * @param WP_REST_Request $request
63
+	 * @param string           $version
64
+	 * @return array|WP_Error
65
+	 */
66
+	public static function handleRequestSiteInfo(WP_REST_Request $request, $version)
67
+	{
68
+		global $wp_json_basic_auth_success, $wp_json_basic_auth_received_data;
69
+		$insecure_usage_of_basic_auth = apply_filters(
70
+			// @codingStandardsIgnoreStart
71
+			'EventEspresso__core__libraries__rest_api__controllers__config__handle_request_site_info__insecure_usage_of_basic_auth',
72
+			// @codingStandardsIgnoreEnd
73
+			$wp_json_basic_auth_success && ! is_ssl(),
74
+			$request
75
+		);
76
+		if ($insecure_usage_of_basic_auth) {
77
+			$warning = sprintf(
78
+				esc_html__(
79
+					// @codingStandardsIgnoreStart
80
+					'Notice: We strongly recommend installing an SSL Certificate on your website to keep your data secure. %1$sPlease see our recommendations.%2$s',
81
+					// @codingStandardsIgnoreEnd
82
+					'event_espresso'
83
+				),
84
+				'<a href="https://eventespresso.com/wiki/rest-api-security-recommendations/">',
85
+				'</a>'
86
+			);
87
+		} else {
88
+			$warning = '';
89
+		}
90
+		return apply_filters(
91
+			'FHEE__EventEspresso_core_libraries_rest_api_controllers_config__handleRequestSiteInfo__return_val',
92
+			array(
93
+				'default_timezone' => array(
94
+					'pretty' => EEH_DTT_Helper::get_timezone_string_for_display(),
95
+					'string' => get_option('timezone_string'),
96
+					'offset' => EEH_DTT_Helper::get_site_timezone_gmt_offset(),
97
+				),
98
+				'default_currency' => EE_Config::instance()->currency,
99
+				'authentication'   => array(
100
+					'received_basic_auth_data'     => (bool)$wp_json_basic_auth_received_data,
101
+					'insecure_usage_of_basic_auth' => (bool)$insecure_usage_of_basic_auth,
102
+					'warning'                      => $warning
103
+				)
104
+			)
105
+		);
106
+	}
107 107
 }
108 108
 
109 109
 // End of file Read.php
Please login to merge, or discard this patch.
Spacing   +3 added lines, -3 removed lines patch added patch discarded remove patch
@@ -8,7 +8,7 @@  discard block
 block discarded – undo
8 8
 use EE_Restriction_Generator_Base;
9 9
 use EEH_DTT_Helper;
10 10
 
11
-if (! defined('EVENT_ESPRESSO_VERSION')) {
11
+if ( ! defined('EVENT_ESPRESSO_VERSION')) {
12 12
     exit('No direct script access allowed');
13 13
 }
14 14
 
@@ -97,8 +97,8 @@  discard block
 block discarded – undo
97 97
                 ),
98 98
                 'default_currency' => EE_Config::instance()->currency,
99 99
                 'authentication'   => array(
100
-                    'received_basic_auth_data'     => (bool)$wp_json_basic_auth_received_data,
101
-                    'insecure_usage_of_basic_auth' => (bool)$insecure_usage_of_basic_auth,
100
+                    'received_basic_auth_data'     => (bool) $wp_json_basic_auth_received_data,
101
+                    'insecure_usage_of_basic_auth' => (bool) $insecure_usage_of_basic_auth,
102 102
                     'warning'                      => $warning
103 103
                 )
104 104
             )
Please login to merge, or discard this patch.