Completed
Branch BUG-10725-paypal-express-dupli... (e50e53)
by
unknown
31:07 queued 17:12
created

EE_Capabilities   B

Complexity

Total Complexity 37

Size/Duplication

Total Lines 798
Duplicated Lines 0 %

Coupling/Cohesion

Components 2
Dependencies 8

Importance

Changes 0
Metric Value
dl 0
loc 798
rs 8.6
c 0
b 0
f 0
wmc 37
lcom 2
cbo 8

14 Methods

Rating   Name   Duplication   Size   Complexity  
A instance() 0 8 2
A __construct() 0 3 1
A init_caps() 0 8 2
A _set_meta_caps() 0 10 2
B _get_default_meta_caps_array() 0 122 2
B map_meta_caps() 0 17 5
B _init_caps_map() 0 316 1
B init_role_caps() 0 20 8
A add_cap_to_role() 0 19 3
A remove_cap_from_role() 0 7 2
A current_user_can() 0 8 2
A user_can() 0 8 2
A current_user_can_for_blog() 0 23 2
A get_ee_capabilities() 0 8 3
1
<?php
2
defined('EVENT_ESPRESSO_VERSION') || exit('No direct script access allowed');
3
4
5
6
/**
7
 * This class contains all the code related to Event Espresso capabilities.
8
 * Assigned to the EE_Registry::instance()->CAP property.
9
 *
10
 * @link       https://github.com/eventespresso/event-espresso-core/tree/master/docs/K--Capability-System
11
 *
12
 * @since      4.5.0
13
 * @package    Event Espresso
14
 * @subpackage core, capabilities
15
 * @author     Darren Ethier
16
 */
