Completed
Branch BUG-10738-inconsistency-in-ses... (cda363)
by
unknown
13:38 queued 12s
created

EE_Capabilities   D

Complexity

Total Complexity 66

Size/Duplication

Total Lines 1001
Duplicated Lines 3.6 %

Coupling/Cohesion

Components 2
Dependencies 9

Importance

Changes 0
Metric Value
dl 36
loc 1001
rs 4.9982
c 0
b 0
f 0
wmc 66
lcom 2
cbo 9

20 Methods

Rating   Name   Duplication   Size   Complexity  
A instance() 0 8 2
A __construct() 0 3 1
B init_caps() 0 30 4
A _set_meta_caps() 0 12 2
B _get_default_meta_caps_array() 0 123 2
B map_meta_caps() 0 17 5
B _init_caps_map() 0 272 1
A setupCapabilitiesMap() 0 12 4
A updateCapabilitiesMap() 0 4 2
C addCaps() 12 33 7
C removeCaps() 12 23 7
A flushWpUser() 0 9 3
B add_cap_to_role() 6 29 6
A remove_cap_from_role() 6 15 4
A capHasBeenAddedToRole() 0 10 4
A current_user_can() 0 15 2
A user_can() 0 16 2
A current_user_can_for_blog() 0 23 2
A get_ee_capabilities() 0 12 4
B init_role_caps() 0 25 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_Capabilities 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_Capabilities, and based on these observations, apply Extract Interface, too.

1
<?php
2
3
defined('EVENT_ESPRESSO_VERSION') || exit('No direct script access allowed');
4
5
6
7
/**
8
 * This class contains all the code related to Event Espresso capabilities.
9
 * Assigned to the EE_Registry::instance()->CAP property.
10
 *
11
 * @link       https://github.com/eventespresso/event-espresso-core/tree/master/docs/K--Capability-System
12
 *
13
 * @since      4.5.0
14
 * @package    Event Espresso
15
 * @subpackage core, capabilities
16
 * @author     Darren Ethier
17
 */
