Completed
Branch FET-8684-new-default-ee-role (134e3f)
by
unknown
34:19 queued 16:36
created

EE_Capabilities   B

Complexity

Total Complexity 36

Size/Duplication

Total Lines 693
Duplicated Lines 0 %

Coupling/Cohesion

Components 2
Dependencies 8

Importance

Changes 1
Bugs 0 Features 1
Metric Value
c 1
b 0
f 1
dl 0
loc 693
rs 8.8
wmc 36
lcom 2
cbo 8

14 Methods

Rating   Name   Duplication   Size   Complexity  
A instance() 0 7 2
A __construct() 0 2 1
A init_caps() 0 7 2
A _set_meta_caps() 0 11 3
B _get_default_meta_caps_array() 0 37 2
A map_meta_caps() 0 12 3
B _init_caps_map() 0 314 1
C init_role_caps() 0 22 8
A add_cap_to_role() 0 18 3
A remove_cap_from_role() 0 6 2
A current_user_can() 0 6 2
A user_can() 0 6 2
A current_user_can_for_blog() 0 8 2
A get_ee_capabilities() 0 7 3
1
<?php
2
3
/**
4
 * This file contains the code related to the capabilities system in Event Espresso.
5
 *
6
 * @since 4.5.0
7
 * @package Event Espresso
8
 * @subpackage core, capabilities
9
 */
10
if ( ! defined( 'EVENT_ESPRESSO_VERSION' ) ) {
11
	exit( 'No direct script access allowed' );
12
}
13
14
15
/**
16
 * This class contains all the code related to Event Espresso capabilities.
17
 * Assigned to the EE_Registry::instance()->CAP property.
18
 *
19
 * @link https://github.com/eventespresso/event-espresso-core/tree/master/docs/K--Capability-System
20
 *
21
 * @since 4.5.0
22
 * @package Event Espresso
23
 * @subpackage core, capabilities
24
 * @author Darren Ethier
25
 */