17
final class EE_Capabilities extends EE_Base
18
{
19
20
    /**
21
     * the name of the wp option used to store caps previously initialized
22
     */
23
    const option_name = 'ee_caps_initialized';
24
25
    /**
26
     * instance of EE_Capabilities object
27
     *
28
     * @var EE_Capabilities
29
     */
30
    private static $_instance;
31
32
33
    /**
34
     * This is a map of caps that correspond to a default WP_Role.
35
     * Array is indexed by Role and values are ee capabilities.
36
     *
37
     * @since 4.5.0
38
     *
39
     * @var array
40
     */
41
    private $_caps_map = array();
42
43
44
    /**
45
     * This used to hold an array of EE_Meta_Capability_Map objects that define the granular capabilities mapped to for
46
     * a user depending on context.
47
     *
48
     * @var EE_Meta_Capability_Map[]
49
     */
50
    private $_meta_caps = array();
51
52
53
    /**
54
     * singleton method used to instantiate class object
55
     *
56
     * @since 4.5.0
57
     *
58
     * @return EE_Capabilities
59
     */
60
    public static function instance()
61
    {
62
        //check if instantiated, and if not do so.
63
        if (! self::$_instance instanceof EE_Capabilities) {
64
            self::$_instance = new self();
65
        }
66
        return self::$_instance;
67
    }
68
69
70
    /**
71
     * private constructor
72
     *
73
     * @since 4.5.0
74
     *
75
     * @return \EE_Capabilities
0 ignored issues
show
Comprehensibility Best Practice introduced by
Adding a @return annotation to constructors is generally not recommended as a constructor does not have a meaningful return value.

Adding a @return annotation to a constructor is not recommended, since a constructor does not have a meaningful return value.

Please refer to the PHP core documentation on constructors.

Loading history...
76
     */
77
    private function __construct()
78
    {
79
    }
80
81
82
    /**
83
     * This delays the initialization of the capabilities class until EE_System core is loaded and ready.
84
     *
85
     * @param bool $reset allows for resetting the default capabilities saved on roles.  Note that this doesn't
86
     *                    actually REMOVE any capabilities from existing roles, it just resaves defaults roles and
87
     *                    ensures that they are up to date.
88
     *
89
     *
90
     * @since 4.5.0
91
     * @return void
92
     */
93
    public function init_caps($reset = false)
94
    {
95
        if (EE_Maintenance_Mode::instance()->models_can_query()) {
96
            $this->_caps_map = $this->_init_caps_map();
97
            $this->init_role_caps($reset);
98
            $this->_set_meta_caps();
99
        }
100
    }
101
102
103
    /**
104
     * This sets the meta caps property.
105
     * @since 4.5.0
106
     *
107
     * @return void
108
     */
109
    private function _set_meta_caps()
110
    {
111
        //make sure we're only ever initializing the default _meta_caps array once if it's empty.
112
        $this->_meta_caps = $this->_get_default_meta_caps_array();
113
        $this->_meta_caps = apply_filters('FHEE__EE_Capabilities___set_meta_caps__meta_caps', $this->_meta_caps);
114
        //add filter for map_meta_caps but only if models can query.
115
        if (! has_filter('map_meta_cap', array($this, 'map_meta_caps'))) {
116
            add_filter('map_meta_cap', array($this, 'map_meta_caps'), 10, 4);
117
        }
118
    }
119
120
121
    /**
122
     * This builds and returns the default meta_caps array only once.
123
     *
124
     * @since  4.8.28.rc.012
125
     * @return array
126
     * @throws \EE_Error
127
     */
128
    private function _get_default_meta_caps_array()
129
    {
130
        static $default_meta_caps = array();
131
        if (empty($default_meta_caps)) {
132
            $default_meta_caps = array(
133
                //edits
134
                new EE_Meta_Capability_Map_Edit(
135
                    'ee_edit_event',
136
                    array('Event', 'ee_edit_published_events', 'ee_edit_others_events', 'ee_edit_private_events')
137
                ),
138
                new EE_Meta_Capability_Map_Edit(
139
                    'ee_edit_venue',
140
                    array('Venue', 'ee_edit_published_venues', 'ee_edit_others_venues', 'ee_edit_private_venues')
141
                ),
142
                new EE_Meta_Capability_Map_Edit(
143
                    'ee_edit_registration',
144
                    array('Registration', '', 'ee_edit_others_registrations', '')
145
                ),
146
                new EE_Meta_Capability_Map_Edit(
147
                    'ee_edit_checkin',
148
                    array('Registration', '', 'ee_edit_others_checkins', '')
149
                ),
150
                new EE_Meta_Capability_Map_Messages_Cap(
151
                    'ee_edit_message',
152
                    array('Message_Template_Group', '', 'ee_edit_others_messages', 'ee_edit_global_messages')
153
                ),
154
                new EE_Meta_Capability_Map_Edit(
155
                    'ee_edit_default_ticket',
156
                    array('Ticket', '', 'ee_edit_others_default_tickets', '')
157
                ),
158
                new EE_Meta_Capability_Map_Registration_Form_Cap(
159
                    'ee_edit_question',
160
                    array('Question', '', '', 'ee_edit_system_questions')
161
                ),
162
                new EE_Meta_Capability_Map_Registration_Form_Cap(
163
                    'ee_edit_question_group',
164
                    array('Question_Group', '', '', 'ee_edit_system_question_groups')
165
                ),
166
                new EE_Meta_Capability_Map_Edit(
167
                    'ee_edit_payment_method',
168
                    array('Payment_Method', '', 'ee_edit_others_payment_methods', '')
169
                ),
170
                //reads
171
                new EE_Meta_Capability_Map_Read(
172
                    'ee_read_event',
173
                    array('Event', '', 'ee_read_others_events', 'ee_read_private_events')
174
                ),
175
                new EE_Meta_Capability_Map_Read(
176
                    'ee_read_venue',
177
                    array('Venue', '', 'ee_read_others_venues', 'ee_read_private_venues')
178
                ),
179
                new EE_Meta_Capability_Map_Read(
180
                    'ee_read_registration',
181
                    array('Registration', '', '', 'ee_edit_others_registrations')
182
                ),
183
                new EE_Meta_Capability_Map_Read(
184
                    'ee_read_checkin',
185
                    array('Registration', '', '', 'ee_read_others_checkins')
186
                ),
187
                new EE_Meta_Capability_Map_Messages_Cap(
188
                    'ee_read_message',
189
                    array('Message_Template_Group', '', 'ee_read_others_messages', 'ee_read_global_messages')
190
                ),
191
                new EE_Meta_Capability_Map_Read(
192
                    'ee_read_default_ticket',
193
                    array('Ticket', '', '', 'ee_read_others_default_tickets')
194
                ),
195
                new EE_Meta_Capability_Map_Read(
196
                    'ee_read_payment_method',
197
                    array('Payment_Method', '', '', 'ee_read_others_payment_methods')),
198
199
                //deletes
200
                new EE_Meta_Capability_Map_Delete(
201
                    'ee_delete_event',
202
                    array(
203
                        'Event',
204
                        'ee_delete_published_events',
205
                        'ee_delete_others_events',
206
                        'ee_delete_private_events',
207
                    )
208
                ),
209
                new EE_Meta_Capability_Map_Delete(
210
                    'ee_delete_venue',
211
                    array(
212
                        'Venue',
213
                        'ee_delete_published_venues',
214
                        'ee_delete_others_venues',
215
                        'ee_delete_private_venues',
216
                    )
217
                ),
218
                new EE_Meta_Capability_Map_Delete(
219
                    'ee_delete_registration',
220
                    array('Registration', '', 'ee_delete_others_registrations', '')
221
                ),
222
                new EE_Meta_Capability_Map_Delete(
223
                    'ee_delete_checkin',
224
                    array('Registration', '', 'ee_delete_others_checkins', '')
225
                ),
226
                new EE_Meta_Capability_Map_Messages_Cap(
227
                    'ee_delete_message',
228
                    array('Message_Template_Group', '', 'ee_delete_others_messages', 'ee_delete_global_messages')
229
                ),
230
                new EE_Meta_Capability_Map_Delete(
231
                    'ee_delete_default_ticket',
232
                    array('Ticket', '', 'ee_delete_others_default_tickets', '')
233
                ),
234
                new EE_Meta_Capability_Map_Registration_Form_Cap(
235
                    'ee_delete_question',
236
                    array('Question', '', '', 'delete_system_questions')
237
                ),
238
                new EE_Meta_Capability_Map_Registration_Form_Cap(
239
                    'ee_delete_question_group',
240
                    array('Question_Group', '', '', 'delete_system_question_groups')
241
                ),
242
                new EE_Meta_Capability_Map_Delete(
243
                    'ee_delete_payment_method',
244
                    array('Payment_Method', '', 'ee_delete_others_payment_methods', '')
245
                ),
246
            );
247
        }
248
        return $default_meta_caps;
249
    }
250
251
252
    /**
253
     * This is the callback for the wp map_meta_caps() function which allows for ensuring certain caps that act as a
254
     * "meta" for other caps ( i.e. ee_edit_event is a meta for ee_edit_others_events ) work as expected.
255
     *
256
     * The actual logic is carried out by implementer classes in their definition of _map_meta_caps.
257
     *
258
     * @since 4.5.0
259
     * @see   wp-includes/capabilities.php
260
     *
261
     * @param array  $caps    actual users capabilities
262
     * @param string $cap     initial capability name that is being checked (the "map" key)
263
     * @param int    $user_id The user id
264
     * @param array  $args    Adds context to the cap. Typically the object ID.
265
     * @return array actual users capabilities
266
     * @throws EE_Error
267
     */
268
    public function map_meta_caps($caps, $cap, $user_id, $args)
269
    {
270
        if (did_action('AHEE__EE_System__load_espresso_addons__complete')) {
271
            //loop through our _meta_caps array
272
            foreach ($this->_meta_caps as $meta_map) {
273
                if (! $meta_map instanceof EE_Meta_Capability_Map) {
274
                    continue;
275
                }
276
                // don't load models if there is no object ID in the args
277
                if(!empty($args[0])){
278
                    $meta_map->ensure_is_model();
279
                }
280
                $caps = $meta_map->map_meta_caps($caps, $cap, $user_id, $args);
281
            }
282
        }
283
        return $caps;
284
    }
285
286
287
    /**
288
     * This sets up and returns the initial capabilities map for Event Espresso
289
     *
290
     * @since 4.5.0
291
     *
292
     * @return array
293
     */
294
    private function _init_caps_map()
295
    {
296
        $caps = array(
297
            'administrator'           => array(
298
                //basic access
299
                'ee_read_ee',
300
                //gateways
301
                /**
302
                 * note that with payment method capabilities, although we've implemented
303
                 * capability mapping which will be used for accessing payment methods owned by
304
                 * other users.  This is not fully implemented yet in the payment method ui.
305
                 * Currently only the "plural" caps are in active use.
306
                 * (Specific payment method caps are in use as well).
307
                 **/
308
                'ee_manage_gateways',
309
                'ee_read_payment_method',
310
                'ee_read_payment_methods',
311
                'ee_read_others_payment_methods',
312
                'ee_edit_payment_method',
313
                'ee_edit_payment_methods',
314
                'ee_edit_others_payment_methods',
315
                'ee_delete_payment_method',
316
                'ee_delete_payment_methods',
317
                //events
318
                'ee_publish_events',
319
                'ee_read_private_events',
320
                'ee_read_others_events',
321
                'ee_read_event',
322
                'ee_read_events',
323
                'ee_edit_event',
324
                'ee_edit_events',
325
                'ee_edit_published_events',
326
                'ee_edit_others_events',
327
                'ee_edit_private_events',
328
                'ee_delete_published_events',
329
                'ee_delete_private_events',
330
                'ee_delete_event',
331
                'ee_delete_events',
332
                'ee_delete_others_events',
333
                //event categories
334
                'ee_manage_event_categories',
335
                'ee_edit_event_category',
336
                'ee_delete_event_category',
337
                'ee_assign_event_category',
338
                //venues
339
                'ee_publish_venues',
340
                'ee_read_venue',
341
                'ee_read_venues',
342
                'ee_read_others_venues',
343
                'ee_read_private_venues',
344
                'ee_edit_venue',
345
                'ee_edit_venues',
346
                'ee_edit_others_venues',
347
                'ee_edit_published_venues',
348
                'ee_edit_private_venues',
349
                'ee_delete_venue',
350
                'ee_delete_venues',
351
                'ee_delete_others_venues',
352
                'ee_delete_private_venues',
353
                'ee_delete_published_venues',
354
                //venue categories
355
                'ee_manage_venue_categories',
356
                'ee_edit_venue_category',
357
                'ee_delete_venue_category',
358
                'ee_assign_venue_category',
359
                //contacts
360
                'ee_read_contact',
361
                'ee_read_contacts',
362
                'ee_edit_contact',
363
                'ee_edit_contacts',
364
                'ee_delete_contact',
365
                'ee_delete_contacts',
366
                //registrations
367
                'ee_read_registration',
368
                'ee_read_registrations',
369
                'ee_read_others_registrations',
370
                'ee_edit_registration',
371
                'ee_edit_registrations',
372
                'ee_edit_others_registrations',
373
                'ee_delete_registration',
374
                'ee_delete_registrations',
375
                //checkins
376
                'ee_read_checkin',
377
                'ee_read_others_checkins',
378
                'ee_read_checkins',
379
                'ee_edit_checkin',
380
                'ee_edit_checkins',
381
                'ee_edit_others_checkins',
382
                'ee_delete_checkin',
383
                'ee_delete_checkins',
384
                'ee_delete_others_checkins',
385
                //transactions && payments
386
                'ee_read_transaction',
387
                'ee_read_transactions',
388
                'ee_edit_payments',
389
                'ee_delete_payments',
390
                //messages
391
                'ee_read_message',
392
                'ee_read_messages',
393
                'ee_read_others_messages',
394
                'ee_read_global_messages',
395
                'ee_edit_global_messages',
396
                'ee_edit_message',
397
                'ee_edit_messages',
398
                'ee_edit_others_messages',
399
                'ee_delete_message',
400
                'ee_delete_messages',
401
                'ee_delete_others_messages',
402
                'ee_delete_global_messages',
403
                'ee_send_message',
404
                //tickets
405
                'ee_read_default_ticket',
406
                'ee_read_default_tickets',
407
                'ee_read_others_default_tickets',
408
                'ee_edit_default_ticket',
409
                'ee_edit_default_tickets',
410
                'ee_edit_others_default_tickets',
411
                'ee_delete_default_ticket',
412
                'ee_delete_default_tickets',
413
                'ee_delete_others_default_tickets',
414
                //prices
415
                'ee_edit_default_price',
416
                'ee_edit_default_prices',
417
                'ee_delete_default_price',
418
                'ee_delete_default_prices',
419
                'ee_edit_default_price_type',
420
                'ee_edit_default_price_types',
421
                'ee_delete_default_price_type',
422
                'ee_delete_default_price_types',
423
                'ee_read_default_prices',
424
                'ee_read_default_price_types',
425
                //registration form
426
                'ee_edit_question',
427
                'ee_edit_questions',
428
                'ee_edit_system_questions',
429
                'ee_read_questions',
430
                'ee_delete_question',
431
                'ee_delete_questions',
432
                'ee_edit_question_group',
433
                'ee_edit_question_groups',
434
                'ee_read_question_groups',
435
                'ee_edit_system_question_groups',
436
                'ee_delete_question_group',
437
                'ee_delete_question_groups',
438
                //event_type taxonomy
439
                'ee_assign_event_type',
440
                'ee_manage_event_types',
441
                'ee_edit_event_type',
442
                'ee_delete_event_type',
443
            ),
444
            'ee_events_administrator' => array(
445
                //core wp caps
446
                'read',
447
                'read_private_pages',
448
                'read_private_posts',
449
                'edit_users',
450
                'edit_posts',
451
                'edit_pages',
452
                'edit_published_posts',
453
                'edit_published_pages',
454
                'edit_private_pages',
455
                'edit_private_posts',
456
                'edit_others_posts',
457
                'edit_others_pages',
458
                'publish_posts',
459
                'publish_pages',
460
                'delete_posts',
461
                'delete_pages',
462
                'delete_private_pages',
463
                'delete_private_posts',
464
                'delete_published_pages',
465
                'delete_published_posts',
466
                'delete_others_posts',
467
                'delete_others_pages',
468
                'manage_categories',
469
                'manage_links',
470
                'moderate_comments',
471
                'unfiltered_html',
472
                'upload_files',
473
                'export',
474
                'import',
475
                'list_users',
476
                'level_1', //required if user with this role shows up in author dropdowns
477
                //basic ee access
478
                'ee_read_ee',
479
                //events
480
                'ee_publish_events',
481
                'ee_read_private_events',
482
                'ee_read_others_events',
483
                'ee_read_event',
484
                'ee_read_events',
485
                'ee_edit_event',
486
                'ee_edit_events',
487
                'ee_edit_published_events',
488
                'ee_edit_others_events',
489
                'ee_edit_private_events',
490
                'ee_delete_published_events',
491
                'ee_delete_private_events',
492
                'ee_delete_event',
493
                'ee_delete_events',
494
                'ee_delete_others_events',
495
                //event categories
496
                'ee_manage_event_categories',
497
                'ee_edit_event_category',
498
                'ee_delete_event_category',
499
                'ee_assign_event_category',
500
                //venues
501
                'ee_publish_venues',
502
                'ee_read_venue',
503
                'ee_read_venues',
504
                'ee_read_others_venues',
505
                'ee_read_private_venues',
506
                'ee_edit_venue',
507
                'ee_edit_venues',
508
                'ee_edit_others_venues',
509
                'ee_edit_published_venues',
510
                'ee_edit_private_venues',
511
                'ee_delete_venue',
512
                'ee_delete_venues',
513
                'ee_delete_others_venues',
514
                'ee_delete_private_venues',
515
                'ee_delete_published_venues',
516
                //venue categories
517
                'ee_manage_venue_categories',
518
                'ee_edit_venue_category',
519
                'ee_delete_venue_category',
520
                'ee_assign_venue_category',
521
                //contacts
522
                'ee_read_contact',
523
                'ee_read_contacts',
524
                'ee_edit_contact',
525
                'ee_edit_contacts',
526
                'ee_delete_contact',
527
                'ee_delete_contacts',
528
                //registrations
529
                'ee_read_registration',
530
                'ee_read_registrations',
531
                'ee_read_others_registrations',
532
                'ee_edit_registration',
533
                'ee_edit_registrations',
534
                'ee_edit_others_registrations',
535
                'ee_delete_registration',
536
                'ee_delete_registrations',
537
                //checkins
538
                'ee_read_checkin',
539
                'ee_read_others_checkins',
540
                'ee_read_checkins',
541
                'ee_edit_checkin',
542
                'ee_edit_checkins',
543
                'ee_edit_others_checkins',
544
                'ee_delete_checkin',
545
                'ee_delete_checkins',
546
                'ee_delete_others_checkins',
547
                //transactions && payments
548
                'ee_read_transaction',
549
                'ee_read_transactions',
550
                'ee_edit_payments',
551
                'ee_delete_payments',
552
                //messages
553
                'ee_read_message',
554
                'ee_read_messages',
555
                'ee_read_others_messages',
556
                'ee_read_global_messages',
557
                'ee_edit_global_messages',
558
                'ee_edit_message',
559
                'ee_edit_messages',
560
                'ee_edit_others_messages',
561
                'ee_delete_message',
562
                'ee_delete_messages',
563
                'ee_delete_others_messages',
564
                'ee_delete_global_messages',
565
                'ee_send_message',
566
                //tickets
567
                'ee_read_default_ticket',
568
                'ee_read_default_tickets',
569
                'ee_read_others_default_tickets',
570
                'ee_edit_default_ticket',
571
                'ee_edit_default_tickets',
572
                'ee_edit_others_default_tickets',
573
                'ee_delete_default_ticket',
574
                'ee_delete_default_tickets',
575
                'ee_delete_others_default_tickets',
576
                //prices
577
                'ee_edit_default_price',
578
                'ee_edit_default_prices',
579
                'ee_delete_default_price',
580
                'ee_delete_default_prices',
581
                'ee_edit_default_price_type',
582
                'ee_edit_default_price_types',
583
                'ee_delete_default_price_type',
584
                'ee_delete_default_price_types',
585
                'ee_read_default_prices',
586
                'ee_read_default_price_types',
587
                //registration form
588
                'ee_edit_question',
589
                'ee_edit_questions',
590
                'ee_edit_system_questions',
591
                'ee_read_questions',
592
                'ee_delete_question',
593
                'ee_delete_questions',
594
                'ee_edit_question_group',
595
                'ee_edit_question_groups',
596
                'ee_read_question_groups',
597
                'ee_edit_system_question_groups',
598
                'ee_delete_question_group',
599
                'ee_delete_question_groups',
600
                //event_type taxonomy
601
                'ee_assign_event_type',
602
                'ee_manage_event_types',
603
                'ee_edit_event_type',
604
                'ee_delete_event_type',
605
            )
606
        );
607
        $caps = apply_filters('FHEE__EE_Capabilities__init_caps_map__caps', $caps);
608
        return $caps;
609
    }
610
611
612
    /**
613
     * This adds all the default caps to roles as registered in the _caps_map property.
614
     *
615
     * @since 4.5.0
616
     *
617
     * @param bool  $reset      allows for resetting the default capabilities saved on roles.  Note that this doesn't
618
     *                          actually REMOVE any capabilities from existing roles, it just resaves defaults roles
619
     *                          and ensures that they are up to date.
620
     * @param array $custom_map Optional.  Can be used to send a custom map of roles and capabilities for setting them
621
     *                          up.  Note that this should ONLY be called on activation hook or some other one-time
622
     *                          task otherwise the caps will be added on every request.
623
     *
624
     * @return void
625
     */
626
    public function init_role_caps($reset = false, $custom_map = array())
627
    {
628
        $caps_map = empty($custom_map) ? $this->_caps_map : $custom_map;
629
        //first let's determine if these caps have already been set.
630
        $caps_set_before = get_option(self::option_name, array());
631
        //if not reset, see what caps are new for each role. if they're new, add them.
632
        foreach ($caps_map as $role => $caps_for_role) {
633
            foreach ($caps_for_role as $cap) {
634
                //first check we haven't already added this cap before, or it's a reset
635
                if ($reset || ! isset($caps_set_before[ $role ]) || ! in_array($cap, $caps_set_before[ $role ])) {
636
                    if ($this->add_cap_to_role($role, $cap)) {
637
                        $caps_set_before[ $role ][] = $cap;
638
                    }
639
                }
640
            }
641
        }
642
        //now let's just save the cap that has been set.
643
        update_option(self::option_name, $caps_set_before);
644
        do_action('AHEE__EE_Capabilities__init_role_caps__complete', $caps_set_before);
645
    }
646
647
648
    /**
649
     * This method sets a capability on a role.  Note this should only be done on activation, or if you have something
650
     * specific to prevent the cap from being added on every page load (adding caps are persistent to the db). Note.
651
     * this is a wrapper for $wp_role->add_cap()
652
     *
653
     * @see   wp-includes/capabilities.php
654
     *
655
     * @since 4.5.0
656
     *
657
     * @param string $role  A WordPress role the capability is being added to
658
     * @param string $cap   The capability being added to the role
659
     * @param bool   $grant Whether to grant access to this cap on this role.
660
     *
661
     * @return bool
662
     */
663
    public function add_cap_to_role($role, $cap, $grant = true)
664
    {
665
        $role_object = get_role($role);
666
        //if the role isn't available then we create it.
667
        if (! $role_object instanceof WP_Role) {
668
            //if a plugin wants to create a specific role name then they should create the role before
669
            //EE_Capabilities does.  Otherwise this function will create the role name from the slug:
670
            // - removes any `ee_` namespacing from the start of the slug.
671
            // - replaces `_` with ` ` (empty space).
672
            // - sentence case on the resulting string.
673
            $role_label = ucwords(str_replace('_', ' ', str_replace('ee_', '', $role)));
674
            $role_object = add_role($role, $role_label);
675
        }
676
        if ($role_object instanceof WP_Role) {
677
            $role_object->add_cap($cap, $grant);
678
            return true;
679
        }
680
        return false;
681
    }
682
683
684
    /**
685
     * Functions similarly to add_cap_to_role except removes cap from given role.
686
     * Wrapper for $wp_role->remove_cap()
687
     *
688
     * @see   wp-includes/capabilities.php
689
     * @since 4.5.0
690
     *
691
     * @param string $role A WordPress role the capability is being removed from.
692
     * @param string $cap  The capability being removed
693
     *
694
     * @return void
695
     */
696
    public function remove_cap_from_role($role, $cap)
697
    {
698
        $role = get_role($role);
699
        if ($role instanceof WP_Role) {
700
            $role->remove_cap($cap);
701
        }
702
    }
703
704
705
    /**
706
     * Wrapper for the native WP current_user_can() method.
707
     * This is provided as a handy method for a couple things:
708
     * 1. Using the context string it allows for targeted filtering by addons for a specific check (without having to
709
     * write those filters wherever current_user_can is called).
710
     * 2. Explicit passing of $id from a given context ( useful in the cases of map_meta_cap filters )
711
     *
712
     * @since 4.5.0
713
     *
714
     * @param string $cap     The cap being checked.
715
     * @param string $context The context where the current_user_can is being called from.
716
     * @param int    $id      Optional. Id for item where current_user_can is being called from (used in map_meta_cap()
717
     *                        filters.
718
     *
719
     * @return bool  Whether user can or not.
720
     */
721
    public function current_user_can($cap, $context, $id = 0)
722
    {
723
        //apply filters (both a global on just the cap, and context specific.  Global overrides context specific)
724
        $filtered_cap = apply_filters('FHEE__EE_Capabilities__current_user_can__cap__' . $context, $cap, $id);
725
        $filtered_cap = apply_filters('FHEE__EE_Capabilities__current_user_can__cap', $filtered_cap, $context, $cap,
726
            $id);
727
        return ! empty($id) ? current_user_can($filtered_cap, $id) : current_user_can($filtered_cap);
728
    }
729
730
731
    /**
732
     * This is a wrapper for the WP user_can() function and follows the same style as the other wrappers in this class.
733
     *
734
     * @param int|WP_User $user    Either the user_id or a WP_User object
735
     * @param string      $cap     The capability string being checked
736
     * @param string      $context The context where the user_can is being called from (used in filters).
737
     * @param int         $id      Optional. Id for item where user_can is being called from ( used in map_meta_cap()
738
     *                             filters)
739
     *
740
     * @return bool Whether user can or not.
741
     */
742
    public function user_can($user, $cap, $context, $id = 0)
743
    {
744
        //apply filters (both a global on just the cap, and context specific.  Global overrides context specific)
745
        $filtered_cap = apply_filters('FHEE__EE_Capabilities__user_can__cap__' . $context, $cap, $user, $id);
746
        $filtered_cap = apply_filters('FHEE__EE_Capabilities__user_can__cap', $filtered_cap, $context, $cap, $user,
747
            $id);
748
        return ! empty($id) ? user_can($user, $filtered_cap, $id) : user_can($user, $filtered_cap);
749
    }
750
751
752
    /**
753
     * Wrapper for the native WP current_user_can_for_blog() method.
754
     * This is provided as a handy method for a couple things:
755
     * 1. Using the context string it allows for targeted filtering by addons for a specific check (without having to
756
     * write those filters wherever current_user_can is called).
757
     * 2. Explicit passing of $id from a given context ( useful in the cases of map_meta_cap filters )
758
     *
759
     * @since 4.5.0
760
     *
761
     * @param int    $blog_id The blog id that is being checked for.
762
     * @param string $cap     The cap being checked.
763
     * @param string $context The context where the current_user_can is being called from.
764
     * @param int    $id      Optional. Id for item where current_user_can is being called from (used in map_meta_cap()
765
     *                        filters.
766
     *
767
     * @return bool  Whether user can or not.
768
     */
769
    public function current_user_can_for_blog($blog_id, $cap, $context, $id = 0)
770
    {
771
        $user_can = ! empty($id)
772
            ? current_user_can_for_blog($blog_id, $cap, $id)
773
            : current_user_can($blog_id, $cap);
774
        //apply filters (both a global on just the cap, and context specific.  Global overrides context specific)
775
        $user_can = apply_filters(
776
            'FHEE__EE_Capabilities__current_user_can_for_blog__user_can__' . $context,
777
            $user_can,
778
            $blog_id,
779
            $cap,
780
            $id
781
        );
782
        $user_can = apply_filters(
783
            'FHEE__EE_Capabilities__current_user_can_for_blog__user_can',
784
            $user_can,
785
            $context,
786
            $blog_id,
787
            $cap,
788
            $id
789
        );
790
        return $user_can;
791
    }
792
793
794
    /**
795
     * This helper method just returns an array of registered EE capabilities.
796
     * Note this array is filtered.  It is assumed that all available EE capabilities are assigned to the administrator
797
     * role.
798
     *
799
     * @since 4.5.0
800
     *
801
     * @param string $role If empty then the entire role/capability map is returned.  Otherwise just the capabilities
802
     *                     for the given role are returned.
803
     *
804
     * @return array
805
     */
806
    public function get_ee_capabilities($role = 'administrator')
807
    {
808
        $capabilities = $this->_init_caps_map();
809
        if (empty($role)) {
810
            return $capabilities;
811
        }
812
        return isset($capabilities[ $role ]) ? $capabilities[ $role ] : array();
813
    }
814
}
815
816
817
/**
818
 * Meta Capability Map class.
819
 * This children of this class are used to define capability mappings for capabilities that have further filtering
820
 * depending on context.
821
 *
822
 * @since      4.5.0
823
 * @package    Event Espresso
824
 * @subpackage core, capabilities
825
 * @author     Darren Ethier
826
 */
