Completed
Branch FET/event-question-group-refac... (96eb61)
by
unknown
35:37 queued 27:03
created

EE_Admin   F

Complexity

Total Complexity 86

Size/Duplication

Total Lines 1053
Duplicated Lines 0.85 %

Coupling/Cohesion

Components 2
Dependencies 20

Importance

Changes 0
Metric Value
dl 9
loc 1053
rs 1.3879
c 0
b 0
f 0
wmc 86
lcom 2
cbo 20

37 Methods

Rating   Name   Duplication   Size   Complexity  
A instance() 0 8 2
A reset() 0 5 1
A __construct() 0 26 1
A _define_all_constants() 9 10 2
A filter_plugin_actions() 0 29 4
A get_request() 0 4 1
A hide_admin_pages_except_maintenance_mode() 0 8 1
A init() 0 22 5
A getLoader() 0 7 2
A initModelsReady() 0 21 1
A maybeSetDatetimeWarningNotice() 0 35 4
A remove_pages_from_nav_menu() 0 12 2
B enable_hidden_ee_nav_menu_metaboxes() 0 39 7
A register_custom_nav_menu_boxes() 0 11 1
A modify_edit_post_link() 0 17 3
B ee_cpt_archive_pages() 0 80 4
A _get_extra_nav_menu_pages_items() 0 9 1
A _setup_extra_nav_menu_pages_items() 0 26 3
A route_admin_request() 0 3 1
A wp_loaded() 0 3 1
A admin_init() 0 29 4
A adminInitModelsReady() 0 6 2
A modify_dropdown_pages() 0 20 4
A enqueue_admin_scripts() 0 51 2
A display_admin_notices() 0 4 1
A dashboard_glance_items() 0 39 3
B check_for_invalid_datetime_formats() 0 65 8
A its_eSpresso() 0 4 1
A espresso_admin_footer() 0 4 1
A register_ee_admin_page() 0 18 2
A parse_post_content_on_save() 0 8 1
A reset_page_for_posts_on_change() 0 8 1
A get_persistent_admin_notices() 0 11 1
A dismiss_ee_nag_notice_callback() 0 12 1
A hookIntoWpPluginsPage() 0 7 1
A displayStateForCriticalPages() 0 17 4
A addLinksToPluginRowMeta() 0 21 2

How to fix   Duplicated Code    Complexity   

Duplicated Code

Duplicate code is one of the most pungent code smells. A rule that is often used is to re-structure code once it is duplicated in three or more places.

Common duplication problems, and corresponding solutions are:

Complex Class

 Tip:   Before tackling complexity, make sure that you eliminate any duplication first. This often can reduce the size of classes significantly.

Complex classes like EE_Admin often do a lot of different things. To break such a class down, we need to identify a cohesive component within that class. A common approach to find such a component is to look for fields/methods that share the same prefixes, or suffixes. You can also have a look at the cohesion graph to spot any un-connected, or weakly-connected components.

Once you have determined the fields that belong together, you can apply the Extract Class refactoring. If the component makes sense as a sub-class, Extract Subclass is also a candidate, and is often faster.

While breaking up the class, it is a good idea to analyze how other classes use EE_Admin, and based on these observations, apply Extract Interface, too.

1
<?php
2
3
use EventEspresso\core\domain\entities\notifications\PersistentAdminNotice;
4
use EventEspresso\core\domain\services\admin\ExitModal;
5
use EventEspresso\core\exceptions\InvalidDataTypeException;
6
use EventEspresso\core\exceptions\InvalidInterfaceException;
7
use EventEspresso\core\interfaces\InterminableInterface;
8
use EventEspresso\core\services\container\exceptions\ServiceNotFoundException;
9
use EventEspresso\core\services\loaders\LoaderFactory;
10
use EventEspresso\core\services\notifications\PersistentAdminNoticeManager;
11
use EventEspresso\core\services\loaders\LoaderInterface;
12
13
/**
14
 * EE_Admin
15
 *
16
 * @package               Event Espresso
17
 * @subpackage            /core/admin/
18
 * @author                Brent Christensen
19
 */