26
final class EE_Capabilities extends EE_Base {
27
28
29
	/**
30
	 * instance of EE_Capabilities object
31
	 *
32
	 * @var EE_Capabilities
33
	 */
34
	private static $_instance = null;
35
36
37
	/**
38
	 * This is a map of caps that correspond to a default WP_Role.
39
	 * Array is indexed by Role and values are ee capabilities.
40
	 *
41
	 * @since 4.5.0
42
	 *
43
	 * @var array
44
	 */
45
	private $_caps_map = array();
46
47
48
49
	/**
50
	 * This used to hold an array of EE_Meta_Capability_Map objects that define the granular capabilities mapped to for a user depending on context.
51
	 *
52
	 * @var EE_Meta_Capability_Map[]
53
	 */
54
	private $_meta_caps = array();
55
56
	/**
57
	 * the name of the wp option used to store caps previously initialized
58
	 */
59
	const option_name = 'ee_caps_initialized';
60
61
62
63
64
65
	/**
66
	 * singleton method used to instantiate class object
67
	 *
68
	 * @since 4.5.0
69
	 *
70
	 * @return EE_Capabilities
71
	 */
72
	public static function instance() {
73
		//check if instantiated, and if not do so.
74
		if ( ! self::$_instance instanceof EE_Capabilities ) {
75
			self::$_instance = new self();
76
		}
77
		return self::$_instance;
78
	}
79
80
81
82
	/**
83
	 * private constructor
84
	 *
85
	 * @since 4.5.0
86
	 *
87
	 * @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...
88
	 */
89
	private function __construct() {
90
	}
91
92
93
94
	/**
95
	 * This delays the initialization of the capabilities class until EE_System core is loaded and ready.
96
	 *
97
	 * @param bool $reset allows for resetting the default capabilities saved on roles.  Note that this doesn't actually REMOVE any capabilities from existing roles, it just resaves defaults roles and ensures that they are up to date.
98
	 *
99
	 *
100
	 * @since 4.5.0
101
	 * @return void
102
	 */
103
	public function init_caps( $reset = false ) {
104
		if ( EE_Maintenance_Mode::instance()->models_can_query() ){
105
			$this->_caps_map = $this->_init_caps_map();
106
			$this->init_role_caps( $reset );
107
			$this->_set_meta_caps();
108
		}
109
	}
110
111
112
113
114
	/**
115
	 * This sets the meta caps property.
116
117
	 * @since 4.5.0
118
	 *
119
	 * @return void
120
	 */
121
	private function _set_meta_caps() {
122
		//make sure we're only ever initializing the default _meta_caps array once if it's empty.
123
		$this->_meta_caps = $this->_get_default_meta_caps_array();
124
125
		$this->_meta_caps = apply_filters( 'FHEE__EE_Capabilities___set_meta_caps__meta_caps', $this->_meta_caps );
126
127
		//add filter for map_meta_caps but only if models can query.
128
		if ( EE_Maintenance_Mode::instance()->models_can_query() && ! has_filter( 'map_meta_cap', array( $this, 'map_meta_caps' ) ) ) {
129
			add_filter( 'map_meta_cap', array( $this, 'map_meta_caps' ), 10, 4 );
130
		}
131
	}
132
133
134
	/**
135
	 * This builds and returns the default meta_caps array only once.
136
	 *
137
	 * @since  4.8.28.rc.012
138
	 * @return array
139
	 */
140
	private function _get_default_meta_caps_array() {
141
		static $default_meta_caps = array();
142
		if ( empty( $default_meta_caps ) ) {
143
			$default_meta_caps = array(
144
				//edits
145
				new EE_Meta_Capability_Map_Edit( 'ee_edit_event', array( 'Event', 'ee_edit_published_events', 'ee_edit_others_events', 'ee_edit_private_events' ) ),
146
				new EE_Meta_Capability_Map_Edit( 'ee_edit_venue', array( 'Venue', 'ee_edit_published_venues', 'ee_edit_others_venues', 'ee_edit_private_venues' ) ),
147
				new EE_Meta_Capability_Map_Edit( 'ee_edit_registration', array( 'Registration', '', 'ee_edit_others_registrations', '' ) ),
148
				new EE_Meta_Capability_Map_Edit( 'ee_edit_checkin', array( 'Registration', '', 'ee_edit_others_checkins', '' ) ),
149
				new EE_Meta_Capability_Map_Messages_Cap( 'ee_edit_message', array( 'Message_Template_Group', '', 'ee_edit_others_messages', 'ee_edit_global_messages' ) ),
150
				new EE_Meta_Capability_Map_Edit( 'ee_edit_default_ticket', array( 'Ticket', '', 'ee_edit_others_default_tickets', '' ) ),
151
				new EE_Meta_Capability_Map_Registration_Form_Cap( 'ee_edit_question', array( 'Question', '', '', 'ee_edit_system_questions' ) ),
152
				new EE_Meta_Capability_Map_Registration_Form_Cap( 'ee_edit_question_group', array( 'Question_Group', '', '', 'ee_edit_system_question_groups' ) ),
153
				new EE_Meta_Capability_Map_Edit( 'ee_edit_payment_method', array( 'Payment_Method', '', 'ee_edit_others_payment_methods', '' ) ),
154
				//reads
155
				new EE_Meta_Capability_Map_Read( 'ee_read_event', array( 'Event', '', 'ee_read_others_events', 'ee_read_private_events' ) ),
156
				new EE_Meta_Capability_Map_Read( 'ee_read_venue', array( 'Venue', '', 'ee_read_others_venues', 'ee_read_private_venues' ) ),
157
				new EE_Meta_Capability_Map_Read( 'ee_read_registration', array( 'Registration', '', '', 'ee_edit_others_registrations' ) ),
158
				new EE_Meta_Capability_Map_Read( 'ee_read_checkin', array( 'Registration', '', '', 'ee_read_others_checkins' ) ),
159
				new EE_Meta_Capability_Map_Messages_Cap( 'ee_read_message', array( 'Message_Template_Group', '', 'ee_read_others_messages', 'ee_read_global_messages' ) ),
160
				new EE_Meta_Capability_Map_Read( 'ee_read_default_ticket', array( 'Ticket', '', '', 'ee_read_others_default_tickets' ) ),
161
				new EE_Meta_Capability_Map_Read( 'ee_read_payment_method', array( 'Payment_Method', '', '', 'ee_read_others_payment_methods' ) ),
162
163
				//deletes
164
				new EE_Meta_Capability_Map_Delete( 'ee_delete_event', array( 'Event', 'ee_delete_published_events', 'ee_delete_others_events', 'ee_delete_private_events' ) ),
165
				new EE_Meta_Capability_Map_Delete( 'ee_delete_venue', array( 'Venue', 'ee_delete_published_venues', 'ee_delete_others_venues', 'ee_delete_private_venues' ) ),
166
				new EE_Meta_Capability_Map_Delete( 'ee_delete_registration', array( 'Registration', '', 'ee_delete_others_registrations', '' ) ),
167
				new EE_Meta_Capability_Map_Delete( 'ee_delete_checkin', array( 'Registration', '', 'ee_delete_others_checkins', '' ) ),
168
				new EE_Meta_Capability_Map_Messages_Cap( 'ee_delete_message', array( 'Message_Template_Group', '', 'ee_delete_others_messages', 'ee_delete_global_messages' ) ),
169
				new EE_Meta_Capability_Map_Delete( 'ee_delete_default_ticket', array( 'Ticket', '', 'ee_delete_others_default_tickets', '' ) ),
170
				new EE_Meta_Capability_Map_Registration_Form_Cap( 'ee_delete_question', array( 'Question', '', '', 'delete_system_questions' ) ),
171
				new EE_Meta_Capability_Map_Registration_Form_Cap( 'ee_delete_question_group', array( 'Question_Group', '', '', 'delete_system_question_groups' ) ),
172
				new EE_Meta_Capability_Map_Delete( 'ee_delete_payment_method', array( 'Payment_Method', '', 'ee_delete_others_payment_methods', '' ) ),
173
			);
174
		}
175
		return $default_meta_caps;
176
	}
177
178
179
180
	/**
181
	 * This is the callback for the wp map_meta_caps() function which allows for ensuring certain caps that act as a
182
	 * "meta" for other caps ( i.e. ee_edit_event is a meta for ee_edit_others_events ) work as expected.
183
	 *
184
	 * The actual logic is carried out by implementer classes in their definition of _map_meta_caps.
185
	 *
186
	 * @since 4.5.0
187
	 * @see  wp-includes/capabilities.php
188
	 *
189
	 * @param array  $caps    actual users capabilities
190
	 * @param string $cap     initial capability name that is being checked (the "map" key)
191
	 * @param int    $user_id The user id
192
	 * @param array  $args    Adds context to the cap. Typically the object ID.
193
	 *
194
	 * @return array   actual users capabilities
195
	 */
196
	public function map_meta_caps( $caps, $cap, $user_id, $args ) {
197
		//loop through our _meta_caps array
198
		foreach ( $this->_meta_caps as $meta_map ) {
199
			if ( ! $meta_map instanceof EE_Meta_Capability_Map ) {
200
				continue;
201
			}
202
			$meta_map->ensure_is_model();
203
204
			$caps = $meta_map->map_meta_caps( $caps, $cap, $user_id, $args );
205
		}
206
		return $caps;
207
	}
208
209
210
211
212
	/**
213
	 * This sets up and returns the initial capabilities map for Event Espresso
214
	 *
215
	 * @since 4.5.0
216
	 *
217
	 * @return array
218
	 */
219
	private function _init_caps_map() {
220
		$caps = array(
221
			'administrator' => array(
222
			//basic access
223
				'ee_read_ee',
224
			//gateways
225
			/**
226
			 * note that with payment method capabilities, although we've implemented
227
			 * capability mapping which will be used for accessing payment methods owned by
228
			 * other users.  This is not fully implemented yet in the payment method ui.
229
			 * Currently only the "plural" caps are in active use. (Specific payment method caps are in use as well).
230
			**/
231
				'ee_manage_gateways',
232
				'ee_read_payment_method',
233
				'ee_read_payment_methods',
234
				'ee_read_others_payment_methods',
235
				'ee_edit_payment_method',
236
				'ee_edit_payment_methods',
237
				'ee_edit_others_payment_methods',
238
				'ee_delete_payment_method',
239
				'ee_delete_payment_methods',
240
			//events
241
				'ee_publish_events',
242
				'ee_read_private_events',
243
				'ee_read_others_events',
244
				'ee_read_event',
245
				'ee_read_events',
246
				'ee_edit_event',
247
				'ee_edit_events',
248
				'ee_edit_published_events',
249
				'ee_edit_others_events',
250
				'ee_edit_private_events',
251
				'ee_delete_published_events',
252
				'ee_delete_private_events',
253
				'ee_delete_event',
254
				'ee_delete_events',
255
				'ee_delete_others_events',
256
			//event categories
257
				'ee_manage_event_categories',
258
				'ee_edit_event_category',
259
				'ee_delete_event_category',
260
				'ee_assign_event_category',
261
			//venues
262
				'ee_publish_venues',
263
				'ee_read_venue',
264
				'ee_read_venues',
265
				'ee_read_others_venues',
266
				'ee_read_private_venues',
267
				'ee_edit_venue',
268
				'ee_edit_venues',
269
				'ee_edit_others_venues',
270
				'ee_edit_published_venues',
271
				'ee_edit_private_venues',
272
				'ee_delete_venue',
273
				'ee_delete_venues',
274
				'ee_delete_others_venues',
275
				'ee_delete_private_venues',
276
				'ee_delete_published_venues',
277
			//venue categories
278
				'ee_manage_venue_categories',
279
				'ee_edit_venue_category',
280
				'ee_delete_venue_category',
281
				'ee_assign_venue_category',
282
			//contacts
283
				'ee_read_contact',
284
				'ee_read_contacts',
285
				'ee_edit_contact',
286
				'ee_edit_contacts',
287
				'ee_delete_contact',
288
				'ee_delete_contacts',
289
			//registrations
290
				'ee_read_registration',
291
				'ee_read_registrations',
292
				'ee_read_others_registrations',
293
				'ee_edit_registration',
294
				'ee_edit_registrations',
295
				'ee_edit_others_registrations',
296
				'ee_delete_registration',
297
				'ee_delete_registrations',
298
			//checkins
299
				'ee_read_checkin',
300
				'ee_read_others_checkins',
301
				'ee_read_checkins',
302
				'ee_edit_checkin',
303
				'ee_edit_checkins',
304
				'ee_edit_others_checkins',
305
				'ee_delete_checkin',
306
				'ee_delete_checkins',
307
				'ee_delete_others_checkins',
308
			//transactions && payments
309
				'ee_read_transaction',
310
				'ee_read_transactions',
311
				'ee_edit_payments',
312
				'ee_delete_payments',
313
			//messages
314
				'ee_read_message',
315
				'ee_read_messages',
316
				'ee_read_others_messages',
317
				'ee_read_global_messages',
318
				'ee_edit_global_messages',
319
				'ee_edit_message',
320
				'ee_edit_messages',
321
				'ee_edit_others_messages',
322
				'ee_delete_message',
323
				'ee_delete_messages',
324
				'ee_delete_others_messages',
325
				'ee_delete_global_messages',
326
				'ee_send_message',
327
			//tickets
328
				'ee_read_default_ticket',
329
				'ee_read_default_tickets',
330
				'ee_read_others_default_tickets',
331
				'ee_edit_default_ticket',
332
				'ee_edit_default_tickets',
333
				'ee_edit_others_default_tickets',
334
				'ee_delete_default_ticket',
335
				'ee_delete_default_tickets',
336
				'ee_delete_others_default_tickets',
337
			//prices
338
				'ee_edit_default_price',
339
				'ee_edit_default_prices',
340
				'ee_delete_default_price',
341
				'ee_delete_default_prices',
342
				'ee_edit_default_price_type',
343
				'ee_edit_default_price_types',
344
				'ee_delete_default_price_type',
345
				'ee_delete_default_price_types',
346
				'ee_read_default_prices',
347
				'ee_read_default_price_types',
348
			//registration form
349
				'ee_edit_question',
350
				'ee_edit_questions',
351
				'ee_edit_system_questions',
352
				'ee_read_questions',
353
				'ee_delete_question',
354
				'ee_delete_questions',
355
				'ee_edit_question_group',
356
				'ee_edit_question_groups',
357
				'ee_read_question_groups',
358
				'ee_edit_system_question_groups',
359
				'ee_delete_question_group',
360
				'ee_delete_question_groups',
361
			//event_type taxonomy
362
				'ee_assign_event_type',
363
				'ee_manage_event_types',
364
				'ee_edit_event_type',
365
				'ee_delete_event_type',
366
				),
367
			'ee_events_administrator' => array(
368
			//core wp caps
369
				'read',
370
				'read_private_pages',
371
				'read_private_posts',
372
				'edit_users',
373
				'edit_posts',
374
				'edit_pages',
375
				'edit_published_posts',
376
				'edit_published_pages',
377
				'edit_private_pages',
378
				'edit_private_posts',
379
				'edit_others_posts',
380
				'edit_others_pages',
381
				'publish_posts',
382
				'publish_pages',
383
				'delete_posts',
384
				'delete_pages',
385
				'delete_private_pages',
386
				'delete_private_posts',
387
				'delete_published_pages',
388
				'delete_published_posts',
389
				'delete_others_posts',
390
				'delete_others_pages',
391
				'manage_categories',
392
				'manage_links',
393
				'moderate_comments',
394
				'unfiltered_html',
395
				'upload_files',
396
				'export',
397
				'import',
398
				'list_users',
399
			//basic ee access
400
				'ee_read_ee',
401
				//events
402
				'ee_publish_events',
403
				'ee_read_private_events',
404
				'ee_read_others_events',
405
				'ee_read_event',
406
				'ee_read_events',
407
				'ee_edit_event',
408
				'ee_edit_events',
409
				'ee_edit_published_events',
410
				'ee_edit_others_events',
411
				'ee_edit_private_events',
412
				'ee_delete_published_events',
413
				'ee_delete_private_events',
414
				'ee_delete_event',
415
				'ee_delete_events',
416
				'ee_delete_others_events',
417
				//event categories
418
				'ee_manage_event_categories',
419
				'ee_edit_event_category',
420
				'ee_delete_event_category',
421
				'ee_assign_event_category',
422
				//venues
423
				'ee_publish_venues',
424
				'ee_read_venue',
425
				'ee_read_venues',
426
				'ee_read_others_venues',
427
				'ee_read_private_venues',
428
				'ee_edit_venue',
429
				'ee_edit_venues',
430
				'ee_edit_others_venues',
431
				'ee_edit_published_venues',
432
				'ee_edit_private_venues',
433
				'ee_delete_venue',
434
				'ee_delete_venues',
435
				'ee_delete_others_venues',
436
				'ee_delete_private_venues',
437
				'ee_delete_published_venues',
438
				//venue categories
439
				'ee_manage_venue_categories',
440
				'ee_edit_venue_category',
441
				'ee_delete_venue_category',
442
				'ee_assign_venue_category',
443
				//contacts
444
				'ee_read_contact',
445
				'ee_read_contacts',
446
				'ee_edit_contact',
447
				'ee_edit_contacts',
448
				'ee_delete_contact',
449
				'ee_delete_contacts',
450
				//registrations
451
				'ee_read_registration',
452
				'ee_read_registrations',
453
				'ee_read_others_registrations',
454
				'ee_edit_registration',
455
				'ee_edit_registrations',
456
				'ee_edit_others_registrations',
457
				'ee_delete_registration',
458
				'ee_delete_registrations',
459
				//checkins
460
				'ee_read_checkin',
461
				'ee_read_others_checkins',
462
				'ee_read_checkins',
463
				'ee_edit_checkin',
464
				'ee_edit_checkins',
465
				'ee_edit_others_checkins',
466
				'ee_delete_checkin',
467
				'ee_delete_checkins',
468
				'ee_delete_others_checkins',
469
				//transactions && payments
470
				'ee_read_transaction',
471
				'ee_read_transactions',
472
				'ee_edit_payments',
473
				'ee_delete_payments',
474
				//messages
475
				'ee_read_message',
476
				'ee_read_messages',
477
				'ee_read_others_messages',
478
				'ee_read_global_messages',
479
				'ee_edit_global_messages',
480
				'ee_edit_message',
481
				'ee_edit_messages',
482
				'ee_edit_others_messages',
483
				'ee_delete_message',
484
				'ee_delete_messages',
485
				'ee_delete_others_messages',
486
				'ee_delete_global_messages',
487
				'ee_send_message',
488
				//tickets
489
				'ee_read_default_ticket',
490
				'ee_read_default_tickets',
491
				'ee_read_others_default_tickets',
492
				'ee_edit_default_ticket',
493
				'ee_edit_default_tickets',
494
				'ee_edit_others_default_tickets',
495
				'ee_delete_default_ticket',
496
				'ee_delete_default_tickets',
497
				'ee_delete_others_default_tickets',
498
				//prices
499
				'ee_edit_default_price',
500
				'ee_edit_default_prices',
501
				'ee_delete_default_price',
502
				'ee_delete_default_prices',
503
				'ee_edit_default_price_type',
504
				'ee_edit_default_price_types',
505
				'ee_delete_default_price_type',
506
				'ee_delete_default_price_types',
507
				'ee_read_default_prices',
508
				'ee_read_default_price_types',
509
				//registration form
510
				'ee_edit_question',
511
				'ee_edit_questions',
512
				'ee_edit_system_questions',
513
				'ee_read_questions',
514
				'ee_delete_question',
515
				'ee_delete_questions',
516
				'ee_edit_question_group',
517
				'ee_edit_question_groups',
518
				'ee_read_question_groups',
519
				'ee_edit_system_question_groups',
520
				'ee_delete_question_group',
521
				'ee_delete_question_groups',
522
				//event_type taxonomy
523
				'ee_assign_event_type',
524
				'ee_manage_event_types',
525
				'ee_edit_event_type',
526
				'ee_delete_event_type',
527
			)
528
		);
529
530
		$caps = apply_filters( 'FHEE__EE_Capabilities__init_caps_map__caps', $caps );
531
		return $caps;
532
	}
533
534
535
536
537
	/**
538
	 * This adds all the default caps to roles as registered in the _caps_map property.
539
	 *
540
	 * @since 4.5.0
541
	 *
542
	 * @param bool $reset allows for resetting the default capabilities saved on roles.  Note that this doesn't actually REMOVE any capabilities from existing roles, it just resaves defaults roles and ensures that they are up to date.
543
	 * @param array $custom_map Optional.  Can be used to send a custom map of roles and capabilities for setting them up.  Note that this should ONLY be called on activation hook or some other one-time task otherwise the caps will be added on every request.
544
	 *
545
	 * @return void
546
	 */
547
	public function init_role_caps( $reset = false, $custom_map = array() ) {
548
549
		$caps_map = empty( $custom_map ) ? $this->_caps_map : $custom_map;
550
551
		//first let's determine if these caps have already been set.
552
		$caps_set_before = get_option( self::option_name, array() );
553
		//if not reset, see what caps are new for each role. if they're new, add them.
554
		foreach ( $caps_map as $role => $caps_for_role ) {
555
			foreach ( $caps_for_role as $cap ) {
556
				//first check we haven't already added this cap before, or it's a reset
557
				if ( $reset || ! isset( $caps_set_before[ $role ] ) || ! in_array( $cap, $caps_set_before[ $role ] ) ) {
558
					if ( $this->add_cap_to_role( $role, $cap ) ) {
559
						$caps_set_before[ $role ][] = $cap;
560
					}
561
				}
562
			}
563
		}
564
565
		//now let's just save the cap that has been set.
566
		update_option( self::option_name, $caps_set_before );
567
		do_action( 'AHEE__EE_Capabilities__init_role_caps__complete', $caps_set_before );
568
	}
569
570
571
572
573
	/**
574
	 * This method sets a capability on a role.  Note this should only be done on activation, or if you have something specific to prevent the cap from being added on every page load (adding caps are persistent to the db).
575
	 * Note. this is a wrapper for $wp_role->add_cap()
576
	 *
577
	 * @see wp-includes/capabilities.php
578
	 *
579
	 * @since 4.5.0
580
	 *
581
	 * @param string $role  A WordPress role the capability is being added to
582
	 * @param string $cap   The capability being added to the role
583
	 * @param bool $grant  Whether to grant access to this cap on this role.
584
	 * @return bool
585
	 */
586
	public function add_cap_to_role( $role, $cap, $grant = true ) {
587
		$role_object = get_role( $role );
588
		//if the role isn't available then we create it.
589
		if ( ! $role_object instanceof WP_Role ) {
0 ignored issues
show
Bug introduced by
The class WP_Role does not exist. Did you forget a USE statement, or did you not list all dependencies?

This error could be the result of:

1. Missing dependencies

PHP Analyzer uses your composer.json file (if available) to determine the dependencies of your project and to determine all the available classes and functions. It expects the composer.json to be in the root folder of your repository.

Are you sure this class is defined by one of your dependencies, or did you maybe not list a dependency in either the require or require-dev section?

2. Missing use statement

PHP does not complain about undefined classes in ìnstanceof checks. For example, the following PHP code will work perfectly fine:

if ($x instanceof DoesNotExist) {
    // Do something.
}

If you have not tested against this specific condition, such errors might go unnoticed.

Loading history...
590
			//if a plugin wants to create a specific role name then they should create the role before
591
			//EE_Capabilities does.  Otherwise this function will create the role name from the slug:
592
			// - removes any `ee_` namespacing from the start of the slug.
593
			// - replaces `_` with ` ` (empty space).
594
			// - sentence case on the resulting string.
595
			$role_label = ucwords( str_replace( '_', ' ', str_replace( 'ee_', '', $role ) ) );
596
			$role_object = add_role( $role, $role_label );
597
		}
598
		if ( $role_object instanceof WP_Role ) {
0 ignored issues
show
Bug introduced by
The class WP_Role does not exist. Did you forget a USE statement, or did you not list all dependencies?

This error could be the result of:

1. Missing dependencies

PHP Analyzer uses your composer.json file (if available) to determine the dependencies of your project and to determine all the available classes and functions. It expects the composer.json to be in the root folder of your repository.

Are you sure this class is defined by one of your dependencies, or did you maybe not list a dependency in either the require or require-dev section?

2. Missing use statement

PHP does not complain about undefined classes in ìnstanceof checks. For example, the following PHP code will work perfectly fine:

if ($x instanceof DoesNotExist) {
    // Do something.
}

If you have not tested against this specific condition, such errors might go unnoticed.

Loading history...
599
			$role_object->add_cap( $cap, $grant );
600
			return true;
601
		}
602
		return false;
603
	}
604
605
606
607
608
609
	/**
610
	 * Functions similarly to add_cap_to_role except removes cap from given role.
611
	 * Wrapper for $wp_role->remove_cap()
612
	 *
613
	 * @see wp-includes/capabilities.php
614
	 * @since 4.5.0
615
	 *
616
	 * @param string $role A WordPress role the capability is being removed from.
617
	 * @param string $cap  The capability being removed
618
	 *
619
	 * @return void
620
	 */
621
	public function remove_cap_from_role( $role, $cap ) {
622
		$role = get_role( $role );
623
		if ( $role instanceof WP_Role ) {
0 ignored issues
show
Bug introduced by
The class WP_Role does not exist. Did you forget a USE statement, or did you not list all dependencies?

This error could be the result of:

1. Missing dependencies

PHP Analyzer uses your composer.json file (if available) to determine the dependencies of your project and to determine all the available classes and functions. It expects the composer.json to be in the root folder of your repository.

Are you sure this class is defined by one of your dependencies, or did you maybe not list a dependency in either the require or require-dev section?

2. Missing use statement

PHP does not complain about undefined classes in ìnstanceof checks. For example, the following PHP code will work perfectly fine:

if ($x instanceof DoesNotExist) {
    // Do something.
}

If you have not tested against this specific condition, such errors might go unnoticed.

Loading history...
624
			$role->remove_cap( $cap );
625
		}
626
	}
627
628
629
630
631
	/**
632
	 * Wrapper for the native WP current_user_can() method.
633
	 * This is provided as a handy method for a couple things:
634
	 * 1. Using the context string it allows for targeted filtering by addons for a specific check (without having to write those filters wherever current_user_can is called).
635
	 * 2. Explicit passing of $id from a given context ( useful in the cases of map_meta_cap filters )
636
	 *
637
	 * @since 4.5.0
638
	 *
639
	 * @param string $cap     The cap being checked.
640
	 * @param string $context The context where the current_user_can is being called from.
641
	 * @param int    $id          Optional. Id for item where current_user_can is being called from (used in map_meta_cap() filters.
642
	 *
643
	 * @return bool  Whether user can or not.
644
	 */
645
	public function current_user_can( $cap, $context, $id = 0 ) {
646
		//apply filters (both a global on just the cap, and context specific.  Global overrides context specific)
647
		$filtered_cap = apply_filters( 'FHEE__EE_Capabilities__current_user_can__cap__' . $context,  $cap, $id );
648
		$filtered_cap = apply_filters( 'FHEE__EE_Capabilities__current_user_can__cap', $filtered_cap, $context, $cap, $id );
649
		return ! empty( $id ) ? current_user_can( $filtered_cap, $id ) : current_user_can( $filtered_cap );
650
	}
651
652
653
654
655
656
	/**
657
	 * This is a wrapper for the WP user_can() function and follows the same style as the other wrappers in this class.
658
	 *
659
	 * @param int|WP_User $user    Either the user_id or a WP_User object
660
	 * @param string $cap     The capability string being checked
661
	 * @param string $context The context where the user_can is being called from (used in filters).
662
	 * @param int    $id      Optional. Id for item where user_can is being called from ( used in map_meta_cap() filters)
663
	 *
664
	 * @return bool Whether user can or not.
665
	 */
666
	public function user_can( $user, $cap, $context, $id = 0 ) {
667
		//apply filters (both a global on just the cap, and context specific.  Global overrides context specific)
668
		$filtered_cap = apply_filters( 'FHEE__EE_Capabilities__user_can__cap__' . $context, $cap, $user, $id );
669
		$filtered_cap = apply_filters( 'FHEE__EE_Capabilities__user_can__cap', $filtered_cap, $context, $cap, $user,  $id );
670
		return ! empty( $id ) ? user_can( $user, $filtered_cap, $id ) : user_can( $user, $filtered_cap );
671
	}
672
673
674
675
	/**
676
	 * Wrapper for the native WP current_user_can_for_blog() method.
677
	 * This is provided as a handy method for a couple things:
678
	 * 1. Using the context string it allows for targeted filtering by addons for a specific check (without having to write those filters wherever current_user_can is called).
679
	 * 2. Explicit passing of $id from a given context ( useful in the cases of map_meta_cap filters )
680
	 *
681
	 * @since 4.5.0
682
	 *
683
	 * @param int      $blog_id The blog id that is being checked for.
684
	 * @param string $cap     The cap being checked.
685
	 * @param string $context The context where the current_user_can is being called from.
686
	 * @param int    $id          Optional. Id for item where current_user_can is being called from (used in map_meta_cap() filters.
687
	 *
688
	 * @return bool  Whether user can or not.
689
	 */
690
	public function current_user_can_for_blog( $blog_id, $cap, $context, $id = 0 ) {
691
		$user_can = ! empty( $id ) ? current_user_can_for_blog( $blog_id, $cap, $id ) : current_user_can( $blog_id, $cap );
692
693
		//apply filters (both a global on just the cap, and context specific.  Global overrides context specific)
694
		$user_can = apply_filters( 'FHEE__EE_Capabilities__current_user_can_for_blog__user_can__' . $context, $user_can, $blog_id, $cap, $id );
695
		$user_can = apply_filters( 'FHEE__EE_Capabilities__current_user_can_for_blog__user_can', $user_can, $context, $blog_id, $cap, $id );
696
		return $user_can;
697
	}
698
699
700
701
	/**
702
	 * This helper method just returns an array of registered EE capabilities.
703
	 * Note this array is filtered.  It is assumed that all available EE capabilities are assigned to the administrator role.
704
	 *
705
	 * @since 4.5.0
706
	 *
707
	 * @param string $role  If empty then the entire role/capability map is returned.  Otherwise just the capabilities for the given role are returned.
708
	 *
709
	 * @return array
710
	 */
711
	public function get_ee_capabilities( $role = 'administrator' ) {
712
		$capabilities = $this->_init_caps_map();
713
		if ( empty( $role ) ) {
714
			return $capabilities;
715
		}
716
		return isset( $capabilities[ $role ] ) ? $capabilities[ $role ] : array();
717
	}
718
}
719
720
721
722
723
/**
724
 * Meta Capability Map class.
725
 * This children of this class are used to define capability mappings for capabilities that have further filtering depending on context.
726
 *
727
 * @since 4.5.0
728
 * @package Event Espresso
729
 * @subpackage core, capabilities
730
 * @author  Darren Ethier
731
 */