827
abstract class EE_Meta_Capability_Map
828
{
829
830
    public $meta_cap;
831
832
    /**
833
     * @var EEM_Base
834
     */
835
    protected $_model;
836
837
    protected $_model_name;
838
839
    public $published_cap = '';
840
841
    public $others_cap = '';
842
843
    public $private_cap = '';
844
845
846
    /**
847
     * constructor.
848
     * Receives the setup arguments for the map.
849
     *
850
     * @since                        4.5.0
851
     *
852
     * @param string $meta_cap   What meta capability is this mapping.
853
     * @param array  $map_values array {
854
     *                           //array of values that MUST match a count of 4.  It's okay to send an empty string for
855
     *                           capabilities that don't get mapped to.
856
     *
857
     * @type         $map_values [0] string A string representing the model name. Required.  String's
858
     *                               should always be used when Menu Maps are registered via the
859
     *                               plugin API as models are not allowed to be instantiated when
860
     *                               in maintenance mode 2 (migrations).
861
     * @type         $map_values [1] string represents the capability used for published. Optional.
862
     * @type         $map_values [2] string represents the capability used for "others". Optional.
863
     * @type         $map_values [3] string represents the capability used for private. Optional.
864
     *                               }
865
     * @throws EE_Error
866
     */
867
    public function __construct($meta_cap, $map_values)
868
    {
869
        $this->meta_cap = $meta_cap;
870
        //verify there are four args in the $map_values array;
871
        if (count($map_values) !== 4) {
872
            throw new EE_Error(
873
                sprintf(
874
                    __(
875
                        'Incoming $map_values array should have a count of four values in it.  This is what was given: %s',
876
                        'event_espresso'
877
                    ),
878
                    '<br>' . print_r($map_values, true)
879
                )
880
            );
881
        }
882
        //set properties
883
        $this->_model = null;
884
        $this->_model_name = $map_values[0];
885
        $this->published_cap = (string)$map_values[1];
886
        $this->others_cap = (string)$map_values[2];
887
        $this->private_cap = (string)$map_values[3];
888
    }
889
890
    /**
891
     * Makes it so this object stops filtering caps
892
     */
893
    public function remove_filters()
894
    {
895
        remove_filter('map_meta_cap', array($this, 'map_meta_caps'), 10);
896
    }
897
898
899
    /**
900
     * This method ensures that the $model property is converted from the model name string to a proper EEM_Base class
901
     *
902
     * @since 4.5.0
903
     * @throws EE_Error
904
     *
905
     * @return void
906
     */
907
    public function ensure_is_model()
908
    {
909
        //is it already instantiated?
910
        if ($this->_model instanceof EEM_Base) {
911
            return;
912
        }
913
        //ensure model name is string
914
        $this->_model_name = (string)$this->_model_name;
915
        //error proof if the name has EEM in it
916
        $this->_model_name = str_replace('EEM', '', $this->_model_name);
917
        $this->_model = EE_Registry::instance()->load_model($this->_model_name);
918 View Code Duplication
        if (! $this->_model instanceof EEM_Base) {
919
            throw new EE_Error(
920
                sprintf(
921
                    __(
922
                        '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',
923
                        'event_espresso'
924
                    ),
925
                    get_class($this),
926
                    $this->_model
927
                )
928
            );
929
        }
930
    }
931
932
933
    /**
934
     *
935
     * @see   EE_Meta_Capability_Map::_map_meta_caps() for docs on params.
936
     * @since 4.6.x
937
     *
938
     * @param $caps
939
     * @param $cap
940
     * @param $user_id
941
     * @param $args
942
     *
943
     * @return array
944
     */
945
    public function map_meta_caps($caps, $cap, $user_id, $args)
946
    {
947
        return $this->_map_meta_caps($caps, $cap, $user_id, $args);
948
    }
949
950
951
    /**
952
     * This is the callback for the wp map_meta_caps() function which allows for ensuring certain caps that act as a
953
     * "meta" for other caps ( i.e. ee_edit_event is a meta for ee_edit_others_events ) work as expected.
954
     *
955
     * @since 4.5.0
956
     * @see   wp-includes/capabilities.php
957
     *
958
     * @param array  $caps    actual users capabilities
959
     * @param string $cap     initial capability name that is being checked (the "map" key)
960
     * @param int    $user_id The user id
961
     * @param array  $args    Adds context to the cap. Typically the object ID.
962
     *
963
     * @return array   actual users capabilities
964
     */
965
    abstract protected function _map_meta_caps($caps, $cap, $user_id, $args);
966
}
967
968
969
/**
970
 * Meta Capability Map class for Edit type capabilities.
971
 * Any capability that is an edit type of capability utilizes this map.
972
 *
973
 * @since      4.5.0
974
 * @package    Event Espresso
975
 * @subpackage core, capabilities
976
 * @author     Darren Ethier
977
 */