18
final class EE_Capabilities extends EE_Base
19
{
20
21
    /**
22
     * the name of the wp option used to store caps previously initialized
23
     */
24
    const option_name = 'ee_caps_initialized';
25
26
    /**
27
     * instance of EE_Capabilities object
28
     *
29
     * @var EE_Capabilities
30
     */
31
    private static $_instance;
32
33
34
    /**
35
     * This is a map of caps that correspond to a default WP_Role.
36
     * Array is indexed by Role and values are ee capabilities.
37
     *
38
     * @since 4.5.0
39
     *
40
     * @var array
41
     */
42
    private $capabilities_map = array();
43
44
    /**
45
     * This used to hold an array of EE_Meta_Capability_Map objects
46
     * that define the granular capabilities mapped to for a user depending on context.
47
     *
48
     * @var EE_Meta_Capability_Map[]
49
     */
50
    private $_meta_caps = array();
51
52
    /**
53
     * The internal $capabilities_map needs to be initialized before it can be used.
54
     * This flag tracks whether that has happened or not.
55
     * But for this to work, we need three states to indicate:
56
     *      initialization has not occurred at all
57
     *      initialization has started but is not complete
58
     *      initialization is complete
59
     * The reason this is needed is because the addCaps() method
60
     * normally requires the $capabilities_map to be initialized,
61
     * but is also used during the initialization process.
62
     * So:
63
     *      If initialized === null, init_caps() will be called before any other methods will run.
64
     *      If initialized === false, then init_caps() is in the process of running it's logic.
65
     *      If initialized === true, then init_caps() has completed the initialization process.
66
     *
67
     * @var boolean|null $initialized
68
     */
69
    private $initialized;
70
71
    /**
72
     * @var boolean $reset
73
     */
74
    private $reset = false;
75
76
77
78
    /**
79
     * singleton method used to instantiate class object
80
     *
81
     * @since 4.5.0
82
     *
83
     * @return EE_Capabilities
84
     */
85
    public static function instance()
86
    {
87
        //check if instantiated, and if not do so.
88
        if (! self::$_instance instanceof EE_Capabilities) {
89
            self::$_instance = new self();
90
        }
91
        return self::$_instance;
92
    }
93
94
95
96
    /**
97
     * private constructor
98
     *
99
     * @since 4.5.0
100
     */
101
    private function __construct()
102
    {
103
    }
104
105
106
107
    /**
108
     * This delays the initialization of the capabilities class until EE_System core is loaded and ready.
109
     *
110
     * @param bool $reset allows for resetting the default capabilities saved on roles.  Note that this doesn't
111
     *                    actually REMOVE any capabilities from existing roles, it just resaves defaults roles and
112
     *                    ensures that they are up to date.
113
     *
114
     * @since 4.5.0
115
     * @return bool
116
     * @throws EE_Error
117
     */
118
    public function init_caps($reset = false)
119
    {
120
        if(! EE_Maintenance_Mode::instance()->models_can_query()){
121
            return false;
122
        }
123
        $this->reset = filter_var($reset, FILTER_VALIDATE_BOOLEAN);
124
        // if reset, then completely delete the cache option and clear the $capabilities_map property.
125
        if ($this->reset) {
126
            $this->initialized = null;
127
            $this->capabilities_map = array();
128
            delete_option(self::option_name);
129
        }
130
        if ($this->initialized === null) {
131
            $this->initialized = false;
132
            do_action(
133
                'AHEE__EE_Capabilities__init_caps__before_initialization',
134
                $this->reset
135
            );
136
            $this->addCaps($this->_init_caps_map());
137
            $this->_set_meta_caps();
138
            do_action(
139
                'AHEE__EE_Capabilities__init_caps__after_initialization',
140
                $this->capabilities_map
141
            );
142
            $this->initialized = true;
143
        }
144
        // reset $this->reset so that it's not stuck on true if init_caps() gets called again
145
        $this->reset = false;
146
        return true;
147
    }
148
149
150
151
152
    /**
153
     * This sets the meta caps property.
154
     *
155
     * @since 4.5.0
156
     * @return void
157
     * @throws EE_Error
158
     */
159
    private function _set_meta_caps()
160
    {
161
        // get default meta caps and filter the returned array
162
        $this->_meta_caps = apply_filters(
163
            'FHEE__EE_Capabilities___set_meta_caps__meta_caps',
164
            $this->_get_default_meta_caps_array()
165
        );
166
        //add filter for map_meta_caps but only if models can query.
167
        if (! has_filter('map_meta_cap', array($this, 'map_meta_caps'))) {
168
            add_filter('map_meta_cap', array($this, 'map_meta_caps'), 10, 4);
169
        }
170
    }
171
172
173
174
    /**
175
     * This builds and returns the default meta_caps array only once.
176
     *
177
     * @since  4.8.28.rc.012
178
     * @return array
179
     * @throws EE_Error
180
     */
181
    private function _get_default_meta_caps_array()
182
    {
183
        static $default_meta_caps = array();
184
        // make sure we're only ever initializing the default _meta_caps array once if it's empty.
185
        if (empty($default_meta_caps)) {
186
            $default_meta_caps = array(
187
                //edits
188
                new EE_Meta_Capability_Map_Edit(
189
                    'ee_edit_event',
190
                    array('Event', 'ee_edit_published_events', 'ee_edit_others_events', 'ee_edit_private_events')
191
                ),
192
                new EE_Meta_Capability_Map_Edit(
193
                    'ee_edit_venue',
194
                    array('Venue', 'ee_edit_published_venues', 'ee_edit_others_venues', 'ee_edit_private_venues')
195
                ),
196
                new EE_Meta_Capability_Map_Edit(
197
                    'ee_edit_registration',
198
                    array('Registration', '', 'ee_edit_others_registrations', '')
199
                ),
200
                new EE_Meta_Capability_Map_Edit(
201
                    'ee_edit_checkin',
202
                    array('Registration', '', 'ee_edit_others_checkins', '')
203
                ),
204
                new EE_Meta_Capability_Map_Messages_Cap(
205
                    'ee_edit_message',
206
                    array('Message_Template_Group', '', 'ee_edit_others_messages', 'ee_edit_global_messages')
207
                ),
208
                new EE_Meta_Capability_Map_Edit(
209
                    'ee_edit_default_ticket',
210
                    array('Ticket', '', 'ee_edit_others_default_tickets', '')
211
                ),
212
                new EE_Meta_Capability_Map_Registration_Form_Cap(
213
                    'ee_edit_question',
214
                    array('Question', '', '', 'ee_edit_system_questions')
215
                ),
216
                new EE_Meta_Capability_Map_Registration_Form_Cap(
217
                    'ee_edit_question_group',
218
                    array('Question_Group', '', '', 'ee_edit_system_question_groups')
219
                ),
220
                new EE_Meta_Capability_Map_Edit(
221
                    'ee_edit_payment_method',
222
                    array('Payment_Method', '', 'ee_edit_others_payment_methods', '')
223
                ),
224
                //reads
225
                new EE_Meta_Capability_Map_Read(
226
                    'ee_read_event',
227
                    array('Event', '', 'ee_read_others_events', 'ee_read_private_events')
228
                ),
229
                new EE_Meta_Capability_Map_Read(
230
                    'ee_read_venue',
231
                    array('Venue', '', 'ee_read_others_venues', 'ee_read_private_venues')
232
                ),
233
                new EE_Meta_Capability_Map_Read(
234
                    'ee_read_registration',
235
                    array('Registration', '', 'ee_read_others_registrations', '')
236
                ),
237
                new EE_Meta_Capability_Map_Read(
238
                    'ee_read_checkin',
239
                    array('Registration', '', 'ee_read_others_checkins', '')
240
                ),
241
                new EE_Meta_Capability_Map_Messages_Cap(
242
                    'ee_read_message',
243
                    array('Message_Template_Group', '', 'ee_read_others_messages', 'ee_read_global_messages')
244
                ),
245
                new EE_Meta_Capability_Map_Read(
246
                    'ee_read_default_ticket',
247
                    array('Ticket', '', 'ee_read_others_default_tickets', '')
248
                ),
249
                new EE_Meta_Capability_Map_Read(
250
                    'ee_read_payment_method',
251
                    array('Payment_Method', '', 'ee_read_others_payment_methods', '')
252
                ),
253
                //deletes
254
                new EE_Meta_Capability_Map_Delete(
255
                    'ee_delete_event',
256
                    array(
257
                        'Event',
258
                        'ee_delete_published_events',
259
                        'ee_delete_others_events',
260
                        'ee_delete_private_events',
261
                    )
262
                ),
263
                new EE_Meta_Capability_Map_Delete(
264
                    'ee_delete_venue',
265
                    array(
266
                        'Venue',
267
                        'ee_delete_published_venues',
268
                        'ee_delete_others_venues',
269
                        'ee_delete_private_venues',
270
                    )
271
                ),
272
                new EE_Meta_Capability_Map_Delete(
273
                    'ee_delete_registration',
274
                    array('Registration', '', 'ee_delete_others_registrations', '')
275
                ),
276
                new EE_Meta_Capability_Map_Delete(
277
                    'ee_delete_checkin',
278
                    array('Registration', '', 'ee_delete_others_checkins', '')
279
                ),
280
                new EE_Meta_Capability_Map_Messages_Cap(
281
                    'ee_delete_message',
282
                    array('Message_Template_Group', '', 'ee_delete_others_messages', 'ee_delete_global_messages')
283
                ),
284
                new EE_Meta_Capability_Map_Delete(
285
                    'ee_delete_default_ticket',
286
                    array('Ticket', '', 'ee_delete_others_default_tickets', '')
287
                ),
288
                new EE_Meta_Capability_Map_Registration_Form_Cap(
289
                    'ee_delete_question',
290
                    array('Question', '', '', 'delete_system_questions')
291
                ),
292
                new EE_Meta_Capability_Map_Registration_Form_Cap(
293
                    'ee_delete_question_group',
294
                    array('Question_Group', '', '', 'delete_system_question_groups')
295
                ),
296
                new EE_Meta_Capability_Map_Delete(
297
                    'ee_delete_payment_method',
298
                    array('Payment_Method', '', 'ee_delete_others_payment_methods', '')
299
                ),
300
            );
301
        }
302
        return $default_meta_caps;
303
    }
304
305
306
307
    /**
308
     * This is the callback for the wp map_meta_caps() function which allows for ensuring certain caps that act as a
309
     * "meta" for other caps ( i.e. ee_edit_event is a meta for ee_edit_others_events ) work as expected.
310
     *
311
     * The actual logic is carried out by implementer classes in their definition of _map_meta_caps.
312
     *
313
     * @since 4.5.0
314
     * @see   wp-includes/capabilities.php
315
     *
316
     * @param array  $caps    actual users capabilities
317
     * @param string $cap     initial capability name that is being checked (the "map" key)
318
     * @param int    $user_id The user id
319
     * @param array  $args    Adds context to the cap. Typically the object ID.
320
     * @return array actual users capabilities
321
     * @throws EE_Error
322
     */
323
    public function map_meta_caps($caps, $cap, $user_id, $args)
324
    {
325
        if (did_action('AHEE__EE_System__load_espresso_addons__complete')) {
326
            //loop through our _meta_caps array
327
            foreach ($this->_meta_caps as $meta_map) {
328
                if (! $meta_map instanceof EE_Meta_Capability_Map) {
329
                    continue;
330
                }
331
                // don't load models if there is no object ID in the args
332
                if (! empty($args[0])) {
333
                    $meta_map->ensure_is_model();
334
                }
335
                $caps = $meta_map->map_meta_caps($caps, $cap, $user_id, $args);
336
            }
337
        }
338
        return $caps;
339
    }
340
341
342
343
    /**
344
     * This sets up and returns the initial capabilities map for Event Espresso
345
     * Note this array is filtered.
346
     * It is assumed that all available EE capabilities are assigned to the administrator role.
347
     *
348
     * @since 4.5.0
349
     *
350
     * @return array
351
     */
352
    private function _init_caps_map()
353
    {
354
        return apply_filters(
355
            'FHEE__EE_Capabilities__init_caps_map__caps',
356
            array(
357
                'administrator'           => array(
358
                    //basic access
359
                    'ee_read_ee',
360
                    //gateways
361
                    /**
362
                     * note that with payment method capabilities, although we've implemented
363
                     * capability mapping which will be used for accessing payment methods owned by
364
                     * other users.  This is not fully implemented yet in the payment method ui.
365
                     * Currently only the "plural" caps are in active use.
366
                     * (Specific payment method caps are in use as well).
367
                     **/
368
                    'ee_manage_gateways',
369
                    'ee_read_payment_methods',
370
                    'ee_read_others_payment_methods',
371
                    'ee_edit_payment_methods',
372
                    'ee_edit_others_payment_methods',
373
                    'ee_delete_payment_methods',
374
                    //events
375
                    'ee_publish_events',
376
                    'ee_read_private_events',
377
                    'ee_read_others_events',
378
                    'ee_read_events',
379
                    'ee_edit_events',
380
                    'ee_edit_published_events',
381
                    'ee_edit_others_events',
382
                    'ee_edit_private_events',
383
                    'ee_delete_published_events',
384
                    'ee_delete_private_events',
385
                    'ee_delete_events',
386
                    'ee_delete_others_events',
387
                    //event categories
388
                    'ee_manage_event_categories',
389
                    'ee_edit_event_category',
390
                    'ee_delete_event_category',
391
                    'ee_assign_event_category',
392
                    //venues
393
                    'ee_publish_venues',
394
                    'ee_read_venues',
395
                    'ee_read_others_venues',
396
                    'ee_read_private_venues',
397
                    'ee_edit_venues',
398
                    'ee_edit_others_venues',
399
                    'ee_edit_published_venues',
400
                    'ee_edit_private_venues',
401
                    'ee_delete_venues',
402
                    'ee_delete_others_venues',
403
                    'ee_delete_private_venues',
404
                    'ee_delete_published_venues',
405
                    //venue categories
406
                    'ee_manage_venue_categories',
407
                    'ee_edit_venue_category',
408
                    'ee_delete_venue_category',
409
                    'ee_assign_venue_category',
410
                    //contacts
411
                    'ee_read_contacts',
412
                    'ee_edit_contacts',
413
                    'ee_delete_contacts',
414
                    //registrations
415
                    'ee_read_registrations',
416
                    'ee_read_others_registrations',
417
                    'ee_edit_registrations',
418
                    'ee_edit_others_registrations',
419
                    'ee_delete_registrations',
420
                    //checkins
421
                    'ee_read_others_checkins',
422
                    'ee_read_checkins',
423
                    'ee_edit_checkins',
424
                    'ee_edit_others_checkins',
425
                    'ee_delete_checkins',
426
                    'ee_delete_others_checkins',
427
                    //transactions && payments
428
                    'ee_read_transaction',
429
                    'ee_read_transactions',
430
                    'ee_edit_payments',
431
                    'ee_delete_payments',
432
                    //messages
433
                    'ee_read_messages',
434
                    'ee_read_others_messages',
435
                    'ee_read_global_messages',
436
                    'ee_edit_global_messages',
437
                    'ee_edit_messages',
438
                    'ee_edit_others_messages',
439
                    'ee_delete_messages',
440
                    'ee_delete_others_messages',
441
                    'ee_delete_global_messages',
442
                    'ee_send_message',
443
                    //tickets
444
                    'ee_read_default_tickets',
445
                    'ee_read_others_default_tickets',
446
                    'ee_edit_default_tickets',
447
                    'ee_edit_others_default_tickets',
448
                    'ee_delete_default_tickets',
449
                    'ee_delete_others_default_tickets',
450
                    //prices
451
                    'ee_edit_default_price',
452
                    'ee_edit_default_prices',
453
                    'ee_delete_default_price',
454
                    'ee_delete_default_prices',
455
                    'ee_edit_default_price_type',
456
                    'ee_edit_default_price_types',
457
                    'ee_delete_default_price_type',
458
                    'ee_delete_default_price_types',
459
                    'ee_read_default_prices',
460
                    'ee_read_default_price_types',
461
                    //registration form
462
                    'ee_edit_questions',
463
                    'ee_edit_system_questions',
464
                    'ee_read_questions',
465
                    'ee_delete_questions',
466
                    'ee_edit_question_groups',
467
                    'ee_read_question_groups',
468
                    'ee_edit_system_question_groups',
469
                    'ee_delete_question_groups',
470
                    //event_type taxonomy
471
                    'ee_assign_event_type',
472
                    'ee_manage_event_types',
473
                    'ee_edit_event_type',
474
                    'ee_delete_event_type',
475
                ),
476
                'ee_events_administrator' => array(
477
                    //core wp caps
478
                    'read',
479
                    'read_private_pages',
480
                    'read_private_posts',
481
                    'edit_users',
482
                    'edit_posts',
483
                    'edit_pages',
484
                    'edit_published_posts',
485
                    'edit_published_pages',
486
                    'edit_private_pages',
487
                    'edit_private_posts',
488
                    'edit_others_posts',
489
                    'edit_others_pages',
490
                    'publish_posts',
491
                    'publish_pages',
492
                    'delete_posts',
493
                    'delete_pages',
494
                    'delete_private_pages',
495
                    'delete_private_posts',
496
                    'delete_published_pages',
497
                    'delete_published_posts',
498
                    'delete_others_posts',
499
                    'delete_others_pages',
500
                    'manage_categories',
501
                    'manage_links',
502
                    'moderate_comments',
503
                    'unfiltered_html',
504
                    'upload_files',
505
                    'export',
506
                    'import',
507
                    'list_users',
508
                    'level_1', //required if user with this role shows up in author dropdowns
509
                    //basic ee access
510
                    'ee_read_ee',
511
                    //events
512
                    'ee_publish_events',
513
                    'ee_read_private_events',
514
                    'ee_read_others_events',
515
                    'ee_read_event',
516
                    'ee_read_events',
517
                    'ee_edit_event',
518
                    'ee_edit_events',
519
                    'ee_edit_published_events',
520
                    'ee_edit_others_events',
521
                    'ee_edit_private_events',
522
                    'ee_delete_published_events',
523
                    'ee_delete_private_events',
524
                    'ee_delete_event',
525
                    'ee_delete_events',
526
                    'ee_delete_others_events',
527
                    //event categories
528
                    'ee_manage_event_categories',
529
                    'ee_edit_event_category',
530
                    'ee_delete_event_category',
531
                    'ee_assign_event_category',
532
                    //venues
533
                    'ee_publish_venues',
534
                    'ee_read_venue',
535
                    'ee_read_venues',
536
                    'ee_read_others_venues',
537
                    'ee_read_private_venues',
538
                    'ee_edit_venue',
539
                    'ee_edit_venues',
540
                    'ee_edit_others_venues',
541
                    'ee_edit_published_venues',
542
                    'ee_edit_private_venues',
543
                    'ee_delete_venue',
544
                    'ee_delete_venues',
545
                    'ee_delete_others_venues',
546
                    'ee_delete_private_venues',
547
                    'ee_delete_published_venues',
548
                    //venue categories
549
                    'ee_manage_venue_categories',
550
                    'ee_edit_venue_category',
551
                    'ee_delete_venue_category',
552
                    'ee_assign_venue_category',
553
                    //contacts
554
                    'ee_read_contacts',
555
                    'ee_edit_contacts',
556
                    'ee_delete_contacts',
557
                    //registrations
558
                    'ee_read_registrations',
559
                    'ee_read_others_registrations',
560
                    'ee_edit_registration',
561
                    'ee_edit_registrations',
562
                    'ee_edit_others_registrations',
563
                    'ee_delete_registration',
564
                    'ee_delete_registrations',
565
                    //checkins
566
                    'ee_read_others_checkins',
567
                    'ee_read_checkins',
568
                    'ee_edit_checkins',
569
                    'ee_edit_others_checkins',
570
                    'ee_delete_checkins',
571
                    'ee_delete_others_checkins',
572
                    //transactions && payments
573
                    'ee_read_transaction',
574
                    'ee_read_transactions',
575
                    'ee_edit_payments',
576
                    'ee_delete_payments',
577
                    //messages
578
                    'ee_read_messages',
579
                    'ee_read_others_messages',
580
                    'ee_read_global_messages',
581
                    'ee_edit_global_messages',
582
                    'ee_edit_messages',
583
                    'ee_edit_others_messages',
584
                    'ee_delete_messages',
585
                    'ee_delete_others_messages',
586
                    'ee_delete_global_messages',
587
                    'ee_send_message',
588
                    //tickets
589
                    'ee_read_default_tickets',
590
                    'ee_read_others_default_tickets',
591
                    'ee_edit_default_tickets',
592
                    'ee_edit_others_default_tickets',
593
                    'ee_delete_default_tickets',
594
                    'ee_delete_others_default_tickets',
595
                    //prices
596
                    'ee_edit_default_price',
597
                    'ee_edit_default_prices',
598
                    'ee_delete_default_price',
599
                    'ee_delete_default_prices',
600
                    'ee_edit_default_price_type',
601
                    'ee_edit_default_price_types',
602
                    'ee_delete_default_price_type',
603
                    'ee_delete_default_price_types',
604
                    'ee_read_default_prices',
605
                    'ee_read_default_price_types',
606
                    //registration form
607
                    'ee_edit_questions',
608
                    'ee_edit_system_questions',
609
                    'ee_read_questions',
610
                    'ee_delete_questions',
611
                    'ee_edit_question_groups',
612
                    'ee_read_question_groups',
613
                    'ee_edit_system_question_groups',
614
                    'ee_delete_question_groups',
615
                    //event_type taxonomy
616
                    'ee_assign_event_type',
617
                    'ee_manage_event_types',
618
                    'ee_edit_event_type',
619
                    'ee_delete_event_type',
620
                )
621
            )
622
        );
623
    }
624
625
626
627
    /**
628
     * @return bool
629
     * @throws EE_Error
630
     */
631
    private function setupCapabilitiesMap()
632
    {
633
        // if the initialization process hasn't even started, then we need to call init_caps()
634
        if($this->initialized === null) {
635
            return $this->init_caps();
636
        }
637
        // unless resetting, get caps from db if we haven't already
638
        $this->capabilities_map = $this->reset || ! empty($this->capabilities_map)
639
            ? $this->capabilities_map
640
            : get_option(self::option_name, array());
641
        return true;
642
    }
643
644
645
646
    /**
647
     * @param bool $update
648
     * @return bool
649
     */
650
    private function updateCapabilitiesMap($update = true)
651
    {
652
        return $update ? update_option(self::option_name, $this->capabilities_map) : false;
653
    }
654
655
656
657
    /**
658
     * Adds capabilities to roles.
659
     *
660
     * @since 4.9.42
661
     * @param array $capabilities_to_add array of capabilities to add, indexed by roles.
662
     *                                   Note that this should ONLY be called on activation hook
663
     *                                   otherwise the caps will be added on every request.
664
     * @return bool
665
     * @throws \EE_Error
666
     */
667
    public function addCaps(array $capabilities_to_add)
668
    {
669
        // don't do anything if the capabilities map can not be initialized
670
        if (! $this->setupCapabilitiesMap()) {
671
            return false;
672
        }
673
        // and filter the array so others can get in on the fun during resets
674
        $capabilities_to_add = apply_filters(
675
            'FHEE__EE_Capabilities__addCaps__capabilities_to_add',
676
            $capabilities_to_add,
677
            $this->reset,
678
            $this->capabilities_map
679
        );
680
        $update_capabilities_map = false;
681
        // if not reset, see what caps are new for each role. if they're new, add them.
682 View Code Duplication
        foreach ($capabilities_to_add as $role => $caps_for_role) {
683
            if (is_array($caps_for_role)) {
684
                foreach ($caps_for_role as $cap) {
685
                    if (
686
                        ! $this->capHasBeenAddedToRole($role, $cap)
687
                        && $this->add_cap_to_role($role, $cap, true, false)
688
                    ) {
689
                        $update_capabilities_map = true;
690
                    }
691
                }
692
            }
693
        }
694
        // now let's just save the cap that has been set but only if there's been a change.
695
        $updated = $this->updateCapabilitiesMap($update_capabilities_map);
696
        $this->flushWpUser($updated);
697
        do_action('AHEE__EE_Capabilities__addCaps__complete', $this->capabilities_map, $updated);
698
        return $updated;
699
    }
700
701
702
703
    /**
704
     * Loops through the capabilities map and removes the role caps specified by the incoming array
705
     *
706
     * @param array $caps_map map of capabilities to be removed (indexed by roles)
707
     * @return bool
708
     * @throws \EE_Error
709
     */
710
    public function removeCaps($caps_map)
711
    {
712
        // don't do anything if the capabilities map can not be initialized
713
        if (! $this->setupCapabilitiesMap()) {
714
            return false;
715
        }
716
        $update_capabilities_map = false;
717 View Code Duplication
        foreach ($caps_map as $role => $caps_for_role) {
718
            if (is_array($caps_for_role)) {
719
                foreach ($caps_for_role as $cap) {
720
                    if ($this->capHasBeenAddedToRole($role, $cap)
721
                        && $this->remove_cap_from_role($role, $cap, false)
722
                    ) {
723
                        $update_capabilities_map = true;
724
                    }
725
                }
726
            }
727
        }
728
        // maybe resave the caps
729
        $updated = $this->updateCapabilitiesMap($update_capabilities_map);
730
        $this->flushWpUser($updated);
731
        return $updated;
732
    }
733
734
735
    /**
736
     * This ensures that the WP User object cached on the $current_user global in WP has the latest capabilities from
737
     * the roles on that user.
738
     *
739
     * @param bool $flush  Default is to flush the WP_User object.  If false, then this method effectively does nothing.
740
     */
741
    private function flushWpUser($flush = true)
742
    {
743
        if ($flush) {
744
            $user = wp_get_current_user();
745
            if ($user instanceof WP_User) {
746
                $user->get_role_caps();
747
            }
748
        }
749
    }
750
751
752
753
    /**
754
     * This method sets a capability on a role.  Note this should only be done on activation, or if you have something
755
     * specific to prevent the cap from being added on every page load (adding caps are persistent to the db). Note.
756
     * this is a wrapper for $wp_role->add_cap()
757
     *
758
     * @see   wp-includes/capabilities.php
759
     * @since 4.5.0
760
     * @param string|WP_Role $role  A WordPress role the capability is being added to
761
     * @param string         $cap   The capability being added to the role
762
     * @param bool           $grant Whether to grant access to this cap on this role.
763
     * @param bool           $update_capabilities_map
764
     * @return bool
765
     * @throws \EE_Error
766
     */
767
    public function add_cap_to_role($role, $cap, $grant = true, $update_capabilities_map = true)
768
    {
769
        // capture incoming value for $role because we may need it to create a new WP_Role
770
        $orig_role = $role;
771
        $role = $role instanceof WP_Role ? $role : get_role($role);
772
        //if the role isn't available then we create it.
773
        if (! $role instanceof WP_Role) {
774
            // if a plugin wants to create a specific role name then they should create the role before
775
            // EE_Capabilities does.  Otherwise this function will create the role name from the slug:
776
            // - removes any `ee_` namespacing from the start of the slug.
777
            // - replaces `_` with ` ` (empty space).
778
            // - sentence case on the resulting string.
779
            $role_label = ucwords(str_replace(array('ee_', '_'), array('', ' '), $orig_role));
780
            $role = add_role($orig_role, $role_label);
781
        }
782
        if ($role instanceof WP_Role) {
783
            // don't do anything if the capabilities map can not be initialized
784
            if (! $this->setupCapabilitiesMap()) {
785
                return false;
786
            }
787 View Code Duplication
            if (! $this->capHasBeenAddedToRole($role->name, $cap)) {
788
                $role->add_cap($cap, $grant);
789
                $this->capabilities_map[ $role->name ][] = $cap;
790
                $this->updateCapabilitiesMap($update_capabilities_map);
791
                return true;
792
            }
793
        }
794
        return false;
795
    }
796
797
798
799
    /**
800
     * Functions similarly to add_cap_to_role except removes cap from given role.
801
     * Wrapper for $wp_role->remove_cap()
802
     *
803
     * @see   wp-includes/capabilities.php
804
     * @since 4.5.0
805
     * @param string|WP_Role $role A WordPress role the capability is being removed from.
806
     * @param string         $cap  The capability being removed
807
     * @param bool           $update_capabilities_map
808
     * @return bool
809
     * @throws \EE_Error
810
     */
811
    public function remove_cap_from_role($role, $cap, $update_capabilities_map = true)
812
    {
813
        // don't do anything if the capabilities map can not be initialized
814
        if (! $this->setupCapabilitiesMap()) {
815
            return false;
816
        }
817
        $role = $role instanceof WP_Role ? $role :get_role($role);
818 View Code Duplication
        if ($index = $this->capHasBeenAddedToRole($role->name, $cap, true)) {
819
            $role->remove_cap($cap);
820
            unset($this->capabilities_map[ $role->name ][ $index ]);
821
            $this->updateCapabilitiesMap($update_capabilities_map);
822
            return true;
823
        }
824
        return false;
825
    }
826
827
828
829
    /**
830
     * @param string $role_name
831
     * @param string $cap
832
     * @param bool   $get_index
833
     * @return bool|mixed
834
     */
835
    private function capHasBeenAddedToRole($role_name='', $cap='', $get_index = false)
836
    {
837
        if (
838
            isset($this->capabilities_map[$role_name])
839
            && ($index = array_search($cap, $this->capabilities_map[$role_name], true)) !== false
840
        ) {
841
            return $get_index ? $index : true;
842
        }
843
        return false;
844
    }
845
846
847
848
    /**
849
     * Wrapper for the native WP current_user_can() method.
850
     * This is provided as a handy method for a couple things:
851
     * 1. Using the context string it allows for targeted filtering by addons for a specific check (without having to
852
     * write those filters wherever current_user_can is called).
853
     * 2. Explicit passing of $id from a given context ( useful in the cases of map_meta_cap filters )
854
     *
855
     * @since 4.5.0
856
     *
857
     * @param string $cap     The cap being checked.
858
     * @param string $context The context where the current_user_can is being called from.
859
     * @param int    $id      Optional. Id for item where current_user_can is being called from (used in map_meta_cap()
860
     *                        filters.
861
     *
862
     * @return bool  Whether user can or not.
863
     */
864
    public function current_user_can($cap, $context, $id = 0)
865
    {
866
        //apply filters (both a global on just the cap, and context specific.  Global overrides context specific)
867
        $filtered_cap = apply_filters('FHEE__EE_Capabilities__current_user_can__cap__' . $context, $cap, $id);
868
        $filtered_cap = apply_filters(
869
            'FHEE__EE_Capabilities__current_user_can__cap',
870
            $filtered_cap,
871
            $context,
872
            $cap,
873
            $id
874
        );
875
        return ! empty($id)
876
            ? current_user_can($filtered_cap, $id)
877
            : current_user_can($filtered_cap);
878
    }
879
880
881
882
    /**
883
     * This is a wrapper for the WP user_can() function and follows the same style as the other wrappers in this class.
884
     *
885
     * @param int|WP_User $user    Either the user_id or a WP_User object
886
     * @param string      $cap     The capability string being checked
887
     * @param string      $context The context where the user_can is being called from (used in filters).
888
     * @param int         $id      Optional. Id for item where user_can is being called from ( used in map_meta_cap()
889
     *                             filters)
890
     *
891
     * @return bool Whether user can or not.
892
     */
893
    public function user_can($user, $cap, $context, $id = 0)
894
    {
895
        //apply filters (both a global on just the cap, and context specific.  Global overrides context specific)
896
        $filtered_cap = apply_filters('FHEE__EE_Capabilities__user_can__cap__' . $context, $cap, $user, $id);
897
        $filtered_cap = apply_filters(
898
            'FHEE__EE_Capabilities__user_can__cap',
899
            $filtered_cap,
900
            $context,
901
            $cap,
902
            $user,
903
            $id
904
        );
905
        return ! empty($id)
906
            ? user_can($user, $filtered_cap, $id)
907
            : user_can($user, $filtered_cap);
908
    }
909
910
911
912
    /**
913
     * Wrapper for the native WP current_user_can_for_blog() method.
914
     * This is provided as a handy method for a couple things:
915
     * 1. Using the context string it allows for targeted filtering by addons for a specific check (without having to
916
     * write those filters wherever current_user_can is called).
917
     * 2. Explicit passing of $id from a given context ( useful in the cases of map_meta_cap filters )
918
     *
919
     * @since 4.5.0
920
     *
921
     * @param int    $blog_id The blog id that is being checked for.
922
     * @param string $cap     The cap being checked.
923
     * @param string $context The context where the current_user_can is being called from.
924
     * @param int    $id      Optional. Id for item where current_user_can is being called from (used in map_meta_cap()
925
     *                        filters.
926
     *
927
     * @return bool  Whether user can or not.
928
     */
929
    public function current_user_can_for_blog($blog_id, $cap, $context, $id = 0)
930
    {
931
        $user_can = ! empty($id)
932
            ? current_user_can_for_blog($blog_id, $cap, $id)
933
            : current_user_can($blog_id, $cap);
934
        //apply filters (both a global on just the cap, and context specific.  Global overrides context specific)
935
        $user_can = apply_filters(
936
            'FHEE__EE_Capabilities__current_user_can_for_blog__user_can__' . $context,
937
            $user_can,
938
            $blog_id,
939
            $cap,
940
            $id
941
        );
942
        $user_can = apply_filters(
943
            'FHEE__EE_Capabilities__current_user_can_for_blog__user_can',
944
            $user_can,
945
            $context,
946
            $blog_id,
947
            $cap,
948
            $id
949
        );
950
        return $user_can;
951
    }
952
953
954
955
    /**
956
     * This helper method just returns an array of registered EE capabilities.
957
     *
958
     * @since 4.5.0
959
     * @param string $role If empty then the entire role/capability map is returned.
960
     *                     Otherwise just the capabilities for the given role are returned.
961
     * @return array
962
     * @throws EE_Error
963
     */
964
    public function get_ee_capabilities($role = 'administrator')
965
    {
966
        if (! $this->initialized) {
0 ignored issues
show
Bug Best Practice introduced by
The expression $this->initialized of type boolean|null is loosely compared to false; this is ambiguous if the boolean can be false. You might want to explicitly use !== null instead.

If an expression can have both false, and null as possible values. It is generally a good practice to always use strict comparison to clearly distinguish between those two values.

$a = canBeFalseAndNull();

// Instead of
if ( ! $a) { }

// Better use one of the explicit versions:
if ($a !== null) { }
if ($a !== false) { }
if ($a !== null && $a !== false) { }
Loading history...
967
            $this->init_caps();
968
        }
969
        if (empty($role)) {
970
            return $this->capabilities_map;
971
        }
972
        return isset($this->capabilities_map[ $role ])
973
            ? $this->capabilities_map[ $role ]
974
            : array();
975
    }
976
977
978
979
    /**
980
     * @deprecated 4.9.42
981
     * @param bool  $reset      If you need to reset Event Espresso's capabilities,
982
     *                          then please use the init_caps() method with the "$reset" parameter set to "true"
983
     * @param array $caps_map   Optional.
984
     *                          Can be used to send a custom map of roles and capabilities for setting them up.
985
     *                          Note that this should ONLY be called on activation hook or some other one-time
986
     *                          task otherwise the caps will be added on every request.
987
     * @return void
988
     * @throws EE_Error
989
     */
990
    public function init_role_caps($reset = false, $caps_map = array())
991
    {
992
        // If this method is called directly and reset is set as 'true',
993
        // then display a doing it wrong notice, because we want resets to go through init_caps()
994
        // to guarantee that everything is set up correctly.
995
        // This prevents the capabilities map getting reset incorrectly by direct calls to this method.
996
        if ($reset) {
997
            EE_Error::doing_it_wrong(
998
                __METHOD__,
999
                sprintf(
1000
                    esc_html__(
1001
                        'The "%1$s" parameter for the "%2$s" method is deprecated. If you need to reset Event Espresso\'s capabilities, then please use the "%3$s" method with the "%1$s" parameter set to "%4$s".',
1002
                        'event_espresso'
1003
                    ),
1004
                    '$reset',
1005
                    __METHOD__ . '()',
1006
                    'EE_Capabilities::init_caps()',
1007
                    'true'
1008
                ),
1009
                '4.9.42',
1010
                '5.0.0'
1011
            );
1012
        }
1013
        $this->addCaps($caps_map);
1014
    }
1015
1016
1017
1018
}
1019
1020
1021
1022
/**
1023
 * Meta Capability Map class.
1024
 * This children of this class are used to define capability mappings for capabilities that have further filtering
1025
 * depending on context.
1026
 *
1027
 * @since      4.5.0
1028
 * @package    Event Espresso
1029
 * @subpackage core, capabilities
1030
 * @author     Darren Ethier
1031
 */