732
abstract class EE_Meta_Capability_Map {
733
	public $meta_cap;
734
	/**
735
	 * @var EEM_Base
736
	 */
737
	protected $_model;
738
	protected $_model_name;
739
	public $published_cap = '';
740
	public $others_cap = '';
741
	public $private_cap = '';
742
743
744
745
	/**
746
	 * constructor.
747
	 * Receives the setup arguments for the map.
748
	 *
749
	 * @since    4.5.0
750
	 *
751
	 * @param string $meta_cap     What meta capability is this mapping.
752
	 * @param array  $map_values   array {
753
	 * 		//array of values that MUST match a count of 4.  It's okay to send an empty string for capabilities that don't get mapped to.
754
	 * 		@type $map_values[0] string A string representing the model name. Required.  String's
755
	 * 		      	    	       should always be used when Menu Maps are registered via the
756
	 * 		      	    	       plugin API as models are not allowed to be instantiated when
757
	 * 		      	    	       in maintenance mode 2 (migrations).
758
	 * 		@type $map_values[1] string represents the capability used for published. Optional.
759
	 * 		@type $map_values[2] string represents the capability used for "others". Optional.
760
	 * 		@type $map_values[3] string represents the capability used for private. Optional.
761
	 * 	}
762
	 * @throws EE_Error
763
	 */
764
	public function __construct( $meta_cap, $map_values ) {
765
		$this->meta_cap = $meta_cap;
766
		//verify there are four args in the $map_values array;
767
		if ( count( $map_values ) !== 4 ) {
768
			throw new EE_Error( sprintf( __( 'Incoming $map_values array should have a count of four values in it.  This is what was given: %s', 'event_espresso' ), '<br>' . print_r( $map_values, true ) ) );
769
		}
770
771
		//set properties
772
		$this->_model = null;
773
		$this->_model_name = $map_values[0];
774
		$this->published_cap = (string) $map_values[1];
775
		$this->others_cap = (string) $map_values[2];
776
		$this->private_cap = (string) $map_values[3];
777
	}
778
779
	/**
780
	 * Makes it so this object stops filtering caps
781
	 */
782
	public function remove_filters(){
783
		remove_filter( 'map_meta_cap', array( $this, 'map_meta_caps' ), 10 );
784
	}
785
786
787
788
	/**
789
	 * This method ensures that the $model property is converted from the model name string to a proper EEM_Base class
790
	 *
791
	 * @since 4.5.0
792
	 * @throws EE_Error
793
	 *
794
	 * @return void
795
	 */
796
	public function ensure_is_model() {
797
		//is it already instantiated?
798
		if ( $this->_model instanceof EEM_Base ) {
799
			return;
800
		}
801
802
		//ensure model name is string
803
		$this->_model_name = (string) $this->_model_name;
804
		//error proof if the name has EEM in it
805
		$this->_model_name = str_replace( 'EEM', '', $this->_model_name );
806
807
		$this->_model = EE_Registry::instance()->load_model( $this->_model_name );
808
809 View Code Duplication
		if ( ! $this->_model instanceof EEM_Base ) {
810
			throw new EE_Error( sprintf( __( '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', 'event_espresso' ), get_class( $this ), $this->_model ) );
811
		}
812
	}
813
814
815
	/**
816
	 *
817
	 * @see EE_Meta_Capability_Map::_map_meta_caps() for docs on params.
818
	 * @since 4.6.x
819
	 * @param $caps
820
	 * @param $cap
821
	 * @param $user_id
822
	 * @param $args
823
	 *
824
	 * @return array
825
	 */
826
	public function map_meta_caps( $caps, $cap, $user_id, $args ) {
827
		return $this->_map_meta_caps( $caps, $cap, $user_id, $args );
828
	}
829
830
831
832
	/**
833
	 * This is the callback for the wp map_meta_caps() function which allows for ensuring certain caps that act as a "meta" for other caps ( i.e. ee_edit_event is a meta for ee_edit_others_events ) work as expected.
834
	 *
835
	 * @since 4.5.0
836
	 * @see  wp-includes/capabilities.php
837
	 *
838
	 * @param array  $caps    actual users capabilities
839
	 * @param string $cap     initial capability name that is being checked (the "map" key)
840
	 * @param int     $user_id The user id
841
	 * @param array  $args    Adds context to the cap. Typically the object ID.
842
	 *
843
	 * @return array   actual users capabilities
844
	 */
845
	abstract protected function _map_meta_caps( $caps, $cap, $user_id, $args );
846
}
847
848
849
850
851
852
853
/**
854
 * Meta Capability Map class for Edit type capabilities.
855
 * Any capability that is an edit type of capability utilizes this map.
856
 *
857
 * @since 4.5.0
858
 * @package Event Espresso
859
 * @subpackage core, capabilities
860
 * @author  Darren Ethier
861
 */