978
class EE_Meta_Capability_Map_Edit extends EE_Meta_Capability_Map
979
{
980
981
    /**
982
     * This is the callback for the wp map_meta_caps() function which allows for ensuring certain caps that act as a
983
     * "meta" for other caps ( i.e. ee_edit_event is a meta for ee_edit_others_events ) work as expected.
984
     *
985
     * @since 4.5.0
986
     * @see   wp-includes/capabilities.php
987
     *
988
     * @param array  $caps    actual users capabilities
989
     * @param string $cap     initial capability name that is being checked (the "map" key)
990
     * @param int    $user_id The user id
991
     * @param array  $args    Adds context to the cap. Typically the object ID.
992
     *
993
     * @return array   actual users capabilities
994
     */
995
    protected function _map_meta_caps($caps, $cap, $user_id, $args)
996
    {
997
        //only process if we're checking our mapped_cap
998
        if ($cap !== $this->meta_cap) {
999
            return $caps;
1000
        }
1001
1002
        //cast $user_id to int for later explicit comparisons
1003
        $user_id = (int) $user_id;
1004
1005
        /** @var EE_Base_Class $obj */
1006
        $obj = ! empty($args[0]) ? $this->_model->get_one_by_ID($args[0]) : null;
1007
        //if no obj then let's just do cap
1008
        if (! $obj instanceof EE_Base_Class) {
1009
            $caps[] = $cap;
1010
            return $caps;
1011
        }
1012
        if ($obj instanceof EE_CPT_Base) {
1013
            //if the item author is set and the user is the author...
1014
            if ($obj->wp_user() && $user_id === $obj->wp_user()) {
1015
                if (empty($this->published_cap)) {
1016
                    $caps[] = $cap;
1017
                } else {
1018
                    //if obj is published...
1019
                    if ($obj->status() === 'publish') {
1020
                        $caps[] = $this->published_cap;
1021
                    } else {
1022
                        $caps[] = $cap;
1023
                    }
1024
                }
1025
            } else {
1026
                //the user is trying to edit someone else's obj
1027
                if (! empty($this->others_cap)) {
1028
                    $caps[] = $this->others_cap;
1029
                }
1030
                if (! empty($this->published_cap) && $obj->status() === 'publish') {
1031
                    $caps[] = $this->published_cap;
1032
                } elseif (! empty($this->private_cap) && $obj->status() === 'private') {
1033
                    $caps[] = $this->private_cap;
1034
                }
1035
            }
1036
        } else {
1037
            //not a cpt object so handled differently
1038
            $has_cap = false;
1039
            try {
1040
                $has_cap = method_exists($obj, 'wp_user')
1041
                    && $obj->wp_user()
1042
                    && $obj->wp_user() === $user_id;
1043
            } catch (Exception $e) {
1044
                if (WP_DEBUG) {
1045
                    EE_Error::add_error($e->getMessage(), __FILE__, __FUNCTION__, __LINE__);
1046
                }
1047
            }
1048
            if ($has_cap) {
1049
                $caps[] = $cap;
1050
            } else {
1051
                if (! empty($this->others_cap)) {
1052
                    $caps[] = $this->others_cap;
1053
                }
1054
            }
1055
        }
1056
        return $caps;
1057
    }
1058
}
1059
1060
1061
/**
1062
 * Meta Capability Map class for delete type capabilities
1063
 * Merely extends the Edit map.  Intention is for type hinting so it's clear a capability is a "delete" type of
1064
 * capability (in case mapping needs to change in the future)
1065
 *
1066
 * @since      4.5.0
1067
 * @package    Event Espresso
1068
 * @subpackage core, capabilities
1069
 * @author     Darren Ethier
1070
 */