1032
abstract class EE_Meta_Capability_Map
1033
{
1034
1035
    public $meta_cap;
1036
1037
    /**
1038
     * @var EEM_Base
1039
     */
1040
    protected $_model;
1041
1042
    protected $_model_name;
1043
1044
    public $published_cap = '';
1045
1046
    public $others_cap = '';
1047
1048
    public $private_cap = '';
1049
1050
1051
    /**
1052
     * constructor.
1053
     * Receives the setup arguments for the map.
1054
     *
1055
     * @since                        4.5.0
1056
     *
1057
     * @param string $meta_cap   What meta capability is this mapping.
1058
     * @param array  $map_values array {
1059
     *                           //array of values that MUST match a count of 4.  It's okay to send an empty string for
1060
     *                           capabilities that don't get mapped to.
1061
     *
1062
     * @type         $map_values [0] string A string representing the model name. Required.  String's
1063
     *                               should always be used when Menu Maps are registered via the
1064
     *                               plugin API as models are not allowed to be instantiated when
1065
     *                               in maintenance mode 2 (migrations).
1066
     * @type         $map_values [1] string represents the capability used for published. Optional.
1067
     * @type         $map_values [2] string represents the capability used for "others". Optional.
1068
     * @type         $map_values [3] string represents the capability used for private. Optional.
1069
     *                               }
1070
     * @throws EE_Error
1071
     */
1072
    public function __construct($meta_cap, $map_values)
1073
    {
1074
        $this->meta_cap = $meta_cap;
1075
        //verify there are four args in the $map_values array;
1076
        if (count($map_values) !== 4) {
1077
            throw new EE_Error(
1078
                sprintf(
1079
                    __(
1080
                        'Incoming $map_values array should have a count of four values in it.  This is what was given: %s',
1081
                        'event_espresso'
1082
                    ),
1083
                    '<br>' . print_r($map_values, true)
1084
                )
1085
            );
1086
        }
1087
        //set properties
1088
        $this->_model = null;
1089
        $this->_model_name = $map_values[0];
1090
        $this->published_cap = (string)$map_values[1];
1091
        $this->others_cap = (string)$map_values[2];
1092
        $this->private_cap = (string)$map_values[3];
1093
    }
1094
1095
    /**
1096
     * Makes it so this object stops filtering caps
1097
     */
1098
    public function remove_filters()
1099
    {
1100
        remove_filter('map_meta_cap', array($this, 'map_meta_caps'), 10);
1101
    }
1102
1103
1104
    /**
1105
     * This method ensures that the $model property is converted from the model name string to a proper EEM_Base class
1106
     *
1107
     * @since 4.5.0
1108
     * @throws EE_Error
1109
     *
1110
     * @return void
1111
     */
1112
    public function ensure_is_model()
1113
    {
1114
        //is it already instantiated?
1115
        if ($this->_model instanceof EEM_Base) {
1116
            return;
1117
        }
1118
        //ensure model name is string
1119
        $this->_model_name = (string)$this->_model_name;
1120
        //error proof if the name has EEM in it
1121
        $this->_model_name = str_replace('EEM', '', $this->_model_name);
1122
        $this->_model = EE_Registry::instance()->load_model($this->_model_name);
1123 View Code Duplication
        if (! $this->_model instanceof EEM_Base) {
1124
            throw new EE_Error(
1125
                sprintf(
1126
                    __(
1127
                        'This string passed in to %s to represent a EEM_Base model class was not able to be used to instantiate the class.   Please ensure that the string is a match for the EEM_Base model name (not including the EEM_ part). This was given: %s',
1128
                        'event_espresso'
1129
                    ),
1130
                    get_class($this),
1131
                    $this->_model
1132
                )
1133
            );
1134
        }
1135
    }
1136
1137
1138
    /**
1139
     *
1140
     * @see   EE_Meta_Capability_Map::_map_meta_caps() for docs on params.
1141
     * @since 4.6.x
1142
     *
1143
     * @param $caps
1144
     * @param $cap
1145
     * @param $user_id
1146
     * @param $args
1147
     *
1148
     * @return array
1149
     */
1150
    public function map_meta_caps($caps, $cap, $user_id, $args)
1151
    {
1152
        return $this->_map_meta_caps($caps, $cap, $user_id, $args);
1153
    }
1154
1155
1156
    /**
1157
     * This is the callback for the wp map_meta_caps() function which allows for ensuring certain caps that act as a
1158
     * "meta" for other caps ( i.e. ee_edit_event is a meta for ee_edit_others_events ) work as expected.
1159
     *
1160
     * @since 4.5.0
1161
     * @see   wp-includes/capabilities.php
1162
     *
1163
     * @param array  $caps    actual users capabilities
1164
     * @param string $cap     initial capability name that is being checked (the "map" key)
1165
     * @param int    $user_id The user id
1166
     * @param array  $args    Adds context to the cap. Typically the object ID.
1167
     *
1168
     * @return array   actual users capabilities
1169
     */
1170
    abstract protected function _map_meta_caps($caps, $cap, $user_id, $args);
1171
}
1172
1173
1174
/**
1175
 * Meta Capability Map class for Edit type capabilities.
1176
 * Any capability that is an edit type of capability utilizes this map.
1177
 *
1178
 * @since      4.5.0
1179
 * @package    Event Espresso
1180
 * @subpackage core, capabilities
1181
 * @author     Darren Ethier
1182
 */