862
class EE_Meta_Capability_Map_Edit extends EE_Meta_Capability_Map {
863
864
	/**
865
	 * This is the callback for the wp map_meta_caps() function which allows for ensuring certain caps that act as a "meta" for other caps ( i.e. ee_edit_event is a meta for ee_edit_others_events ) work as expected.
866
	 *
867
	 * @since 4.5.0
868
	 * @see  wp-includes/capabilities.php
869
	 *
870
	 * @param array  $caps    actual users capabilities
871
	 * @param string $cap     initial capability name that is being checked (the "map" key)
872
	 * @param int     $user_id The user id
873
	 * @param array  $args    Adds context to the cap. Typically the object ID.
874
	 *
875
	 * @return array   actual users capabilities
876
	 */
877
	protected function _map_meta_caps( $caps, $cap, $user_id, $args ) {
878
		//only process if we're checking our mapped_cap
879
		if ( $cap !== $this->meta_cap ) {
880
			return $caps;
881
		}
882
883
		$obj = ! empty( $args[0] ) ? $this->_model->get_one_by_ID( $args[0] ) : null;
884
885
		//if no obj then let's just do cap
886
		if ( ! $obj instanceof EE_Base_Class ) {
887
			$caps[] = $cap;
888
			return $caps;
889
		}
890
891
		if ( $obj instanceof EE_CPT_Base ) {
892
			//if the item author is set and the user is the author...
893
			if ( $obj->wp_user() && $user_id == $obj->wp_user() ) {
894
				if ( empty( $this->published_cap ) ) {
895
					$caps[] = $cap;
896
				} else {
897
					//if obj is published...
898
					if ( $obj->status() == 'publish' ) {
899
						$caps[] = $this->published_cap;
900
					} else {
901
						$caps[] = $cap;
902
					}
903
				}
904
			} else {
905
				//the user is trying to edit someone else's obj
906
				if ( ! empty( $this->others_cap ) ) {
907
					$caps[] = $this->others_cap;
908
				}
909
				if ( ! empty( $this->published_cap ) && $obj->status() == 'publish' ) {
910
					$caps[] = $this->published_cap;
911
				} elseif ( ! empty( $this->private_cap ) && $obj->status() == 'private' ) {
912
					$caps[] = $this->private_cap;
913
				}
914
			}
915
		} else {
916
			//not a cpt object so handled differently
917
			if ( method_exists( $obj, 'wp_user' ) && $obj->wp_user() && $user_id == $obj->wp_user() ) {
0 ignored issues
show
Documentation Bug introduced by
The method wp_user does not exist on object<EE_Base_Class>? Since you implemented __call, maybe consider adding a @method annotation.

If you implement __call and you know which methods are available, you can improve IDE auto-completion and static analysis by adding a @method annotation to the class.

This is often the case, when __call is implemented by a parent class and only the child class knows which methods exist:

class ParentClass {
    private $data = array();

    public function __call($method, array $args) {
        if (0 === strpos($method, 'get')) {
            return $this->data[strtolower(substr($method, 3))];
        }

        throw new \LogicException(sprintf('Unsupported method: %s', $method));
    }
}

/**
 * If this class knows which fields exist, you can specify the methods here:
 *
 * @method string getName()
 */
class SomeClass extends ParentClass { }
Loading history...
918
				$caps[] = $cap;
919
			} else {
920
				if ( ! empty( $this->others_cap ) ) {
921
					$caps[] = $this->others_cap;
922
				}
923
			}
924
		}
925
		return $caps;
926
	}
927
}
928
929
930
931
932
933
/**
934
 * Meta Capability Map class for delete type capabilities
935
 * Merely extends the Edit map.  Intention is for type hinting so it's clear a capability is a "delete" type of capability (in case mapping needs to change in the future)
936
 *
937
 * @since 4.5.0
938
 * @package Event Espresso
939
 * @subpackage core, capabilities
940
 * @author  Darren Ethier
941
 */