1071
class EE_Meta_Capability_Map_Delete extends EE_Meta_Capability_Map_Edit
1072
{
1073
1074
    /**
1075
     * This is the callback for the wp map_meta_caps() function which allows for ensuring certain caps that act as a
1076
     * "meta" for other caps ( i.e. ee_edit_event is a meta for ee_edit_others_events ) work as expected.
1077
     *
1078
     * @since 4.5.0
1079
     * @see   wp-includes/capabilities.php
1080
     *
1081
     * @param array  $caps    actual users capabilities
1082
     * @param string $cap     initial capability name that is being checked (the "map" key)
1083
     * @param int    $user_id The user id
1084
     * @param array  $args    Adds context to the cap. Typically the object ID.
1085
     *
1086
     * @return array   actual users capabilities
1087
     */
1088
    protected function _map_meta_caps($caps, $cap, $user_id, $args)
1089
    {
1090
        return parent::_map_meta_caps($caps, $cap, $user_id, $args);
1091
    }
1092
}
1093
1094
1095
/**
1096
 * Meta Capability Map class for reads.
1097
 * Maps any read meta capabilities to equivalents for context.
1098
 *
1099
 * @since      4.5.0
1100
 * @package    Event Espresso
1101
 * @subpackage core, capabilities
1102
 * @author     Darren Ethier
1103
 */