1183
class EE_Meta_Capability_Map_Edit extends EE_Meta_Capability_Map
1184
{
1185
1186
    /**
1187
     * This is the callback for the wp map_meta_caps() function which allows for ensuring certain caps that act as a
1188
     * "meta" for other caps ( i.e. ee_edit_event is a meta for ee_edit_others_events ) work as expected.
1189
     *
1190
     * @since 4.5.0
1191
     * @see   wp-includes/capabilities.php
1192
     *
1193
     * @param array  $caps    actual users capabilities
1194
     * @param string $cap     initial capability name that is being checked (the "map" key)
1195
     * @param int    $user_id The user id
1196
     * @param array  $args    Adds context to the cap. Typically the object ID.
1197
     *
1198
     * @return array   actual users capabilities
1199
     */
1200
    protected function _map_meta_caps($caps, $cap, $user_id, $args)
1201
    {
1202
        //only process if we're checking our mapped_cap
1203
        if ($cap !== $this->meta_cap) {
1204
            return $caps;
1205
        }
1206
1207
        //okay it is a meta cap so let's first remove that cap from the $caps array.
1208
        if (($key = array_search($cap, $caps)) !== false) {
1209
            unset($caps[$key]);
1210
        }
1211
1212
        //cast $user_id to int for later explicit comparisons
1213
        $user_id = (int) $user_id;
1214
1215
        /** @var EE_Base_Class $obj */
1216
        $obj = ! empty($args[0]) ? $this->_model->get_one_by_ID($args[0]) : null;
1217
        //if no obj then let's just do cap
1218
        if (! $obj instanceof EE_Base_Class) {
1219
            $caps[] = 'do_not_allow';
1220
            return $caps;
1221
        }
1222
        $caps[] = $cap . 's';
1223
        if ($obj instanceof EE_CPT_Base) {
1224
            //if the item author is set and the user is the author...
1225
            if ($obj->wp_user() && $user_id === $obj->wp_user()) {
1226
                //if obj is published...
1227
                if ($obj->status() === 'publish') {
1228
                    $caps[] = $this->published_cap;
1229
                }
1230
            } else {
1231
                //the user is trying to edit someone else's obj
1232
                if (! empty($this->others_cap)) {
1233
                    $caps[] = $this->others_cap;
1234
                }
1235
                if (! empty($this->published_cap) && $obj->status() === 'publish') {
1236
                    $caps[] = $this->published_cap;
1237
                } elseif (! empty($this->private_cap) && $obj->status() === 'private') {
1238
                    $caps[] = $this->private_cap;
1239
                }
1240
            }
1241
        } else {
1242
            //not a cpt object so handled differently
1243
            $has_cap = false;
1244
            try {
1245
                $has_cap = method_exists($obj, 'wp_user')
1246
                    && $obj->wp_user()
1247
                    && $obj->wp_user() === $user_id;
1248
            } catch (Exception $e) {
1249
                if (WP_DEBUG) {
1250
                    EE_Error::add_error($e->getMessage(), __FILE__, __FUNCTION__, __LINE__);
1251
                }
1252
            }
1253
            if (! $has_cap) {
1254
                if (! empty($this->others_cap)) {
1255
                    $caps[] = $this->others_cap;
1256
                }
1257
            }
1258
        }
1259
        return $caps;
1260
    }
1261
}
1262
1263
1264
/**
1265
 * Meta Capability Map class for delete type capabilities
1266
 * Merely extends the Edit map.  Intention is for type hinting so it's clear a capability is a "delete" type of
1267
 * capability (in case mapping needs to change in the future)
1268
 *
1269
 * @since      4.5.0
1270
 * @package    Event Espresso
1271
 * @subpackage core, capabilities
1272
 * @author     Darren Ethier
1273
 */
