Completed
Branch FET-10766-extract-activation-d... (2c1e01)
by
unknown
84:57 queued 73:57
created

EE_Capabilities::addCaps()   C

Complexity

Conditions 7
Paths 6

Size

Total Lines 32
Code Lines 19

Duplication

Lines 12
Ratio 37.5 %

Importance

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