1104
class EE_Meta_Capability_Map_Read extends EE_Meta_Capability_Map
1105
{
1106
1107
    /**
1108
     * This is the callback for the wp map_meta_caps() function which allows for ensuring certain caps that act as a
1109
     * "meta" for other caps ( i.e. ee_edit_event is a meta for ee_edit_others_events ) work as expected.
1110
     *
1111
     * @since 4.5.0
1112
     * @see   wp-includes/capabilities.php
1113
     *
1114
     * @param array  $caps    actual users capabilities
1115
     * @param string $cap     initial capability name that is being checked (the "map" key)
1116
     * @param int    $user_id The user id
1117
     * @param array  $args    Adds context to the cap. Typically the object ID.
1118
     *
1119
     * @return array   actual users capabilities
1120
     */
1121
    protected function _map_meta_caps($caps, $cap, $user_id, $args)
1122
    {
1123
        //only process if we're checking our mapped cap;
1124
        if ($cap !== $this->meta_cap) {
1125
            return $caps;
1126
        }
1127
1128
        //cast $user_id to int for later explicit comparisons
1129
        $user_id = (int) $user_id;
1130
1131
        $obj = ! empty($args[0]) ? $this->_model->get_one_by_ID($args[0]) : null;
1132
        //if no obj then let's just do cap
1133
        if (! $obj instanceof EE_Base_Class) {
1134
            $caps[] = $cap;
1135
            return $caps;
1136
        }
1137
        if ($obj instanceof EE_CPT_Base) {
1138
            $status_obj = get_post_status_object($obj->status());
1139
            if ($status_obj->public) {
1140
                $caps[] = $cap;
1141
                return $caps;
1142
            }
1143
            //if the item author is set and the user is the author...
1144
            if ($obj->wp_user() && $obj->wp_user() === $user_id) {
1145
                $caps[] = $cap;
1146
            } elseif ($status_obj->private && ! empty($this->private_cap)) {
1147
                //the user is trying to view someone else's obj
1148
                $caps[] = $this->private_cap;
1149
            } elseif (! empty($this->others_cap)) {
1150
                $caps[] = $this->others_cap;
1151
            } else {
1152
                $caps[] = $cap;
1153
            }
1154
        } else {
1155
            //not a cpt object so handled differently
1156
            $has_cap = false;
1157
            try {
1158
                $has_cap = method_exists($obj, 'wp_user') && $obj->wp_user() && $obj->wp_user() === $user_id;
1159
            } catch (Exception $e) {
1160
                if (WP_DEBUG) {
1161
                    EE_Error::add_error($e->getMessage(), __FILE__, __FUNCTION__, __LINE__);
1162
                }
1163
            }
1164
            if ($has_cap) {
1165
                $caps[] = $cap;
1166
            } elseif (! empty($this->private_cap)) {
1167
                $caps[] = $this->private_cap;
1168
            } elseif (! empty($this->others_cap)) {
1169
                $caps[] = $this->others_cap;
1170
            } else {
1171
                $caps[] = $cap;
1172
            }
1173
        }
1174
        return $caps;
1175
    }
1176
}
1177
1178
1179
/**
1180
 * Meta Capability Map class for the messages component
1181
 * This is a special map due to messages having global and custom messages.  Only users with the edit_global_message
1182
 * capability should be able to do things with the global messages.
1183
 *
1184
 * @since      4.5.0
1185
 * @package    Event Espresso
1186
 * @subpackage core, capabilities
1187
 * @author     Darren Ethier
1188
 */