1274
class EE_Meta_Capability_Map_Delete extends EE_Meta_Capability_Map_Edit
1275
{
1276
1277
    /**
1278
     * This is the callback for the wp map_meta_caps() function which allows for ensuring certain caps that act as a
1279
     * "meta" for other caps ( i.e. ee_edit_event is a meta for ee_edit_others_events ) work as expected.
1280
     *
1281
     * @since 4.5.0
1282
     * @see   wp-includes/capabilities.php
1283
     *
1284
     * @param array  $caps    actual users capabilities
1285
     * @param string $cap     initial capability name that is being checked (the "map" key)
1286
     * @param int    $user_id The user id
1287
     * @param array  $args    Adds context to the cap. Typically the object ID.
1288
     *
1289
     * @return array   actual users capabilities
1290
     */
1291
    protected function _map_meta_caps($caps, $cap, $user_id, $args)
1292
    {
1293
        return parent::_map_meta_caps($caps, $cap, $user_id, $args);
1294
    }
1295
}
1296
1297
1298
/**
1299
 * Meta Capability Map class for reads.
1300
 * Maps any read meta capabilities to equivalents for context.
1301
 *
1302
 * @since      4.5.0
1303
 * @package    Event Espresso
1304
 * @subpackage core, capabilities
1305
 * @author     Darren Ethier
1306
 */
