GravityView  2.17
The best, easiest way to display Gravity Forms entries on your website.
class-gravityview-roles-capabilities.php
Go to the documentation of this file.
1 <?php
2 /**
3  * Roles and Capabilities
4  *
5  * @package GravityView
6  * @license GPL2+
7  * @since 1.14
8  * @author Katz Web Services, Inc.
9  * @link http://gravityview.co
10  * @copyright Copyright 2015, Katz Web Services, Inc.
11  */
12 
13 // Exit if accessed directly
14 defined( 'ABSPATH' ) || exit;
15 
16 /**
17  * GravityView Roles Class
18  *
19  * This class handles the role creation and assignment of capabilities for those roles.
20  *
21  * @since 1.15
22  */
24 
25  /**
26  * @var GravityView_Roles_Capabilities|null
27  */
28  static $instance = null;
29 
30  /**
31  * @since 1.15
32  * @return GravityView_Roles_Capabilities
33  */
34  public static function get_instance() {
35 
36  if( ! self::$instance ) {
37  self::$instance = new self;
38  }
39 
40  return self::$instance;
41  }
42 
43  /**
44  * Get things going
45  *
46  * @since 1.15
47  */
48  public function __construct() {
49  $this->add_hooks();
50  }
51 
52  /**
53  * @since 1.15
54  */
55  private function add_hooks() {
56  add_filter( 'members_get_capabilities', array( 'GravityView_Roles_Capabilities', 'merge_with_all_caps' ) );
57  add_action( 'members_register_cap_groups', array( $this, 'members_register_cap_group' ), 20 );
58  add_filter( 'user_has_cap', array( $this, 'filter_user_has_cap' ), 10, 4 );
59  add_action( 'admin_init', array( $this, 'add_caps') );
60  }
61 
62 
63  /**
64  * Add support for `gravityview_full_access` capability, and
65  *
66  * @see map_meta_cap()
67  *
68  * @since 1.15
69  *
70  * @param array $allcaps An array of all the user's capabilities.
71  * @param array $caps Actual capabilities for meta capability.
72  * @param array $args Optional parameters passed to has_cap(), typically object ID.
73  * @param WP_User|null $user The user object, in WordPress 3.7.0 or higher
74  *
75  * @return mixed
76  */
77  public function filter_user_has_cap( $usercaps = array(), $caps = array(), $args = array(), $user = NULL ) {
78 
79  // Empty caps_to_check array
80  if( ! $usercaps || ! $caps ) {
81  return $usercaps;
82  }
83 
84  /**
85  * Enable all GravityView caps_to_check if `gravityview_full_access` is enabled
86  */
87  if( ! empty( $usercaps['gravityview_full_access'] ) ) {
88 
89  $all_gravityview_caps = self::all_caps();
90 
91  foreach( $all_gravityview_caps as $gv_cap ) {
92  $usercaps[ $gv_cap ] = true;
93  }
94 
95  unset( $all_gravityview_caps );
96  }
97 
98  $usercaps = $this->add_gravity_forms_usercaps_to_gravityview_caps( $usercaps );
99 
100  return $usercaps;
101  }
102 
103  /**
104  * If a user has been assigned custom capabilities for Gravity Forms, but they haven't been assigned similar abilities
105  * in GravityView yet, we give temporary access to the permissions, until they're set.
106  *
107  * This is for custom roles that GravityView_Roles_Capabilities::add_caps() doesn't modify. If you have a
108  * custom role with the ability to edit any Gravity Forms entries (`gravityforms_edit_entries`), you would
109  * expect GravityView to match that capability, until the role has been updated with GravityView caps.
110  *
111  * @since 1.15
112  *
113  * @param array $usercaps User's allcaps array
114  *
115  * @return array
116  */
117  private function add_gravity_forms_usercaps_to_gravityview_caps( $usercaps ) {
118 
119  $gf_to_gv_caps = array(
120  'gravityforms_edit_entries' => 'gravityview_edit_others_entries',
121  'gravityforms_delete_entries' => 'gravityview_delete_others_entries',
122  'gravityforms_view_entry_notes' => 'gravityview_view_entry_notes',
123  'gravityforms_edit_entry_notes' => 'gravityview_delete_entry_notes',
124  );
125 
126  foreach ( $gf_to_gv_caps as $gf_cap => $gv_cap ) {
127  if ( isset( $usercaps[ $gf_cap ] ) && ! isset( $usercaps[ $gv_cap ] ) ) {
128  $usercaps[ $gv_cap ] = $usercaps[ $gf_cap ];
129  }
130  }
131 
132  return $usercaps;
133  }
134 
135  /**
136  * Add GravityView group to Members 1.x plugin management screen
137  * @see members_register_cap_group()
138  * @since 1.15
139  * @return void
140  */
142  if ( function_exists( 'members_register_cap_group' ) ) {
143 
144  $args = array(
145  'label' => __( 'GravityView', 'gk-gravityview' ),
146  'icon' => 'gv-icon-astronaut-head',
147  'caps' => self::all_caps(),
148  'merge_added' => true,
149  'diff_added' => false,
150  );
151 
152  members_register_cap_group( 'gravityview', $args );
153  }
154  }
155 
156  /**
157  * Merge capabilities array with GravityView capabilities
158  *
159  * @since 1.15 Used to add GravityView caps to the Members plugin
160  * @param array $caps Existing capabilities
161  * @return array Modified capabilities array
162  */
163  public static function merge_with_all_caps( $caps ) {
164 
165  $return_caps = array_merge( $caps, self::all_caps() );
166 
167  return array_unique( $return_caps );
168  }
169 
170  /**
171  * Retrieves the global WP_Roles instance and instantiates it if necessary.
172  *
173  * @see wp_roles() This method uses the exact same code as wp_roles(), here for backward compatibility
174  *
175  * @global WP_Roles $wp_roles WP_Roles global instance.
176  *
177  * @return WP_Roles WP_Roles global instance if not already instantiated.
178  */
179  private function wp_roles() {
180  global $wp_roles;
181 
182  if ( ! isset( $wp_roles ) ) {
183  $wp_roles = new WP_Roles();
184  }
185 
186  return $wp_roles;
187  }
188 
189  /**
190  * Add capabilities to their respective roles if they don't already exist
191  * This could be simpler, but the goal is speed.
192  *
193  * @since 1.15
194  * @return void
195  */
196  public function add_caps() {
197 
198  $wp_roles = $this->wp_roles();
199 
200  if ( is_object( $wp_roles ) ) {
201 
202  $_use_db_backup = $wp_roles->use_db;
203 
204  /**
205  * When $use_db is true, add_cap() performs update_option() every time.
206  * We disable updating the database here, then re-enable it below.
207  */
208  $wp_roles->use_db = false;
209 
210  $capabilities = self::all_caps( false, false );
211 
212  foreach ( $capabilities as $role_slug => $role_caps ) {
213  foreach ( $role_caps as $cap ) {
214  $wp_roles->add_cap( $role_slug, $cap );
215  }
216  }
217 
218  /**
219  * Update the option, as it does in add_cap when $use_db is true
220  *
221  * @see WP_Roles::add_cap() Original code
222  */
223  update_option( $wp_roles->role_key, $wp_roles->roles );
224 
225  /**
226  * Restore previous $use_db setting
227  */
228  $wp_roles->use_db = $_use_db_backup;
229  }
230  }
231 
232  /**
233  * Get an array of GravityView capabilities
234  *
235  * @see get_post_type_capabilities()
236  *
237  * @since 1.15
238  *
239  * @param string $single_role If set, get the caps_to_check for a specific role. Pass 'all' to get all caps_to_check in a flat array. Default: `all`
240  * @param boolean $flat_array True: return all caps in a one-dimensional array. False: a multi-dimensional array with `$single_role` as keys and the caps as the values
241  *
242  * @return array If $role is set, flat array of caps_to_check. Otherwise, a multi-dimensional array of roles and their caps_to_check with the following keys: 'administrator', 'editor', 'author', 'contributor', 'subscriber'
243  */
244  public static function all_caps( $single_role = false, $flat_array = true ) {
245 
246  // Change settings
247  $administrator_caps = array(
248  'gravityview_full_access', // Grant access to all caps_to_check
249  'gravityview_view_settings',
250  'gravityview_edit_settings',
251  'gravityview_uninstall', // Ability to trigger the Uninstall @todo
252  'gravityview_contact_support', // Whether able to send a message to support via the Support Port
253 
254  'edit_others_gravityviews',
255  'edit_private_gravityviews',
256  'edit_published_gravityviews',
257  );
258 
259  // Edit, publish, delete own and others' stuff
260  $editor_caps = array(
261  'read_private_gravityviews',
262  'delete_private_gravityviews',
263  'delete_others_gravityviews',
264  'publish_gravityviews',
265  'delete_published_gravityviews',
266  'copy_gravityviews', // For duplicate/clone View functionality
267 
268  // GF caps_to_check
269  'gravityview_edit_others_entries',
270  'gravityview_moderate_entries', // Approve or reject entries from the Admin; show/hide approval column in Entries screen
271  'gravityview_delete_others_entries',
272  'gravityview_add_entry_notes',
273  'gravityview_view_entry_notes',
274  'gravityview_delete_entry_notes',
275  'gravityview_email_entry_notes',
276  );
277 
278  // Edit, delete own stuff
279  $author_caps = array(
280  // GF caps_to_check
281  'gravityview_edit_entries',
282  'gravityview_edit_entry',
283  'gravityview_edit_form_entries', // This is similar to `gravityview_edit_entries`, but checks against a Form ID $object_id
284  'gravityview_delete_entries',
285  'gravityview_delete_entry',
286  );
287 
288  // Edit and delete drafts but not publish
289  $contributor_caps = array(
290  'edit_gravityviews',
291  'delete_gravityviews',
292  'gravityview_getting_started', // Getting Started page access
293  'gravityview_support_port', // Display GravityView Support Port
294  );
295 
296  // Read only
297  $subscriber_caps = array(
298  'gravityview_view_entries',
299  'gravityview_view_others_entries',
300  );
301 
302  $subscriber = $subscriber_caps;
303  $contributor = array_merge( $contributor_caps, $subscriber_caps );
304  $author = array_merge( $author_caps, $contributor_caps, $subscriber_caps );
305  $editor = array_merge( $editor_caps, $author_caps, $contributor_caps, $subscriber_caps );
306  $administrator = array_merge( $administrator_caps, $editor_caps, $author_caps, $contributor_caps, $subscriber_caps );
307  $all = $administrator;
308 
309  // If role is set, return caps_to_check for just that role.
310  if( $single_role ) {
311  $caps = isset( ${$single_role} ) ? ${$single_role} : false;
312  return $flat_array ? $caps : array( $single_role => $caps );
313  }
314 
315  // Otherwise, return multi-dimensional array of all caps_to_check
316  return $flat_array ? $all : compact( 'administrator', 'editor', 'author', 'contributor', 'subscriber' );
317  }
318 
319  /**
320  * Check whether the current user has a capability
321  *
322  * @since 1.15
323  *
324  * @see WP_User::user_has_cap()
325  * @see https://codex.wordpress.org/Plugin_API/Filter_Reference/user_has_cap You can filter permissions based on entry/View/form ID using `user_has_cap` filter
326  *
327  * @see GFCommon::current_user_can_any
328  * @uses GFCommon::current_user_can_any
329  *
330  * @param string|array $caps_to_check Single capability or array of capabilities
331  * @param int|null $object_id (optional) Parameter can be used to check for capabilities against a specific object, such as a post or us
332  * @param int|null $user_id (optional) Check the capabilities for a user who is not necessarily the currently logged-in user
333  *
334  * @return bool True: user has at least one passed capability; False: user does not have any defined capabilities
335  */
336  public static function has_cap( $caps_to_check = '', $object_id = null, $user_id = null ) {
337 
338  /**
339  * @filter `gravityview/capabilities/allow_logged_out` Shall we allow a cap check for non-logged in users? USE WITH CAUTION!
340  *
341  * WARNING: This allows anyone to edit and delete entries, add notes, delete notes, etc!
342  *
343  * If you use this filter, at least check against certain capabilities and $object_ids.
344  *
345  * There are use-cases, albeit strange ones, where we'd like to check and override capabilities for
346  * for a non-logged in user.
347  *
348  * Examples, you ask? https://github.com/gravityview/GravityView/issues/826
349  *
350  * @param boolean $allow_logged_out Allow the capability check or bail without even checking. Default: false. Do not allow. Do not pass Go. Do not collect $200.
351  * @param string|array $caps_to_check Single capability or array of capabilities to check against
352  * @param int|null $object_id (optional) Parameter can be used to check for capabilities against a specific object, such as a post or us.
353  * @param int|null $user_id (optional) Check the capabilities for a user who is not necessarily the currently logged-in user.
354  */
355  $allow_logged_out = apply_filters( 'gravityview/capabilities/allow_logged_out', false, $caps_to_check, $object_id, $user_id );
356 
357  if ( true === $allow_logged_out ) {
358 
359  $all_caps = self::all_caps('editor');
360 
361  if( array_intersect( $all_caps, (array) $caps_to_check ) ) {
362  return true;
363  }
364  }
365 
366  /**
367  * We bail with a negative response without even checking if:
368  *
369  * 1. The current user is not logged in and non-logged in users are considered unprivileged (@see `gravityview/capabilities/allow_logged_out` filter).
370  * 2. If the caps to check are empty.
371  */
372  if ( ( ! is_user_logged_in() && ! $allow_logged_out ) || empty( $caps_to_check ) ) {
373  return false;
374  }
375 
376  $has_cap = false;
377 
378  // Add full access caps for GV & GF
379  $caps_to_check = self::maybe_add_full_access_caps( $caps_to_check );
380 
381  foreach ( $caps_to_check as $cap ) {
382  if( ! is_null( $object_id ) ) {
383  $has_cap = $user_id ? user_can( $user_id, $cap, $object_id ) : current_user_can( $cap, $object_id );
384  } else {
385  $has_cap = $user_id ? user_can( $user_id, $cap ) : current_user_can( $cap );
386  }
387  // At the first successful response, stop checking
388  if( $has_cap ) {
389  break;
390  }
391  }
392 
393  return $has_cap;
394  }
395 
396  /**
397  * Add Gravity Forms and GravityView's "full access" caps when any other caps are checked against.
398  *
399  * @since 1.15
400 
401  * @param array $caps_to_check
402  *
403  * @return array
404  */
405  public static function maybe_add_full_access_caps( $caps_to_check = array() ) {
406 
407  $caps_to_check = (array)$caps_to_check;
408 
409  $all_gravityview_caps = self::all_caps();
410 
411  // Are there any $caps_to_check that are from GravityView?
412  if( $has_gravityview_caps = array_intersect( $caps_to_check, $all_gravityview_caps ) ) {
413  $caps_to_check[] = 'gravityview_full_access';
414  }
415 
416  $all_gravity_forms_caps = class_exists( 'GFCommon' ) ? GFCommon::all_caps() : array();
417 
418  // Are there any $caps_to_check that are from Gravity Forms?
419  if( $all_gravity_forms_caps = array_intersect( $caps_to_check, $all_gravity_forms_caps ) ) {
420  $caps_to_check[] = 'gform_full_access';
421  }
422 
423  return array_unique( $caps_to_check );
424  }
425 
426  /**
427  * Remove all GravityView caps_to_check from all roles
428  *
429  * @since 1.15
430  * @return void
431  */
432  public function remove_caps() {
433 
434  $wp_roles = $this->wp_roles();
435 
436  if ( is_object( $wp_roles ) ) {
437 
438  /** Remove all GravityView caps_to_check from all roles */
439  $capabilities = self::all_caps();
440 
441  // Loop through each role and remove GV caps_to_check
442  foreach( $wp_roles->get_names() as $role_slug => $role_name ) {
443  foreach ( $capabilities as $cap ) {
444  $wp_roles->remove_cap( $role_slug, $cap );
445  }
446  }
447  }
448  }
449 }
450 
451 add_action( 'init', array( 'GravityView_Roles_Capabilities', 'get_instance' ), 1 );
remove_caps()
Remove all GravityView caps_to_check from all roles.
if(empty( $value)) $user
static all_caps( $single_role=false, $flat_array=true)
Get an array of GravityView capabilities.
static has_cap( $caps_to_check='', $object_id=null, $user_id=null)
Check whether the current user has a capability.
wp_roles()
Retrieves the global WP_Roles instance and instantiates it if necessary.
static merge_with_all_caps( $caps)
Merge capabilities array with GravityView capabilities.
static maybe_add_full_access_caps( $caps_to_check=array())
Add Gravity Forms and GravityView&#39;s "full access" caps when any other caps are checked against...
add_gravity_forms_usercaps_to_gravityview_caps( $usercaps)
If a user has been assigned custom capabilities for Gravity Forms, but they haven&#39;t been assigned sim...
add_caps()
Add capabilities to their respective roles if they don&#39;t already exist This could be simpler...
filter_user_has_cap( $usercaps=array(), $caps=array(), $args=array(), $user=NULL)
Add support for gravityview_full_access capability, and.
members_register_cap_group()
Add GravityView group to Members 1.x plugin management screen.