1189
class EE_Meta_Capability_Map_Messages_Cap extends EE_Meta_Capability_Map
1190
{
1191
1192
    /**
1193
     * This is the callback for the wp map_meta_caps() function which allows for ensuring certain caps that act as a
1194
     * "meta" for other caps ( i.e. ee_edit_event is a meta for ee_edit_others_events ) work as expected.
1195
     *
1196
     * @since 4.5.0
1197
     * @see   wp-includes/capabilities.php
1198
     *
1199
     * @param array  $caps    actual users capabilities
1200
     * @param string $cap     initial capability name that is being checked (the "map" key)
1201
     * @param int    $user_id The user id
1202
     * @param array  $args    Adds context to the cap. Typically the object ID.
1203
     *
1204
     * @return array   actual users capabilities
1205
     */
1206
    protected function _map_meta_caps($caps, $cap, $user_id, $args)
1207
    {
1208
        //only process if we're checking our mapped_cap
1209
        if ($cap !== $this->meta_cap) {
1210
            return $caps;
1211
        }
1212
1213
        //cast $user_id to int for later explicit comparisons
1214
        $user_id = (int) $user_id;
1215
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_Message_Template_Group) {
1219
            $caps[] = $cap;
1220
            return $caps;
1221
        }
1222
        $is_global = $obj->is_global();
1223
        if ($obj->wp_user() && $obj->wp_user() === $user_id) {
1224
            if ($is_global) {
1225
                $caps[] = $this->private_cap;
1226
            } else {
1227
                $caps[] = $cap;
1228
            }
1229
        } else {
1230
            if ($is_global) {
1231
                $caps[] = $this->private_cap;
1232
            } else {
1233
                $caps[] = $this->others_cap;
1234
            }
1235
        }
1236
        return $caps;
1237
    }