1307
class EE_Meta_Capability_Map_Read extends EE_Meta_Capability_Map
1308
{
1309
1310
    /**
1311
     * This is the callback for the wp map_meta_caps() function which allows for ensuring certain caps that act as a
1312
     * "meta" for other caps ( i.e. ee_edit_event is a meta for ee_edit_others_events ) work as expected.
1313
     *
1314
     * @since 4.5.0
1315
     * @see   wp-includes/capabilities.php
1316
     *
1317
     * @param array  $caps    actual users capabilities
1318
     * @param string $cap     initial capability name that is being checked (the "map" key)
1319
     * @param int    $user_id The user id
1320
     * @param array  $args    Adds context to the cap. Typically the object ID.
1321
     *
1322
     * @return array   actual users capabilities
1323
     */
1324
    protected function _map_meta_caps($caps, $cap, $user_id, $args)
1325
    {
1326
        //only process if we're checking our mapped cap;
1327
        if ($cap !== $this->meta_cap) {
1328
            return $caps;
1329
        }
1330
1331
        //okay it is a meta cap so let's first remove that cap from the $caps array.
1332
        if (($key = array_search($cap, $caps)) !== false) {
1333
            unset($caps[$key]);
1334
        }
1335
1336
        //cast $user_id to int for later explicit comparisons
1337
        $user_id = (int) $user_id;
1338
1339
        $obj = ! empty($args[0]) ? $this->_model->get_one_by_ID($args[0]) : null;
1340
        //if no obj then let's just do cap
1341
        if (! $obj instanceof EE_Base_Class) {
1342
            $caps[] = 'do_not_allow';
1343
            return $caps;
1344
        }
1345
1346
        $caps[] = $cap . 's';
1347
        if ($obj instanceof EE_CPT_Base) {
1348
            $status_obj = get_post_status_object($obj->status());
1349
            if ($status_obj->public) {
1350
                return $caps;
1351
            }
1352
            //if the item author is set and the user is not the author...
1353
            if ($obj->wp_user() && $obj->wp_user() !== $user_id) {
1354
                if (! empty($this->others_cap)) {
1355
                    $caps[] = $this->others_cap;
1356
                }
1357
            }
1358
            //yes this means that if users created the private post, they are able to see it regardless of private cap.
1359
            if ($status_obj->private
1360
                && ! empty($this->private_cap)
1361
                && $obj->wp_user() !== $user_id
1362
            ) {
1363
                //the user is trying to view a private object for an object they don't own.
1364
                $caps[] = $this->private_cap;
1365
            }
1366
        } else {
1367
            //not a cpt object so handled differently
1368
            $has_cap = false;
1369
            try {
1370
                $has_cap = method_exists($obj, 'wp_user')
1371
                           && $obj->wp_user()
1372
                           && $obj->wp_user() === $user_id;
1373
            } catch (Exception $e) {
1374
                if (WP_DEBUG) {
1375
                    EE_Error::add_error($e->getMessage(), __FILE__, __FUNCTION__, __LINE__);
1376
                }
1377
            }
1378
            if (! $has_cap) {
1379
                if (! empty($this->private_cap)) {
1380
                    $caps[] = $this->private_cap;
1381
                }
1382
                if (! empty($this->others_cap)) {
1383
                    $caps[] = $this->others_cap;
1384
                }
1385
            }
1386
        }
1387
        return $caps;
1388
    }
1389
}
1390
1391
1392
/**
1393
 * Meta Capability Map class for the messages component
1394
 * This is a special map due to messages having global and custom messages.  Only users with the edit_global_message
1395
 * capability should be able to do things with the global messages.
1396
 *
1397
 * @since      4.5.0
1398
 * @package    Event Espresso
1399
 * @subpackage core, capabilities
1400
 * @author     Darren Ethier
1401
 */