942
class EE_Meta_Capability_Map_Delete extends EE_Meta_Capability_Map_Edit {
943
944
	/**
945
	 * This is the callback for the wp map_meta_caps() function which allows for ensuring certain caps that act as a "meta" for other caps ( i.e. ee_edit_event is a meta for ee_edit_others_events ) work as expected.
946
	 *
947
	 * @since 4.5.0
948
	 * @see  wp-includes/capabilities.php
949
	 *
950
	 * @param array  $caps    actual users capabilities
951
	 * @param string $cap     initial capability name that is being checked (the "map" key)
952
	 * @param int     $user_id The user id
953
	 * @param array  $args    Adds context to the cap. Typically the object ID.
954
	 *
955
	 * @return array   actual users capabilities
956
	 */
957
	protected function _map_meta_caps( $caps, $cap, $user_id, $args ) {
958
		return parent::_map_meta_caps( $caps, $cap, $user_id, $args );
959
	}
960
}
961
962
963
964
965
966
/**
967
 * Meta Capability Map class for reads.
968
 * Maps any read meta capabilities to equivalents for context.
969
 *
970
 * @since 4.5.0
971
 * @package Event Espresso
972
 * @subpackage core, capabilities
973
 * @author  Darren Ethier
974
 */
975
class EE_Meta_Capability_Map_Read extends EE_Meta_Capability_Map {
976
977
	/**
978
	 * This is the callback for the wp map_meta_caps() function which allows for ensuring certain caps that act as a "meta" for other caps ( i.e. ee_edit_event is a meta for ee_edit_others_events ) work as expected.
979
	 *
980
	 * @since 4.5.0
981
	 * @see  wp-includes/capabilities.php
982
	 *
983
	 * @param array  $caps    actual users capabilities
984
	 * @param string $cap     initial capability name that is being checked (the "map" key)
985
	 * @param int     $user_id The user id
986
	 * @param array  $args    Adds context to the cap. Typically the object ID.
987
	 *
988
	 * @return array   actual users capabilities
989
	 */
990
	protected function _map_meta_caps( $caps, $cap, $user_id, $args ) {
991
		//only process if we're checking our mapped cap;
992
		if ( $cap !== $this->meta_cap ) {
993
			return $caps;
994
		}
995
996
		$obj = ! empty( $args[0] ) ? $this->_model->get_one_by_ID( $args[0] ) : null;
997
998
		//if no obj then let's just do cap
999
		if ( ! $obj instanceof EE_Base_Class ) {
1000
			$caps[] = $cap;
1001
			return $caps;
1002
		}
1003
1004
		if ( $obj instanceof EE_CPT_Base ) {
1005
			$status_obj = get_post_status_object( $obj->status() );
1006
			if ( $status_obj->public ) {
1007
				$caps[] = $cap;
1008
				return $caps;
1009
			}
1010
1011
			//if the item author is set and the user is the author...
1012 View Code Duplication
			if ( $obj->wp_user() && $user_id == $obj->wp_user() ) {
1013
				$caps[] = $cap;
1014
			} elseif ( $status_obj->private && ! empty( $this->private_cap ) ) {
1015
				//the user is trying to view someone else's obj
1016
				$caps[] = $this->private_cap;
1017
			} elseif ( ! empty( $this->others_cap ) ) {
1018
				$caps[] = $this->others_cap;
1019
			} else {
1020
				$caps[] = $cap;
1021
			}
1022 View Code Duplication
		} else {
1023
			//not a cpt object so handled differently
1024
			if ( method_exists( $obj, 'wp_user' ) && $obj->wp_user() && $user_id == $obj->wp_user() ) {
0 ignored issues
show
Documentation Bug introduced by
The method wp_user does not exist on object<EE_Base_Class>? Since you implemented __call, maybe consider adding a @method annotation.

If you implement __call and you know which methods are available, you can improve IDE auto-completion and static analysis by adding a @method annotation to the class.

This is often the case, when __call is implemented by a parent class and only the child class knows which methods exist:

class ParentClass {
    private $data = array();

    public function __call($method, array $args) {
        if (0 === strpos($method, 'get')) {
            return $this->data[strtolower(substr($method, 3))];
        }

        throw new \LogicException(sprintf('Unsupported method: %s', $method));
    }
}

/**
 * If this class knows which fields exist, you can specify the methods here:
 *
 * @method string getName()
 */
class SomeClass extends ParentClass { }
Loading history...
1025
				$caps[] = $cap;
1026
			} elseif ( ! empty( $this->private_cap ) ) {
1027
				$caps[] = $this->private_cap;
1028
			} elseif ( ! empty( $this->others_cap ) ) {
1029
				$caps[] = $this->others_cap;
1030
			} else {
1031
				$caps[] = $cap;
1032
			}
1033
		}
1034
		return $caps;
1035
	}
1036
}
1037
1038
1039
1040
1041
/**
1042
 * Meta Capability Map class for the messages component
1043
 * This is a special map due to messages having global and custom messages.  Only users with the edit_global_message capability should be able to do things with the global messages.
1044
 *
1045
 * @since 4.5.0
1046
 * @package Event Espresso
1047
 * @subpackage core, capabilities
1048
 * @author  Darren Ethier
1049
 */