1238
}
1239
1240
1241
/**
1242
 * Meta Capability Map class for the registration form (questions and question groups) component
1243
 * This is a special map due to questions and question groups having special "system" data.  Only users with the
1244
 * edit_system_question or edit_system_question_group capability should be able to do things with the system data.
1245
 *
1246
 * @since      4.5.0
1247
 * @package    Event Espresso
1248
 * @subpackage core, capabilities
1249
 * @author     Darren Ethier
1250
 */
1251
class EE_Meta_Capability_Map_Registration_Form_Cap extends EE_Meta_Capability_Map
1252
{
1253
1254
    /**
1255
     * This is the callback for the wp map_meta_caps() function which allows for ensuring certain caps that act as a
1256
     * "meta" for other caps ( i.e. ee_edit_event is a meta for ee_edit_others_events ) work as expected.
1257
     *
1258
     * @since 4.5.0
1259
     * @see   wp-includes/capabilities.php
1260
     *
1261
     * @param array  $caps    actual users capabilities
1262
     * @param string $cap     initial capability name that is being checked (the "map" key)
1263
     * @param int    $user_id The user id
1264
     * @param array  $args    Adds context to the cap. Typically the object ID.
1265
     *
1266
     * @return array   actual users capabilities
1267
     */
1268
    protected function _map_meta_caps($caps, $cap, $user_id, $args)
1269
    {
1270
        //only process if we're checking our mapped_cap
1271
        if ($cap !== $this->meta_cap) {
1272
            return $caps;
1273
        }
1274
        $obj = ! empty($args[0]) ? $this->_model->get_one_by_ID($args[0]) : null;
1275
        //if no obj then let's just do cap
1276
        if (! $obj instanceof EE_Base_Class) {
1277
            $caps[] = $cap;
1278
            return $caps;
1279
        }
1280
        $is_system = $obj instanceof EE_Question_Group ? $obj->system_group() : false;
1281
        $is_system = $obj instanceof EE_Question ? $obj->is_system_question() : $is_system;
1282
        if ($is_system) {
1283
            $caps[] = $this->private_cap;
1284
        } else {
1285
            $caps[] = $cap;
1286
        }
1287
        return $caps;
1288
    }
1289
1290
1291
}
1292