1402
class EE_Meta_Capability_Map_Messages_Cap extends EE_Meta_Capability_Map
1403
{
1404
1405
    /**
1406
     * This is the callback for the wp map_meta_caps() function which allows for ensuring certain caps that act as a
1407
     * "meta" for other caps ( i.e. ee_edit_event is a meta for ee_edit_others_events ) work as expected.
1408
     *
1409
     * @since 4.5.0
1410
     * @see   wp-includes/capabilities.php
1411
     *
1412
     * @param array  $caps    actual users capabilities
1413
     * @param string $cap     initial capability name that is being checked (the "map" key)
1414
     * @param int    $user_id The user id
1415
     * @param array  $args    Adds context to the cap. Typically the object ID.
1416
     *
1417
     * @return array   actual users capabilities
1418
     */
1419
    protected function _map_meta_caps($caps, $cap, $user_id, $args)
1420
    {
1421
        //only process if we're checking our mapped_cap
1422
        if ($cap !== $this->meta_cap) {
1423
            return $caps;
1424
        }
1425
1426
        //okay it is a meta cap so let's first remove that cap from the $caps array.
1427
        if (($key = array_search($cap, $caps)) !== false) {
1428
            unset($caps[$key]);
1429
        }
1430
1431
        //cast $user_id to int for later explicit comparisons
1432
        $user_id = (int) $user_id;
1433
1434
        $obj = ! empty($args[0]) ? $this->_model->get_one_by_ID($args[0]) : null;
1435
        //if no obj then let's just do cap
1436
        if (! $obj instanceof EE_Message_Template_Group) {
1437
            $caps[] = 'do_not_allow';
1438
            return $caps;
1439
        }
1440
        $caps[] = $cap . 's';
1441
        $is_global = $obj->is_global();
1442
        if ($obj->wp_user() && $obj->wp_user() === $user_id) {
1443
            if ($is_global) {
1444
                $caps[] = $this->private_cap;
1445
            }
1446
        } else {
1447
            if ($is_global) {
1448
                $caps[] = $this->private_cap;
1449
            } else {
1450
                $caps[] = $this->others_cap;
1451
            }
1452
        }
1453
        return $caps;
1454
    }
1455
}
1456
1457
1458
/**
1459
 * Meta Capability Map class for the registration form (questions and question groups) component
1460
 * This is a special map due to questions and question groups having special "system" data.  Only users with the
1461
 * edit_system_question or edit_system_question_group capability should be able to do things with the system data.
1462
 *
1463
 * @since      4.5.0
1464
 * @package    Event Espresso
1465
 * @subpackage core, capabilities
1466
 * @author     Darren Ethier
1467
 */