20
final class EE_Admin implements InterminableInterface
21
{
22
23
    /**
24
     * @var EE_Admin $_instance
25
     */
26
    private static $_instance;
27
28
    /**
29
     * @var PersistentAdminNoticeManager $persistent_admin_notice_manager
30
     */
31
    private $persistent_admin_notice_manager;
32
33
    /**
34
     * @var LoaderInterface
35
     */
36
    protected $loader;
37
38
    /**
39
     * @singleton method used to instantiate class object
40
     * @return EE_Admin
41
     * @throws EE_Error
42
     */
43
    public static function instance()
44
    {
45
        // check if class object is instantiated
46
        if (! self::$_instance instanceof EE_Admin) {
47
            self::$_instance = new self();
48
        }
49
        return self::$_instance;
50
    }
51
52
53
    /**
54
     * @return EE_Admin
55
     * @throws EE_Error
56
     */
57
    public static function reset()
58
    {
59
        self::$_instance = null;
60
        return self::instance();
61
    }
62
63
64
    /**
65
     * class constructor
66
     *
67
     * @throws EE_Error
68
     * @throws InvalidDataTypeException
69
     * @throws InvalidInterfaceException
70
     * @throws InvalidArgumentException
71
     */
72
    protected function __construct()
73
    {
74
        // define global EE_Admin constants
75
        $this->_define_all_constants();
76
        // set autoloaders for our admin page classes based on included path information
77
        EEH_Autoloader::instance()->register_autoloaders_for_each_file_in_folder(EE_ADMIN);
78
        // admin hooks
79
        add_filter('plugin_action_links', array($this, 'filter_plugin_actions'), 10, 2);
80
        // load EE_Request_Handler early
81
        add_action('AHEE__EE_System__core_loaded_and_ready', array($this, 'get_request'));
82
        add_action('AHEE__EE_System__initialize_last', array($this, 'init'));
83
        add_action('AHEE__EE_Admin_Page__route_admin_request', array($this, 'route_admin_request'), 100, 2);
84
        add_action('wp_loaded', array($this, 'wp_loaded'), 100);
85
        add_action('admin_init', array($this, 'admin_init'), 100);
86
        add_action('admin_enqueue_scripts', array($this, 'enqueue_admin_scripts'), 20);
87
        add_action('admin_notices', array($this, 'display_admin_notices'), 10);
88
        add_action('network_admin_notices', array($this, 'display_admin_notices'), 10);
89
        add_filter('pre_update_option', array($this, 'check_for_invalid_datetime_formats'), 100, 2);
90
        add_filter('admin_footer_text', array($this, 'espresso_admin_footer'));
91
        add_action('load-plugins.php', array($this, 'hookIntoWpPluginsPage'));
92
        add_action('display_post_states', array($this, 'displayStateForCriticalPages'), 10, 2);
93
        add_filter('plugin_row_meta', array($this, 'addLinksToPluginRowMeta'), 10, 2);
94
        // reset Environment config (we only do this on admin page loads);
95
        EE_Registry::instance()->CFG->environment->recheck_values();
96
        do_action('AHEE__EE_Admin__loaded');
97
    }
98
99
100
    /**
101
     * _define_all_constants
102
     * define constants that are set globally for all admin pages
103
     *
104
     * @return void
105
     */
106 View Code Duplication
    private function _define_all_constants()
107
    {
108
        if (! defined('EE_ADMIN_URL')) {
109
            define('EE_ADMIN_URL', EE_PLUGIN_DIR_URL . 'core/admin/');
110
            define('EE_ADMIN_PAGES_URL', EE_PLUGIN_DIR_URL . 'admin_pages/');
111
            define('EE_ADMIN_TEMPLATE', EE_ADMIN . 'templates' . DS);
112
            define('WP_ADMIN_PATH', ABSPATH . 'wp-admin/');
113
            define('WP_AJAX_URL', admin_url('admin-ajax.php'));
114
        }
115
    }
116
117
118
    /**
119
     * filter_plugin_actions - adds links to the Plugins page listing
120
     *
121
     * @param    array  $links
122
     * @param    string $plugin
123
     * @return    array
124
     */
125
    public function filter_plugin_actions($links, $plugin)
126
    {
127
        // set $main_file in stone
128
        static $main_file;
129
        // if $main_file is not set yet
130
        if (! $main_file) {
131
            $main_file = plugin_basename(EVENT_ESPRESSO_MAIN_FILE);
132
        }
133
        if ($plugin === $main_file) {
134
            // compare current plugin to this one
135
            if (EE_Maintenance_Mode::instance()->level() === EE_Maintenance_Mode::level_2_complete_maintenance) {
136
                $maintenance_link = '<a href="admin.php?page=espresso_maintenance_settings"'
137
                                    . ' title="Event Espresso is in maintenance mode.  Click this link to learn why.">'
138
                                    . esc_html__('Maintenance Mode Active', 'event_espresso')
139
                                    . '</a>';
140
                array_unshift($links, $maintenance_link);
141
            } else {
142
                $org_settings_link = '<a href="admin.php?page=espresso_general_settings">'
143
                                     . esc_html__('Settings', 'event_espresso')
144
                                     . '</a>';
145
                $events_link = '<a href="admin.php?page=espresso_events">'
146
                               . esc_html__('Events', 'event_espresso')
147
                               . '</a>';
148
                // add before other links
149
                array_unshift($links, $org_settings_link, $events_link);
150
            }
151
        }
152
        return $links;
153
    }
154
155
156
    /**
157
     * _get_request
158
     *
159
     * @return void
160
     * @throws EE_Error
161
     * @throws InvalidArgumentException
162
     * @throws InvalidDataTypeException
163
     * @throws InvalidInterfaceException
164
     * @throws ReflectionException
165
     */
166
    public function get_request()
167
    {
168
        EE_Registry::instance()->load_core('Request_Handler');
169
    }
170
171
172
    /**
173
     * hide_admin_pages_except_maintenance_mode
174
     *
175
     * @param array $admin_page_folder_names
176
     * @return array
177
     */
178
    public function hide_admin_pages_except_maintenance_mode($admin_page_folder_names = array())
179
    {
180
        return array(
181
            'maintenance' => EE_ADMIN_PAGES . 'maintenance' . DS,
182
            'about'       => EE_ADMIN_PAGES . 'about' . DS,
183
            'support'     => EE_ADMIN_PAGES . 'support' . DS,
184
        );
185
    }
186
187
188
    /**
189
     * init- should fire after shortcode, module,  addon, other plugin (default priority), and even
190
     * EE_Front_Controller's init phases have run
191
     *
192
     * @return void
193
     * @throws EE_Error
194
     * @throws InvalidArgumentException
195
     * @throws InvalidDataTypeException
196
     * @throws InvalidInterfaceException
197
     * @throws ReflectionException
198
     * @throws ServiceNotFoundException
199
     */
200
    public function init()
201
    {
202
        // only enable most of the EE_Admin IF we're not in full maintenance mode
203
        if (EE_Maintenance_Mode::instance()->models_can_query()) {
204
            $this->initModelsReady();
205
        }
206
        // run the admin page factory but ONLY if we are doing an ee admin ajax request
207
        if (! defined('DOING_AJAX') || EE_ADMIN_AJAX) {
208
            try {
209
                // this loads the controller for the admin pages which will setup routing etc
210
                EE_Registry::instance()->load_core('Admin_Page_Loader');
211
            } catch (EE_Error $e) {
212
                $e->get_error();
213
            }
214
        }
215
        add_filter('content_save_pre', array($this, 'its_eSpresso'), 10, 1);
216
        // make sure our CPTs and custom taxonomy metaboxes get shown for first time users
217
        add_action('admin_head', array($this, 'enable_hidden_ee_nav_menu_metaboxes'), 10);
218
        add_action('admin_head', array($this, 'register_custom_nav_menu_boxes'), 10);
219
        // exclude EE critical pages from all nav menus and wp_list_pages
220
        add_filter('nav_menu_meta_box_object', array($this, 'remove_pages_from_nav_menu'), 10);
221
    }
222
223
224
    /**
225
     * Gets the loader (and if it wasn't previously set, sets it)
226
     * @return LoaderInterface
227
     * @throws InvalidArgumentException
228
     * @throws InvalidDataTypeException
229
     * @throws InvalidInterfaceException
230
     */
231
    protected function getLoader()
232
    {
233
        if (! $this->loader instanceof LoaderInterface) {
234
            $this->loader = LoaderFactory::getLoader();
235
        }
236
        return $this->loader;
237
    }
238
239
240
    /**
241
     * Method that's fired on admin requests (including admin ajax) but only when the models are usable
242
     * (ie, the site isn't in maintenance mode)
243
     * @since 4.9.63.p
244
     * @return void
245
     */
246
    protected function initModelsReady()
247
    {
248
        // ok so we want to enable the entire admin
249
        $this->persistent_admin_notice_manager = $this->getLoader()->getShared(
250
            'EventEspresso\core\services\notifications\PersistentAdminNoticeManager'
251
        );
252
        $this->persistent_admin_notice_manager->setReturnUrl(
253
            EE_Admin_Page::add_query_args_and_nonce(
254
                array(
255
                    'page'   => EE_Registry::instance()->REQ->get('page', ''),
256
                    'action' => EE_Registry::instance()->REQ->get('action', ''),
257
                ),
258
                EE_ADMIN_URL
259
            )
260
        );
261
        $this->maybeSetDatetimeWarningNotice();
262
        // at a glance dashboard widget
263
        add_filter('dashboard_glance_items', array($this, 'dashboard_glance_items'), 10);
264
        // filter for get_edit_post_link used on comments for custom post types
265
        add_filter('get_edit_post_link', array($this, 'modify_edit_post_link'), 10, 2);
266
    }
267
268
269
    /**
270
     *    get_persistent_admin_notices
271
     *
272
     * @access    public
273
     * @return void
274
     * @throws EE_Error
275
     * @throws InvalidArgumentException
276
     * @throws InvalidDataTypeException
277
     * @throws InvalidInterfaceException
278
     */
279
    public function maybeSetDatetimeWarningNotice()
280
    {
281
        // add dismissable notice for datetime changes.  Only valid if site does not have a timezone_string set.
282
        // @todo This needs to stay in core for a bit to catch anyone upgrading from a version without this to a version
283
        // with this.  But after enough time (indeterminate at this point) we can just remove this notice.
284
        // this was added with https://events.codebasehq.com/projects/event-espresso/tickets/10626
285
        if (apply_filters('FHEE__EE_Admin__maybeSetDatetimeWarningNotice', true)
286
            && ! get_option('timezone_string')
287
            && EEM_Event::instance()->count() > 0
288
        ) {
289
            new PersistentAdminNotice(
290
                'datetime_fix_notice',
291
                sprintf(
292
                    esc_html__(
293
                        '%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.',
294
                        'event_espresso'
295
                    ),
296
                    '<strong>',
297
                    '</strong>',
298
                    '<a href="https://eventespresso.com/2017/08/important-upcoming-changes-dates-times">',
299
                    '</a>',
300
                    '<a href="' . EE_Admin_Page::add_query_args_and_nonce(
301
                        array(
302
                            'page'   => 'espresso_maintenance_settings',
303
                            'action' => 'datetime_tools',
304
                        ),
305
                        admin_url('admin.php')
306
                    ) . '">'
307
                ),
308
                false,
309
                'manage_options',
310
                'datetime_fix_persistent_notice'
311
            );
312
        }
313
    }
314
315
316
    /**
317
     * this simply hooks into the nav menu setup of pages metabox and makes sure that we remove EE critical pages from
318
     * the list of options. the wp function "wp_nav_menu_item_post_type_meta_box" found in
319
     * wp-admin/includes/nav-menu.php looks for the "_default_query" property on the post_type object and it uses that
320
     * to override any queries found in the existing query for the given post type.  Note that _default_query is not a
321
     * normal property on the post_type object.  It's found ONLY in this particular context.
322
     *
323
     * @param WP_Post $post_type WP post type object
324
     * @return WP_Post
325
     * @throws InvalidArgumentException
326
     * @throws InvalidDataTypeException
327
     * @throws InvalidInterfaceException
328
     */
329
    public function remove_pages_from_nav_menu($post_type)
330
    {
331
        // if this isn't the "pages" post type let's get out
332
        if ($post_type->name !== 'page') {
333
            return $post_type;
334
        }
335
        $critical_pages = EE_Registry::instance()->CFG->core->get_critical_pages_array();
336
        $post_type->_default_query = array(
337
            'post__not_in' => $critical_pages,
338
        );
339
        return $post_type;
340
    }
341
342
343
    /**
344
     * WP by default only shows three metaboxes in "nav-menus.php" for first times users.  We want to make sure our
345
     * metaboxes get shown as well
346
     *
347
     * @return void
348
     */
349
    public function enable_hidden_ee_nav_menu_metaboxes()
350
    {
351
        global $wp_meta_boxes, $pagenow;
352
        if (! is_array($wp_meta_boxes) || $pagenow !== 'nav-menus.php') {
353
            return;
354
        }
355
        $user = wp_get_current_user();
356
        // has this been done yet?
357
        if (get_user_option('ee_nav_menu_initialized', $user->ID)) {
358
            return;
359
        }
360
361
        $hidden_meta_boxes = get_user_option('metaboxhidden_nav-menus', $user->ID);
362
        $initial_meta_boxes = apply_filters(
363
            'FHEE__EE_Admin__enable_hidden_ee_nav_menu_boxes__initial_meta_boxes',
364
            array(
365
                'nav-menu-theme-locations',
366
                'add-page',
367
                'add-custom-links',
368
                'add-category',
369
                'add-espresso_events',
370
                'add-espresso_venues',
371
                'add-espresso_event_categories',
372
                'add-espresso_venue_categories',
373
                'add-post-type-post',
374
                'add-post-type-page',
375
            )
376
        );
377
378
        if (is_array($hidden_meta_boxes)) {
379
            foreach ($hidden_meta_boxes as $key => $meta_box_id) {
380
                if (in_array($meta_box_id, $initial_meta_boxes, true)) {
381
                    unset($hidden_meta_boxes[ $key ]);
382
                }
383
            }
384
        }
385
        update_user_option($user->ID, 'metaboxhidden_nav-menus', $hidden_meta_boxes, true);
386
        update_user_option($user->ID, 'ee_nav_menu_initialized', 1, true);
387
    }
388
389
390
    /**
391
     * This method simply registers custom nav menu boxes for "nav_menus.php route"
392
     * Currently EE is using this to make sure there are menu options for our CPT archive page routes.
393
     *
394
     * @todo   modify this so its more dynamic and automatic for all ee CPTs and setups and can also be hooked into by
395
     *         addons etc.
396
     * @return void
397
     */
398
    public function register_custom_nav_menu_boxes()
399
    {
400
        add_meta_box(
401
            'add-extra-nav-menu-pages',
402
            esc_html__('Event Espresso Pages', 'event_espresso'),
403
            array($this, 'ee_cpt_archive_pages'),
404
            'nav-menus',
405
            'side',
406
            'core'
407
        );
408
    }
409
410
411
    /**
412
     * Use this to edit the post link for our cpts so that the edit link points to the correct page.
413
     *
414
     * @since   4.3.0
415
     * @param string $link the original link generated by wp
416
     * @param int    $id   post id
417
     * @return string  the (maybe) modified link
418
     */
419
    public function modify_edit_post_link($link, $id)
420
    {
421
        if (! $post = get_post($id)) {
422
            return $link;
423
        }
424
        if ($post->post_type === 'espresso_attendees') {
425
            $query_args = array(
426
                'action' => 'edit_attendee',
427
                'post'   => $id,
428
            );
429
            return EEH_URL::add_query_args_and_nonce(
430
                $query_args,
431
                admin_url('admin.php?page=espresso_registrations')
432
            );
433
        }
434
        return $link;
435
    }
436
437
438
    public function ee_cpt_archive_pages()
439
    {
440
        global $nav_menu_selected_id;
441
        $db_fields = false;
442
        $walker = new Walker_Nav_Menu_Checklist($db_fields);
443
        $current_tab = 'event-archives';
444
        $removed_args = array(
445
            'action',
446
            'customlink-tab',
447
            'edit-menu-item',
448
            'menu-item',
449
            'page-tab',
450
            '_wpnonce',
451
        );
452
        ?>
453
        <div id="posttype-extra-nav-menu-pages" class="posttypediv">
454
            <ul id="posttype-extra-nav-menu-pages-tabs" class="posttype-tabs add-menu-item-tabs">
455
                <li <?php echo('event-archives' === $current_tab ? ' class="tabs"' : ''); ?>>
456
                    <a class="nav-tab-link" data-type="tabs-panel-posttype-extra-nav-menu-pages-event-archives"
457
                       href="<?php
458
                        if ($nav_menu_selected_id) {
459
                            echo esc_url(
460
                                add_query_arg(
461
                                    'extra-nav-menu-pages-tab',
462
                                    'event-archives',
463
                                    remove_query_arg($removed_args)
464
                                )
465
                            );
466
                        }
467
                        ?>#tabs-panel-posttype-extra-nav-menu-pages-event-archives">
468
                        <?php _e('Event Archive Pages', 'event_espresso'); ?>
469
                    </a>
470
                </li>
471
            </ul><!-- .posttype-tabs -->
472
473
            <div id="tabs-panel-posttype-extra-nav-menu-pages-event-archives" class="tabs-panel <?php
474
            echo('event-archives' === $current_tab ? 'tabs-panel-active' : 'tabs-panel-inactive');
475
            ?>">
476
                <ul id="extra-nav-menu-pageschecklist-event-archives" class="categorychecklist form-no-clear">
477
                    <?php
478
                    $pages = $this->_get_extra_nav_menu_pages_items();
479
                    $args['walker'] = $walker;
0 ignored issues
show
Coding Style Comprehensibility introduced by
$args was never initialized. Although not strictly required by PHP, it is generally a good practice to add $args = array(); before regardless.

Adding an explicit array definition is generally preferable to implicit array definition as it guarantees a stable state of the code.

Let’s take a look at an example:

foreach ($collection as $item) {
    $myArray['foo'] = $item->getFoo();

    if ($item->hasBar()) {
        $myArray['bar'] = $item->getBar();
    }

    // do something with $myArray
}

As you can see in this example, the array $myArray is initialized the first time when the foreach loop is entered. You can also see that the value of the bar key is only written conditionally; thus, its value might result from a previous iteration.

This might or might not be intended. To make your intention clear, your code more readible and to avoid accidental bugs, we recommend to add an explicit initialization $myArray = array() either outside or inside the foreach loop.

Loading history...
480
                    echo walk_nav_menu_tree(
481
                        array_map(
482
                            array($this, '_setup_extra_nav_menu_pages_items'),
483
                            $pages
484
                        ),
485
                        0,
486
                        (object) $args
487
                    );
488
                    ?>
489
                </ul>
490
            </div><!-- /.tabs-panel -->
491
492
            <p class="button-controls">
493
                <span class="list-controls">
494
                    <a href="<?php
495
                             echo esc_url(
496
                                 add_query_arg(
497
                                     array(
498
                                         'extra-nav-menu-pages-tab' => 'event-archives',
499
                                         'selectall'                => 1,
500
                                     ),
501
                                     remove_query_arg($removed_args)
502
                                 )
503
                             );
504
                        ?>#posttype-extra-nav-menu-pages>" class="select-all"><?php _e('Select All', 'event_espresso'); ?></a>
505
                </span>
506
                <span class="add-to-menu">
507
                    <input type="submit"<?php wp_nav_menu_disabled_check($nav_menu_selected_id); ?>
508
                           class="button-secondary submit-add-to-menu right"
509
                           value="<?php esc_attr_e('Add to Menu', 'event_espresso'); ?>" name="add-post-type-menu-item"
510
                           id="<?php echo esc_attr('submit-posttype-extra-nav-menu-pages'); ?>"/>
511
                    <span class="spinner"></span>
512
                </span>
513
            </p>
514
515
        </div><!-- /.posttypediv -->
516
        <?php
517
    }
518
519
520
    /**
521
     * Returns an array of event archive nav items.
522
     *
523
     * @todo  for now this method is just in place so when it gets abstracted further we can substitute in whatever
524
     *        method we use for getting the extra nav menu items
525
     * @return array
526
     */
527
    private function _get_extra_nav_menu_pages_items()
528
    {
529
        $menuitems[] = array(
0 ignored issues
show
Coding Style Comprehensibility introduced by
$menuitems was never initialized. Although not strictly required by PHP, it is generally a good practice to add $menuitems = array(); before regardless.

Adding an explicit array definition is generally preferable to implicit array definition as it guarantees a stable state of the code.

Let’s take a look at an example:

foreach ($collection as $item) {
    $myArray['foo'] = $item->getFoo();

    if ($item->hasBar()) {
        $myArray['bar'] = $item->getBar();
    }

    // do something with $myArray
}

As you can see in this example, the array $myArray is initialized the first time when the foreach loop is entered. You can also see that the value of the bar key is only written conditionally; thus, its value might result from a previous iteration.

This might or might not be intended. To make your intention clear, your code more readible and to avoid accidental bugs, we recommend to add an explicit initialization $myArray = array() either outside or inside the foreach loop.

Loading history...
530
            'title'       => esc_html__('Event List', 'event_espresso'),
531
            'url'         => get_post_type_archive_link('espresso_events'),
532
            'description' => esc_html__('Archive page for all events.', 'event_espresso'),
533
        );
534
        return apply_filters('FHEE__EE_Admin__get_extra_nav_menu_pages_items', $menuitems);
535
    }
536
537
538
    /**
539
     * Setup nav menu walker item for usage in the event archive nav menu metabox.  It receives a menu_item array with
540
     * the properties and converts it to the menu item object.
541
     *
542
     * @see wp_setup_nav_menu_item() in wp-includes/nav-menu.php
543
     * @param $menu_item_values
544
     * @return stdClass
545
     */
546
    private function _setup_extra_nav_menu_pages_items($menu_item_values)
547
    {
548
        $menu_item = new stdClass();
549
        $keys = array(
550
            'ID'               => 0,
551
            'db_id'            => 0,
552
            'menu_item_parent' => 0,
553
            'object_id'        => -1,
554
            'post_parent'      => 0,
555
            'type'             => 'custom',
556
            'object'           => '',
557
            'type_label'       => esc_html__('Extra Nav Menu Item', 'event_espresso'),
558
            'title'            => '',
559
            'url'              => '',
560
            'target'           => '',
561
            'attr_title'       => '',
562
            'description'      => '',
563
            'classes'          => array(),
564
            'xfn'              => '',
565
        );
566
567
        foreach ($keys as $key => $value) {
568
            $menu_item->{$key} = isset($menu_item_values[ $key ]) ? $menu_item_values[ $key ] : $value;
569
        }
570
        return $menu_item;
571
    }
572
573
574
    /**
575
     * This is the action hook for the AHEE__EE_Admin_Page__route_admin_request hook that fires off right before an
576
     * EE_Admin_Page route is called.
577
     *
578
     * @return void
579
     */
580
    public function route_admin_request()
581
    {
582
    }
583
584
585
    /**
586
     * wp_loaded should fire on the WordPress wp_loaded hook.  This fires on a VERY late priority.
587
     *
588
     * @return void
589
     */
590
    public function wp_loaded()
591
    {
592
    }
593
594
595
    /**
596
     * admin_init
597
     *
598
     * @return void
599
     * @throws EE_Error
600
     * @throws InvalidArgumentException
601
     * @throws InvalidDataTypeException
602
     * @throws InvalidInterfaceException
603
     * @throws ReflectionException
604
     */
605
    public function admin_init()
606
    {
607
        /**
608
         * our cpt models must be instantiated on WordPress post processing routes (wp-admin/post.php),
609
         * so any hooking into core WP routes is taken care of.  So in this next few lines of code:
610
         * - check if doing post processing.
611
         * - check if doing post processing of one of EE CPTs
612
         * - instantiate the corresponding EE CPT model for the post_type being processed.
613
         */
614
        if (isset($_POST['action'], $_POST['post_type']) && $_POST['action'] === 'editpost') {
615
            /** @var EventEspresso\core\domain\entities\custom_post_types\CustomPostTypeDefinitions $custom_post_types */
616
            $custom_post_types = $this->getLoader()->getShared(
617
                'EventEspresso\core\domain\entities\custom_post_types\CustomPostTypeDefinitions'
618
            );
619
            $custom_post_types->getCustomPostTypeModels($_POST['post_type']);
620
        }
621
622
623
        /**
624
         * This code excludes EE critical pages anywhere `wp_dropdown_pages` is used to create a dropdown for selecting
625
         * critical pages.  The only place critical pages need included in a generated dropdown is on the "Critical
626
         * Pages" tab in the EE General Settings Admin page.
627
         * This is for user-proofing.
628
         */
629
        add_filter('wp_dropdown_pages', array($this, 'modify_dropdown_pages'));
630
        if (EE_Maintenance_Mode::instance()->models_can_query()) {
631
            $this->adminInitModelsReady();
632
        }
633
    }
634
635
636
    /**
637
     * Runs on admin_init but only if models are usable (ie, we're not in maintenanc emode)
638
     */
639
    protected function adminInitModelsReady()
640
    {
641
        if (function_exists('wp_add_privacy_policy_content')) {
642
            $this->getLoader()->getShared('EventEspresso\core\services\privacy\policy\PrivacyPolicyManager');
643
        }
644
    }
645
646
647
    /**
648
     * Callback for wp_dropdown_pages hook to remove ee critical pages from the dropdown selection.
649
     *
650
     * @param string $output Current output.
651
     * @return string
652
     * @throws InvalidArgumentException
653
     * @throws InvalidDataTypeException
654
     * @throws InvalidInterfaceException
655
     */
656
    public function modify_dropdown_pages($output)
657
    {
658
        // get critical pages
659
        $critical_pages = EE_Registry::instance()->CFG->core->get_critical_pages_array();
660
661
        // split current output by line break for easier parsing.
662
        $split_output = explode("\n", $output);
663
664
        // loop through to remove any critical pages from the array.
665
        foreach ($critical_pages as $page_id) {
666
            $needle = 'value="' . $page_id . '"';
667
            foreach ($split_output as $key => $haystack) {
668
                if (strpos($haystack, $needle) !== false) {
669
                    unset($split_output[ $key ]);
670
                }
671
            }
672
        }
673
        // replace output with the new contents
674
        return implode("\n", $split_output);
675
    }
676
677
678
    /**
679
     * enqueue all admin scripts that need loaded for admin pages
680
     *
681
     * @return void
682
     */
683
    public function enqueue_admin_scripts()
684
    {
685
        // this javascript is loaded on every admin page to catch any injections ee needs to add to wp run js.
686
        // Note: the intention of this script is to only do TARGETED injections.  I.E, only injecting on certain script
687
        // calls.
688
        wp_enqueue_script(
689
            'ee-inject-wp',
690
            EE_ADMIN_URL . 'assets/ee-cpt-wp-injects.js',
691
            array('jquery'),
692
            EVENT_ESPRESSO_VERSION,
693
            true
694
        );
695
        // register cookie script for future dependencies
696
        wp_register_script(
697
            'jquery-cookie',
698
            EE_THIRD_PARTY_URL . 'joyride/jquery.cookie.js',
699
            array('jquery'),
700
            '2.1',
701
            true
702
        );
703
        // joyride is turned OFF by default, but prior to the admin_enqueue_scripts hook, can be turned back on again
704
        // via: add_filter('FHEE_load_joyride', '__return_true' );
705
        if (apply_filters('FHEE_load_joyride', false)) {
706
            // joyride style
707
            wp_register_style('joyride-css', EE_THIRD_PARTY_URL . 'joyride/joyride-2.1.css', array(), '2.1');
708
            wp_register_style(
709
                'ee-joyride-css',
710
                EE_GLOBAL_ASSETS_URL . 'css/ee-joyride-styles.css',
711
                array('joyride-css'),
712
                EVENT_ESPRESSO_VERSION
713
            );
714
            wp_register_script(
715
                'joyride-modernizr',
716
                EE_THIRD_PARTY_URL . 'joyride/modernizr.mq.js',
717
                array(),
718
                '2.1',
719
                true
720
            );
721
            // joyride JS
722
            wp_register_script(
723
                'jquery-joyride',
724
                EE_THIRD_PARTY_URL . 'joyride/jquery.joyride-2.1.js',
725
                array('jquery-cookie', 'joyride-modernizr'),
726
                '2.1',
727
                true
728
            );
729
            // wanna go for a joyride?
730
            wp_enqueue_style('ee-joyride-css');
731
            wp_enqueue_script('jquery-joyride');
732
        }
733
    }
734
735
736
    /**
737
     * display_admin_notices
738
     *
739
     * @return void
740
     */
741
    public function display_admin_notices()
742
    {
743
        echo EE_Error::get_notices();
744
    }
745
746
747
    /**
748
     * @param array $elements
749
     * @return array
750
     * @throws EE_Error
751
     * @throws InvalidArgumentException
752
     * @throws InvalidDataTypeException
753
     * @throws InvalidInterfaceException
754
     */
755
    public function dashboard_glance_items($elements)
756
    {
757
        $elements = is_array($elements) ? $elements : array($elements);
758
        $events = EEM_Event::instance()->count();
759
        $items['events']['url'] = EE_Admin_Page::add_query_args_and_nonce(
0 ignored issues
show
Coding Style Comprehensibility introduced by
$items was never initialized. Although not strictly required by PHP, it is generally a good practice to add $items = array(); before regardless.

Adding an explicit array definition is generally preferable to implicit array definition as it guarantees a stable state of the code.

Let’s take a look at an example:

foreach ($collection as $item) {
    $myArray['foo'] = $item->getFoo();

    if ($item->hasBar()) {
        $myArray['bar'] = $item->getBar();
    }

    // do something with $myArray
}

As you can see in this example, the array $myArray is initialized the first time when the foreach loop is entered. You can also see that the value of the bar key is only written conditionally; thus, its value might result from a previous iteration.

This might or might not be intended. To make your intention clear, your code more readible and to avoid accidental bugs, we recommend to add an explicit initialization $myArray = array() either outside or inside the foreach loop.

Loading history...
760
            array('page' => 'espresso_events'),
761
            admin_url('admin.php')
762
        );
763
        $items['events']['text'] = sprintf(_n('%s Event', '%s Events', $events, 'event_espresso'), number_format_i18n($events));
764
        $items['events']['title'] = esc_html__('Click to view all Events', 'event_espresso');
765
        $registrations = EEM_Registration::instance()->count(
766
            array(
767
                array(
768
                    'STS_ID' => array('!=', EEM_Registration::status_id_incomplete),
769
                ),
770
            )
771
        );
772
        $items['registrations']['url'] = EE_Admin_Page::add_query_args_and_nonce(
773
            array('page' => 'espresso_registrations'),
774
            admin_url('admin.php')
775
        );
776
        $items['registrations']['text'] = sprintf(
777
            _n('%s Registration', '%s Registrations', $registrations, 'event_espresso'),
778
            number_format_i18n($registrations)
779
        );
780
        $items['registrations']['title'] = esc_html__('Click to view all registrations', 'event_espresso');
781
782
        $items = (array) apply_filters('FHEE__EE_Admin__dashboard_glance_items__items', $items);
783
784
        foreach ($items as $type => $item_properties) {
785
            $elements[] = sprintf(
786
                '<a class="ee-dashboard-link-' . $type . '" href="%s" title="%s">%s</a>',
787
                $item_properties['url'],
788
                $item_properties['title'],
789
                $item_properties['text']
790
            );
791
        }
792
        return $elements;
793
    }
794
795
796
    /**
797
     * check_for_invalid_datetime_formats
798
     * if an admin changes their date or time format settings on the WP General Settings admin page, verify that
799
     * their selected format can be parsed by PHP
800
     *
801
     * @param    $value
802
     * @param    $option
803
     * @throws EE_Error
804
     * @return    string
805
     */
806
    public function check_for_invalid_datetime_formats($value, $option)
807
    {
808
        // check for date_format or time_format
809
        switch ($option) {
810
            case 'date_format':
811
                $date_time_format = $value . ' ' . get_option('time_format');
812
                break;
813
            case 'time_format':
814
                $date_time_format = get_option('date_format') . ' ' . $value;
815
                break;
816
            default:
817
                $date_time_format = false;
818
        }
819
        // do we have a date_time format to check ?
820
        if ($date_time_format) {
0 ignored issues
show
Bug Best Practice introduced by
The expression $date_time_format of type string|false is loosely compared to true; this is ambiguous if the string can be empty. You might want to explicitly use !== false instead.

In PHP, under loose comparison (like ==, or !=, or switch conditions), values of different types might be equal.

For string values, the empty string '' is a special case, in particular the following results might be unexpected:

''   == false // true
''   == null  // true
'ab' == false // false
'ab' == null  // false

// It is often better to use strict comparison
'' === false // false
'' === null  // false
Loading history...
821
            $error_msg = EEH_DTT_Helper::validate_format_string($date_time_format);
822
823
            if (is_array($error_msg)) {
824
                $msg = '<p>'
825
                       . sprintf(
826
                           esc_html__(
827
                               'The following date time "%s" ( %s ) is difficult to be properly parsed by PHP for the following reasons:',
828
                               'event_espresso'
829
                           ),
830
                           date($date_time_format),
831
                           $date_time_format
832
                       )
833
                       . '</p><p><ul>';
834
835
836
                foreach ($error_msg as $error) {
837
                    $msg .= '<li>' . $error . '</li>';
838
                }
839
840
                $msg .= '</ul></p><p>'
841
                        . sprintf(
842
                            esc_html__(
843
                                '%sPlease note that your date and time formats have been reset to "F j, Y" and "g:i a" respectively.%s',
844
                                'event_espresso'
845
                            ),
846
                            '<span style="color:#D54E21;">',
847
                            '</span>'
848
                        )
849
                        . '</p>';
850
851
                // trigger WP settings error
852
                add_settings_error(
853
                    'date_format',
854
                    'date_format',
855
                    $msg
856
                );
857
858
                // set format to something valid
859
                switch ($option) {
860
                    case 'date_format':
861
                        $value = 'F j, Y';
862
                        break;
863
                    case 'time_format':
864
                        $value = 'g:i a';
865
                        break;
866
                }
867
            }
868
        }
869
        return $value;
870
    }
871
872
873
    /**
874
     * its_eSpresso - converts the less commonly used spelling of "Expresso" to "Espresso"
875
     *
876
     * @param $content
877
     * @return    string
878
     */
879
    public function its_eSpresso($content)
880
    {
881
        return str_replace('[EXPRESSO_', '[ESPRESSO_', $content);
882
    }
883
884
885
    /**
886
     * espresso_admin_footer
887
     *
888
     * @return    string
889
     */
890
    public function espresso_admin_footer()
891
    {
892
        return \EEH_Template::powered_by_event_espresso('aln-cntr', '', array('utm_content' => 'admin_footer'));
893
    }
894
895
896
    /**
897
     * static method for registering ee admin page.
898
     * This method is deprecated in favor of the new location in EE_Register_Admin_Page::register.
899
     *
900
     * @since      4.3.0
901
     * @deprecated 4.3.0    Use EE_Register_Admin_Page::register() instead
902
     * @see        EE_Register_Admin_Page::register()
903
     * @param       $page_basename
904
     * @param       $page_path
905
     * @param array $config
906
     * @return void
907
     * @throws EE_Error
908
     */
909
    public static function register_ee_admin_page($page_basename, $page_path, $config = array())
910
    {
911
        EE_Error::doing_it_wrong(
912
            __METHOD__,
913
            sprintf(
914
                esc_html__(
915
                    'Usage is deprecated.  Use EE_Register_Admin_Page::register() for registering the %s admin page.',
916
                    'event_espresso'
917
                ),
918
                $page_basename
919
            ),
920
            '4.3'
921
        );
922
        if (class_exists('EE_Register_Admin_Page')) {
923
            $config['page_path'] = $page_path;
924
        }
925
        EE_Register_Admin_Page::register($page_basename, $config);
926
    }
927
928
929
    /**
930
     * @deprecated 4.8.41
931
     * @param  int      $post_ID
932
     * @param  \WP_Post $post
933
     * @return void
934
     */
935
    public static function parse_post_content_on_save($post_ID, $post)
936
    {
937
        EE_Error::doing_it_wrong(
938
            __METHOD__,
939
            esc_html__('Usage is deprecated', 'event_espresso'),
940
            '4.8.41'
941
        );
942
    }
943
944
945
    /**
946
     * @deprecated 4.8.41
947
     * @param  $option
948
     * @param  $old_value
949
     * @param  $value
950
     * @return void
951
     */
952
    public function reset_page_for_posts_on_change($option, $old_value, $value)
953
    {
954
        EE_Error::doing_it_wrong(
955
            __METHOD__,
956
            esc_html__('Usage is deprecated', 'event_espresso'),
957
            '4.8.41'
958
        );
959
    }
960
961
962
    /**
963
     * @deprecated 4.9.27
964
     * @return void
965
     */
966
    public function get_persistent_admin_notices()
967
    {
968
        EE_Error::doing_it_wrong(
969
            __METHOD__,
970
            sprintf(
971
                __('Usage is deprecated. Use "%1$s" instead.', 'event_espresso'),
972
                '\EventEspresso\core\services\notifications\PersistentAdminNoticeManager'
973
            ),
974
            '4.9.27'
975
        );
976
    }
977
978
979
    /**
980
     * @deprecated 4.9.27
981
     * @throws InvalidInterfaceException
982
     * @throws InvalidDataTypeException
983
     * @throws DomainException
984
     */
985
    public function dismiss_ee_nag_notice_callback()
986
    {
987
        EE_Error::doing_it_wrong(
988
            __METHOD__,
989
            sprintf(
990
                __('Usage is deprecated. Use "%1$s" instead.', 'event_espresso'),
991
                '\EventEspresso\core\services\notifications\PersistentAdminNoticeManager'
992
            ),
993
            '4.9.27'
994
        );
995
        $this->persistent_admin_notice_manager->dismissNotice();
996
    }
997
998
999
    /**
1000
     * Callback on load-plugins.php hook for setting up anything hooking into the wp plugins page.
1001
     *
1002
     * @throws InvalidArgumentException
1003
     * @throws InvalidDataTypeException
1004
     * @throws InvalidInterfaceException
1005
     */
1006
    public function hookIntoWpPluginsPage()
1007
    {
1008
        $this->getLoader()->getShared('EventEspresso\core\domain\services\admin\ExitModal');
1009
        $this->getLoader()
1010
                     ->getShared('EventEspresso\core\domain\services\admin\PluginUpsells')
1011
                     ->decafUpsells();
1012
    }
1013
1014
1015
    /**
1016
     * Hooks into the "post states" filter in a wp post type list table.
1017
     *
1018
     * @param array   $post_states
1019
     * @param WP_Post $post
1020
     * @return array
1021
     * @throws InvalidArgumentException
1022
     * @throws InvalidDataTypeException
1023
     * @throws InvalidInterfaceException
1024
     */
1025
    public function displayStateForCriticalPages($post_states, $post)
1026
    {
1027
        $post_states = (array) $post_states;
1028
        if (! $post instanceof WP_Post || $post->post_type !== 'page') {
1029
            return $post_states;
1030
        }
1031
        /** @var EE_Core_Config $config */
1032
        $config = $this->getLoader()->getShared('EE_Config')->core;
1033
        if (in_array($post->ID, $config->get_critical_pages_array(), true)) {
1034
            $post_states[] = sprintf(
1035
                /* Translators: Using company name - Event Espresso Critical Page */
1036
                esc_html__('%s Critical Page', 'event_espresso'),
1037
                'Event Espresso'
1038
            );
1039
        }
1040
        return $post_states;
1041
    }
1042
1043
1044
    /**
1045
     * Show documentation links on the plugins page
1046
     *
1047
     * @param mixed $meta Plugin Row Meta
1048
     * @param mixed $file Plugin Base file
1049
     * @return array
1050
     */
1051
    public function addLinksToPluginRowMeta($meta, $file)
1052
    {
1053
        if (EE_PLUGIN_BASENAME === $file) {
1054
            $row_meta = array(
1055
                'docs' => '<a href="https://eventespresso.com/support/documentation/versioned-docs/?doc_ver=ee4"'
1056
                          . ' aria-label="'
1057
                          . esc_attr__('View Event Espresso documentation', 'event_espresso')
1058
                          . '">'
1059
                          . esc_html__('Docs', 'event_espresso')
1060
                          . '</a>',
1061
                'api'  => '<a href="https://github.com/eventespresso/event-espresso-core/tree/master/docs/C--REST-API"'
1062
                          . ' aria-label="'
1063
                          . esc_attr__('View Event Espresso API docs', 'event_espresso')
1064
                          . '">'
1065
                          . esc_html__('API docs', 'event_espresso')
1066
                          . '</a>',
1067
            );
1068
            return array_merge($meta, $row_meta);
1069
        }
1070
        return (array) $meta;
1071
    }
1072
}
1073