1050
class EE_Meta_Capability_Map_Messages_Cap extends EE_Meta_Capability_Map {
1051
1052
	/**
1053
	 * This is the callback for the wp map_meta_caps() function which allows for ensuring certain caps that act as a "meta" for other caps ( i.e. ee_edit_event is a meta for ee_edit_others_events ) work as expected.
1054
	 *
1055
	 * @since 4.5.0
1056
	 * @see  wp-includes/capabilities.php
1057
	 *
1058
	 * @param array  $caps    actual users capabilities
1059
	 * @param string $cap     initial capability name that is being checked (the "map" key)
1060
	 * @param int     $user_id The user id
1061
	 * @param array  $args    Adds context to the cap. Typically the object ID.
1062
	 *
1063
	 * @return array   actual users capabilities
1064
	 */
1065
	protected function _map_meta_caps( $caps, $cap, $user_id, $args ) {
1066
		//only process if we're checking our mapped_cap
1067
		if ( $cap !== $this->meta_cap ) {
1068
			return $caps;
1069
		}
1070
1071
		$obj = ! empty( $args[0] ) ? $this->_model->get_one_by_ID( $args[0] ) : null;
1072
1073
		//if no obj then let's just do cap
1074
		if ( ! $obj instanceof EE_Message_Template_Group ) {
1075
			$caps[] = $cap;
1076
			return $caps;
1077
		}
1078
1079
		$is_global = $obj->is_global();
1080
1081
		if ( $obj->wp_user() && $user_id == $obj->wp_user() ) {
1082
			if ( $is_global ) {
1083
				$caps[]  = $this->private_cap;
1084
			} else {
1085
				$caps[] = $cap;
1086
			}
1087
		} else {
1088
			if ( $is_global ) {
1089
				$caps[] = $this->private_cap;
1090
			} else {
1091
				$caps[] = $this->others_cap;
1092
			}
1093
		}
1094
1095
		return $caps;
1096
	}
1097
}
1098
1099
1100
1101
1102
/**
1103
 * Meta Capability Map class for the registration form (questions and question groups) component
1104
 * This is a special map due to questions and question groups having special "system" data.  Only users with the edit_system_question or edit_system_question_group capability should be able to do things with the system data.
1105
 *
1106
 * @since 4.5.0
1107
 * @package Event Espresso
1108
 * @subpackage core, capabilities
1109
 * @author  Darren Ethier
1110
 */