1468
class EE_Meta_Capability_Map_Registration_Form_Cap extends EE_Meta_Capability_Map
1469
{
1470
1471
    /**
1472
     * This is the callback for the wp map_meta_caps() function which allows for ensuring certain caps that act as a
1473
     * "meta" for other caps ( i.e. ee_edit_event is a meta for ee_edit_others_events ) work as expected.
1474
     *
1475
     * @since 4.5.0
1476
     * @see   wp-includes/capabilities.php
1477
     * @param array  $caps    actual users capabilities
1478
     * @param string $cap     initial capability name that is being checked (the "map" key)
1479
     * @param int    $user_id The user id
1480
     * @param array  $args    Adds context to the cap. Typically the object ID.
1481
     * @return array   actual users capabilities
1482
     */
1483
    protected function _map_meta_caps($caps, $cap, $user_id, $args)
1484
    {
1485
        //only process if we're checking our mapped_cap
1486
        if ($cap !== $this->meta_cap) {
1487
            return $caps;
1488
        }
1489
        //okay it is a meta cap so let's first remove that cap from the $caps array.
1490
        if (($key = array_search($cap, $caps)) !== false) {
1491
            unset($caps[$key]);
1492
        }
1493
        $obj = ! empty($args[0]) ? $this->_model->get_one_by_ID($args[0]) : null;
1494
        //if no obj then let's just do cap
1495
        if (! $obj instanceof EE_Base_Class) {
1496
            $caps[] = 'do_not_allow';
1497
            return $caps;
1498
        }
1499
        $caps[]    = $cap . 's';
1500
        $is_system = $obj instanceof EE_Question_Group ? $obj->system_group() : false;
1501
        $is_system = $obj instanceof EE_Question ? $obj->is_system_question() : $is_system;
1502
        if ($is_system) {
1503
            $caps[] = $this->private_cap;
1504
        }
1505
        return $caps;
1506
    }
1507
}
1508