GravityView  2.17
The best, easiest way to display Gravity Forms entries on your website.
class-edit-entry.php
Go to the documentation of this file.
1 <?php
2 /**
3  * The GravityView Edit Entry Extension
4  *
5  * Easily edit entries in GravityView.
6  *
7  * @package GravityView
8  * @license GPL2+
9  * @author GravityView <[email protected]>
10  * @link http://gravityview.co
11  * @copyright Copyright 2014, Katz Web Services, Inc.
12  */
13 
14 if ( ! defined( 'WPINC' ) ) {
15  die;
16 }
17 
18 
20 
21  /**
22  * @var string
23  */
24  static $file;
25 
26  static $instance;
27 
28  /**
29  * Component instances.
30  * @var array
31  */
32  public $instances = array();
33 
34 
35  function __construct() {
36 
37  self::$file = plugin_dir_path( __FILE__ );
38 
39  if( is_admin() ) {
40  $this->load_components( 'admin' );
41  }
42 
43  $this->load_components( 'locking' );
44 
45  $this->load_components( 'render' );
46 
47  // If GF User Registration Add-on exists
48  $this->load_components( 'user-registration' );
49 
50  $this->add_hooks();
51 
52  // Process hooks for addons that may or may not be present
53  $this->addon_specific_hooks();
54  }
55 
56 
57  static function getInstance() {
58 
59  if( empty( self::$instance ) ) {
60  self::$instance = new GravityView_Edit_Entry;
61  }
62 
63  return self::$instance;
64  }
65 
66 
67  private function load_components( $component ) {
68 
69  $dir = trailingslashit( self::$file );
70 
71  $filename = $dir . 'class-edit-entry-' . $component . '.php';
72  $classname = 'GravityView_Edit_Entry_' . str_replace( ' ', '_', ucwords( str_replace( '-', ' ', $component ) ) );
73 
74  // Loads component and pass extension's instance so that component can
75  // talk each other.
76  require_once $filename;
77  $this->instances[ $component ] = new $classname( $this );
78  $this->instances[ $component ]->load();
79 
80  }
81 
82  private function add_hooks() {
83 
84  // Add front-end access to Gravity Forms delete file action
85  add_action( 'wp_ajax_nopriv_rg_delete_file', array( $this, 'delete_file') );
86 
87  // Make sure this hook is run for non-admins
88  add_action( 'wp_ajax_rg_delete_file', array( $this, 'delete_file') );
89 
90  add_filter( 'gravityview_blocklist_field_types', array( $this, 'modify_field_blocklist' ), 10, 2 );
91 
92  // add template path to check for field
93  add_filter( 'gravityview_template_paths', array( $this, 'add_template_path' ) );
94 
95  add_filter( 'gravityview/field/is_visible', array( $this, 'maybe_not_visible' ), 10, 3 );
96 
97  add_filter( 'gravityview/api/reserved_query_args', array( $this, 'add_reserved_arg' ) );
98  }
99 
100  /**
101  * Adds "edit" to the list of internal reserved query args
102  *
103  * @since 2.10
104  *
105  * @param array $args Existing reserved args
106  *
107  * @return array
108  */
109  public function add_reserved_arg( $args ) {
110 
111  $args[] = 'edit';
112 
113  return $args;
114  }
115 
116  /**
117  * Trigger hooks that are normally run in the admin for Addons, but need to be triggered manually because we're not in the admin
118  * @return void
119  */
120  private function addon_specific_hooks() {
121 
122  if( class_exists( 'GFSignature' ) && is_callable( array( 'GFSignature', 'get_instance' ) ) ) {
123  add_filter('gform_admin_pre_render', array( GFSignature::get_instance(), 'edit_lead_script'));
124  }
125 
126  }
127 
128  /**
129  * Hide the field or not.
130  *
131  * For non-logged in users.
132  * For users that have no edit rights on any of the current entries.
133  *
134  * @param bool $visible Visible or not.
135  * @param \GV\Field $field The field.
136  * @param \GV\View $view The View context.
137  *
138  * @return bool
139  */
140  public function maybe_not_visible( $visible, $field, $view ) {
141 
142  if ( 'edit_link' !== $field->ID ) {
143  return $visible;
144  }
145 
146  if ( ! $view instanceof \GV\View ) {
147  return $visible;
148  }
149 
150  static $visibility_cache_for_view = array();
151 
152  if ( ! is_null( $result = \GV\Utils::get( $visibility_cache_for_view, $view->ID, null ) ) ) {
153  return $result;
154  }
155 
156  foreach ( $view->get_entries()->all() as $entry ) {
157  if ( self::check_user_cap_edit_entry( $entry->as_entry(), $view ) ) {
158  // At least one entry is deletable for this user
159  $visibility_cache_for_view[ $view->ID ] = true;
160  return true;
161  }
162  }
163 
164  $visibility_cache_for_view[ $view->ID ] = false;
165 
166  return false;
167  }
168 
169  /**
170  * Include this extension templates path
171  * @param array $file_paths List of template paths ordered
172  */
173  public function add_template_path( $file_paths ) {
174 
175  // Index 100 is the default GravityView template path.
176  $file_paths[ 110 ] = self::$file;
177 
178  return $file_paths;
179  }
180 
181  /**
182  *
183  * Return a well formatted nonce key according to GravityView Edit Entry protocol
184  *
185  * @param $view_id int GravityView view id
186  * @param $form_id int Gravity Forms form id
187  * @param $entry_id int Gravity Forms entry id
188  * @return string
189  */
190  public static function get_nonce_key( $view_id, $form_id, $entry_id ) {
191  return sprintf( 'edit_%d_%d_%d', $view_id, $form_id, $entry_id );
192  }
193 
194 
195  /**
196  * The edit entry link creates a secure link with a nonce
197  *
198  * It also mimics the URL structure Gravity Forms expects to have so that
199  * it formats the display of the edit form like it does in the backend, like
200  * "You can edit this post from the post page" fields, for example.
201  *
202  * @param $entry array Gravity Forms entry object
203  * @param $view_id int GravityView view id
204  * @param $post_id int GravityView Post ID where View may be embedded {@since 1.9.2}
205  * @param string|array $field_values Parameters to pass in to the Edit Entry form to prefill data. Uses the same format as Gravity Forms "Allow field to be populated dynamically" {@since 1.9.2} {@see https://www.gravityhelp.com/documentation/article/allow-field-to-be-populated-dynamically/ }
206  * @return string
207  */
208  public static function get_edit_link( $entry, $view_id, $post_id = null, $field_values = '' ) {
209 
210  $nonce_key = self::get_nonce_key( $view_id, $entry['form_id'], $entry['id'] );
211 
212  $base = gv_entry_link( $entry, $post_id ? : $view_id );
213 
214  $url = add_query_arg( array(
215  'edit' => wp_create_nonce( $nonce_key )
216  ), $base );
217 
218  if ( $post_id ) {
219  $url = add_query_arg( array( 'gvid' => $view_id ), $url );
220  }
221 
222  /**
223  * Allow passing params to dynamically populate entry with values
224  * @since 1.9.2
225  */
226  if( !empty( $field_values ) ) {
227 
228  if( is_array( $field_values ) ) {
229  // If already an array, no parse_str() needed
230  $params = $field_values;
231  } else {
232  parse_str( $field_values, $params );
233  }
234 
235  $url = add_query_arg( $params, $url );
236  }
237 
238  /**
239  * @filter `gravityview/edit/link` Filter the edit URL link.
240  *
241  * @since 2.14.6 Added $post param.
242  *
243  * @param string $url The url.
244  * @param array $entry The entry.
245  * @param \GV\View $view The View.
246  * @param WP_Post|null WP_Post $post WP post.
247  */
248  return apply_filters( 'gravityview/edit/link', $url, $entry, \GV\View::by_id( $view_id ), get_post( $view_id ) );
249  }
250 
251  /**
252  * @depecated 2.14 Use {@see GravityView_Edit_Entry::modify_field_blocklist()}
253  *
254  * @param array $fields Existing blocklist fields
255  * @param string|null $context Context
256  *
257  * @return array If not edit context, original field blocklist. Otherwise, blocklist including post fields.
258  */
259  public function modify_field_blacklist( $fields = array(), $context = NULL ) {
260  _deprecated_function( __METHOD__, '2.14', 'GravityView_Edit_Entry::modify_field_blocklist()' );
261  return $this->modify_field_blocklist( $fields, $context );
262  }
263 
264  /**
265  * Edit mode doesn't allow certain field types.
266  *
267  * @since 2.14
268  *
269  * @param array $fields Existing blocklist fields
270  * @param string|null $context Context
271  *
272  * @return array If not edit context, original field blocklist. Otherwise, blocklist including post fields.
273  */
274  public function modify_field_blocklist( $fields = array(), $context = NULL ) {
275 
276  if( empty( $context ) || $context !== 'edit' ) {
277  return $fields;
278  }
279 
280  $add_fields = $this->get_field_blocklist();
281 
282  return array_merge( $fields, $add_fields );
283  }
284 
285  /**
286  * @depecated 2.14 Use {@see GravityView_Edit_Entry::get_field_blocklist()}
287  *
288  * @since 1.20
289  *
290  * @param array $entry Gravity Forms entry array
291  *
292  * @return array Blocklist of field types
293  */
294  public function get_field_blacklist( $entry = array() ) {
295  _deprecated_function( __METHOD__, '2.14', 'GravityView_Edit_Entry::get_field_blocklist()' );
296  return $this->get_field_blocklist( $entry );
297  }
298 
299  /**
300  * Returns array of field types that should not be displayed in Edit Entry
301  *
302  * @since 2.14
303  *
304  * @param array $entry Gravity Forms entry array
305  *
306  * @return array Blocklist of field types
307  */
308  function get_field_blocklist( $entry = array() ) {
309 
310  $fields = array(
311  'page',
312  'payment_status',
313  'payment_date',
314  'payment_amount',
315  'is_fulfilled',
316  'transaction_id',
317  'transaction_type',
318  'captcha',
319  'honeypot',
320  'creditcard',
321  );
322 
323  /**
324  * @depecated 2.14
325  */
326  $fields = apply_filters_deprecated( 'gravityview/edit_entry/field_blacklist', array( $fields, $entry ), '2.14', 'gravityview/edit_entry/field_blocklist' );
327 
328  /**
329  * @filter `gravityview/edit_entry/field_blocklist` Array of fields that should not be displayed in Edit Entry
330  * @since 1.20
331  * @param string[] $fields Array of field type or meta key names (eg: `[ "captcha", "payment_status" ]` ).
332  * @param array $entry Gravity Forms entry array.
333  */
334  $fields = apply_filters( 'gravityview/edit_entry/field_blocklist', $fields, $entry );
335 
336  return $fields;
337  }
338 
339 
340  /**
341  * checks if user has permissions to edit a specific entry
342  *
343  * Needs to be used combined with GravityView_Edit_Entry::user_can_edit_entry for maximum security!!
344  *
345  * @param array $entry Gravity Forms entry array
346  * @param \GV\View|int $view ID of the view you want to check visibility against {@since 1.9.2}. Required since 2.0
347  * @return bool
348  */
349  public static function check_user_cap_edit_entry( $entry, $view = 0 ) {
350 
351  // No permission by default
352  $user_can_edit = false;
353 
354  // get user_edit setting
355  if ( empty( $view ) ) {
356  // @deprecated path
357  $view_id = GravityView_View::getInstance()->getViewId();
358  $user_edit = GravityView_View::getInstance()->getAtts( 'user_edit' );
359  } else {
360  if ( $view instanceof \GV\View ) {
361  $view_id = $view->ID;
362  } else {
363  $view_id = $view;
364  }
365 
366  // in case is specified and not the current view
367  $user_edit = GVCommon::get_template_setting( $view_id, 'user_edit' );
368  }
369 
370  // If they can edit any entries (as defined in Gravity Forms)
371  // Or if they can edit other people's entries
372  // Then we're good.
373  if( GVCommon::has_cap( array( 'gravityforms_edit_entries', 'gravityview_edit_others_entries' ), $entry['id'] ) ) {
374 
375  gravityview()->log->debug( 'User has ability to edit all entries.' );
376 
377  $user_can_edit = true;
378 
379  } else if( !isset( $entry['created_by'] ) ) {
380 
381  gravityview()->log->error( 'Entry `created_by` doesn\'t exist.');
382 
383  $user_can_edit = false;
384 
385  } else {
386 
387  $current_user = wp_get_current_user();
388 
389  // User edit is disabled
390  if( empty( $user_edit ) ) {
391 
392  gravityview()->log->debug( 'User Edit is disabled. Returning false.' );
393 
394  $user_can_edit = false;
395  }
396 
397  // User edit is enabled and the logged-in user is the same as the user who created the entry. We're good.
398  else if( is_user_logged_in() && intval( $current_user->ID ) === intval( $entry['created_by'] ) ) {
399 
400  gravityview()->log->debug( 'User {user_id} created the entry.', array( 'user_id', $current_user->ID ) );
401 
402  $user_can_edit = true;
403 
404  } else if( ! is_user_logged_in() ) {
405 
406  gravityview()->log->debug( 'No user defined; edit entry requires logged in user' );
407 
408  $user_can_edit = false; // Here just for clarity
409  }
410 
411  }
412 
413  /**
414  * @filter `gravityview/edit_entry/user_can_edit_entry` Modify whether user can edit an entry.
415  * @since 1.15 Added `$entry` and `$view_id` parameters
416  * @param boolean $user_can_edit Can the current user edit the current entry? (Default: false)
417  * @param array $entry Gravity Forms entry array {@since 1.15}
418  * @param int $view_id ID of the view you want to check visibility against {@since 1.15}
419  */
420  $user_can_edit = apply_filters( 'gravityview/edit_entry/user_can_edit_entry', $user_can_edit, $entry, $view_id );
421 
422  return (bool) $user_can_edit;
423  }
424 
425  /**
426  * Deletes a file.
427  *
428  * @since 2.14.4
429  *
430  * @uses GFForms::delete_file()
431  */
432  public function delete_file() {
433  add_filter( 'user_has_cap', function ( $caps ) {
434  $caps['gravityforms_delete_entries'] = true;
435 
436  return $caps;
437 
438  } );
439 
440  GFForms::delete_file();
441  }
442 } // end class
443 
444 //add_action( 'plugins_loaded', array('GravityView_Edit_Entry', 'getInstance'), 6 );
446 
$url
Definition: post_image.php:25
static get_edit_link( $entry, $view_id, $post_id=null, $field_values='')
The edit entry link creates a secure link with a nonce.
add_reserved_arg( $args)
Adds "edit" to the list of internal reserved query args.
__construct()
delete_file()
Deletes a file.
static getInstance( $passed_post=NULL)
static get_template_setting( $post_id, $key)
Get the setting for a View.
static $instance
static check_user_cap_edit_entry( $entry, $view=0)
checks if user has permissions to edit a specific entry
add_hooks()
maybe_not_visible( $visible, $field, $view)
Hide the field or not.
modify_field_blacklist( $fields=array(), $context=NULL)
2.14 Use {
get_field_blocklist( $entry=array())
Returns array of field types that should not be displayed in Edit Entry.
$instances
add_template_path( $file_paths)
Include this extension templates path.
modify_field_blocklist( $fields=array(), $context=NULL)
Edit mode doesn&#39;t allow certain field types.
static get_nonce_key( $view_id, $form_id, $entry_id)
Return a well formatted nonce key according to GravityView Edit Entry protocol.
load_components( $component)
static $file
get_field_blacklist( $entry=array())
2.14 Use {
if(empty( $created_by)) $form_id
gravityview()
The main GravityView wrapper function.
gv_entry_link( $entry, $post_id=NULL)
Definition: class-api.php:938
addon_specific_hooks()
Trigger hooks that are normally run in the admin for Addons, but need to be triggered manually becaus...
static has_cap( $caps='', $object_id=null, $user_id=null)
Alias of GravityView_Roles_Capabilities::has_cap()
$entry
Definition: notes.php:27
static getInstance()