1111
class EE_Meta_Capability_Map_Registration_Form_Cap extends EE_Meta_Capability_Map {
1112
1113
	/**
1114
	 * This is the callback for the wp map_meta_caps() function which allows for ensuring certain caps that act as a "meta" for other caps ( i.e. ee_edit_event is a meta for ee_edit_others_events ) work as expected.
1115
	 *
1116
	 * @since 4.5.0
1117
	 * @see  wp-includes/capabilities.php
1118
	 *
1119
	 * @param array  $caps    actual users capabilities
1120
	 * @param string $cap     initial capability name that is being checked (the "map" key)
1121
	 * @param int     $user_id The user id
1122
	 * @param array  $args    Adds context to the cap. Typically the object ID.
1123
	 *
1124
	 * @return array   actual users capabilities
1125
	 */
1126
	protected function _map_meta_caps( $caps, $cap, $user_id, $args ) {
1127
		//only process if we're checking our mapped_cap
1128
		if ( $cap !== $this->meta_cap ) {
1129
			return $caps;
1130
		}
1131
1132
		$obj = ! empty( $args[0] ) ? $this->_model->get_one_by_ID( $args[0] ) : null;
1133
1134
		//if no obj then let's just do cap
1135
		if ( ! $obj instanceof EE_Base_Class ) {
1136
			$caps[] = $cap;
1137
			return $caps;
1138
		}
1139
1140
		$is_system = $obj instanceof EE_Question_Group ? $obj->system_group() : false;
1141
		$is_system = $obj instanceof EE_Question ? $obj->is_system_question() : $is_system;
1142
1143
		if ( $is_system ) {
1144
			$caps[] = $this->private_cap;
1145
		} else {
1146
			$caps[] = $cap;
1147
		}
1148
1149
		return $caps;
1150
	}
1151
}
1152