GravityView  1.19.4
The best, easiest way to display Gravity Forms entries on your website.
class-gravityview-entry-approval.php
Go to the documentation of this file.
1 <?php
2 /**
3  * @file class-gravityview-entry-approval.php
4  * @package GravityView
5  * @license GPL2+
6  * @author Katz Web Services, Inc.
7  * @link https://gravityview.co
8  * @copyright Copyright 2016, Katz Web Services, Inc.
9  *
10  * @since 1.18
11  */
12 
13 /** If this file is called directly, abort. */
14 if ( ! defined( 'ABSPATH' ) ) {
15  die;
16 }
17 
18 /**
19  * Generate linked list output for a list of entries.
20  *
21  * @since 1.18
22  */
24 
25  /**
26  * @var string Key used to store approval status in the Gravity Forms entry meta table
27  */
28  const meta_key = 'is_approved';
29 
30  public function __construct() {
31  $this->add_hooks();
32  }
33 
34  /**
35  * Add actions and filters related to entry approval
36  *
37  * @return void
38  */
39  private function add_hooks() {
40 
41  // in case entry is edited (on admin or frontend)
42  add_action( 'gform_after_update_entry', array( $this, 'after_update_entry_update_approved_meta' ), 10, 2);
43 
44  // when using the User opt-in field, check on entry submission
45  add_action( 'gform_after_submission', array( $this, 'after_submission' ), 10, 2 );
46 
47  // process ajax approve entry requests
48  add_action('wp_ajax_gv_update_approved', array( $this, 'ajax_update_approved'));
49 
50  }
51 
52  /**
53  * Get the approval status for an entry
54  *
55  * @since 1.18
56  * @uses GVCommon::get_entry_id() Accepts entry slug or entry ID
57  *
58  * @param array|int|string $entry Entry array, entry slug, or entry ID
59  * @param string $value_or_label "value" or "label" (default: "label")
60  *
61  * @return bool|string Return the label or value of entry approval
62  */
63  public static function get_entry_status( $entry, $value_or_label = 'label' ) {
64 
65  $entry_id = is_array( $entry ) ? $entry['id'] : GVCommon::get_entry_id( $entry, true );
66 
67  $status = gform_get_meta( $entry_id, self::meta_key );
68 
70 
71  if( 'value' === $value_or_label ) {
72  return $status;
73  }
74 
76  }
77 
78  /**
79  * Approve/Disapprove entries using the × or ✓ icons in the GF Entries screen
80  *
81  * @uses wp_send_json_error()
82  * @uses wp_send_json_success()
83  *
84  * Expects a $_POST request with the following $_POST keys and values:
85  *
86  * @global array $_POST {
87  * @type int $form_id ID of the form connected to the entry being updated
88  * @type string|int $entry_slug The ID or slug of the entry being updated
89  * @type string $approved The value of the entry approval status {@see GravityView_Entry_Approval_Status::is_valid() }
90  * }
91  *
92  * @return void Prints result using wp_send_json_success() and wp_send_json_error()
93  */
94  public function ajax_update_approved() {
95 
96  $form_id = intval( rgpost('form_id') );
97 
98  // We always want requests from the admin to allow entry IDs, but not from the frontend
99  // There's another nonce sent when approving entries in the admin that we check
100  $force_entry_ids = rgpost( 'admin_nonce' ) && wp_verify_nonce( rgpost( 'admin_nonce' ), 'gravityview_admin_entry_approval' );
101 
102  $entry_id = GVCommon::get_entry_id( rgpost('entry_slug'), $force_entry_ids );
103 
104  $approval_status = rgpost('approved');
105 
106  $nonce = rgpost('nonce');
107 
108  // Valid status
109  if( ! GravityView_Entry_Approval_Status::is_valid( $approval_status ) ) {
110 
111  do_action( 'gravityview_log_error', __METHOD__ . ': Invalid approval status', $_POST );
112 
113  $result = new WP_Error( 'invalid_status', __( 'The request was invalid. Refresh the page and try again.', 'gravityview' ) );
114 
115  }
116 
117  // Valid values
118  elseif ( empty( $entry_id ) || empty( $form_id ) ) {
119 
120  do_action( 'gravityview_log_error', __METHOD__ . ' entry_id or form_id are empty.', $_POST );
121 
122  $result = new WP_Error( 'empty_details', __( 'The request was invalid. Refresh the page and try again.', 'gravityview' ) );
123 
124  }
125 
126  // Valid nonce
127  else if ( empty( $nonce ) || ! wp_verify_nonce( $nonce, 'gravityview_entry_approval' ) ) {
128 
129  do_action( 'gravityview_log_error', __METHOD__ . ' Security check failed.', $_POST );
130 
131  $result = new WP_Error( 'invalid_nonce', __( 'The request was invalid. Refresh the page and try again.', 'gravityview' ) );
132 
133  }
134 
135  // Has capability
136  elseif ( ! GVCommon::has_cap( 'gravityview_moderate_entries', $entry_id ) ) {
137 
138  do_action( 'gravityview_log_error', __METHOD__ . ' User does not have the `gravityview_moderate_entries` capability.' );
139 
140  $result = new WP_Error( 'Missing Cap: gravityview_moderate_entries', __( 'You do not have permission to edit this entry.', 'gravityview') );
141 
142  }
143 
144  // All checks passed
145  else {
146 
147  $result = self::update_approved( $entry_id, $approval_status, $form_id );
148 
149  }
150 
151  if ( is_wp_error( $result ) ) {
152  do_action( 'gravityview_log_error', __METHOD__ . ' Error updating approval: ' . $result->get_error_message() );
153 
154  wp_send_json_error( $result );
155  }
156 
157  $current_status = self::get_entry_status( $entry_id, 'value' );
158 
159  wp_send_json_success( array(
160  'status' => $current_status
161  ) );
162  }
163 
164  /**
165  * Update the is_approved meta whenever the entry is submitted (and it contains a User Opt-in field)
166  *
167  * @since 1.16.6
168  *
169  * @param $entry array Gravity Forms entry object
170  * @param $form array Gravity Forms form object
171  */
172  public function after_submission( $entry, $form ) {
174  }
175 
176  /**
177  * Update the is_approved meta whenever the entry is updated
178  *
179  * @since 1.7.6.1 Was previously named `update_approved_meta`
180  *
181  * @param array $form Gravity Forms form array
182  * @param int $entry_id ID of the Gravity Forms entry
183  * @return void
184  */
185  public function after_update_entry_update_approved_meta( $form, $entry_id = NULL ) {
186 
187  $approved_column = self::get_approved_column( $form['id'] );
188 
189  /**
190  * If the form doesn't contain the approve field, don't assume anything.
191  */
192  if( empty( $approved_column ) ) {
193  return;
194  }
195 
196  $entry = GFAPI::get_entry( $entry_id );
197 
198  // If the checkbox is blank, it's disapproved, regardless of the label
199  if ( '' === rgar( $entry, $approved_column ) ) {
201  } else {
202  // If the checkbox is not blank, it's approved
204  }
205 
206  self::update_approved_meta( $entry_id, $value, $form['id'] );
207  }
208 
209  /**
210  * Process a bulk of entries to update the approve field/property
211  *
212  * @since 1.18 Moved to GravityView_Entry_Approval
213  * @since 1.18 Made public
214  *
215  * @access public
216  * @static
217  * @param array|boolean $entries If array, array of entry IDs that are to be updated. If true: update all entries.
218  * @param int $approved Approved status. If `0`: unapproved, if not empty, `Approved`
219  * @param int $form_id The Gravity Forms Form ID
220  * @return boolean|null True: successfully updated all entries. False: there was an error updating at least one entry. NULL: an error occurred (see log)
221  */
222  public static function update_bulk( $entries = array(), $approved, $form_id ) {
223 
224  if( empty($entries) || ( $entries !== true && !is_array($entries) ) ) {
225  do_action( 'gravityview_log_error', __METHOD__ . ' Entries were empty or malformed.', $entries );
226  return NULL;
227  }
228 
229  if( ! GVCommon::has_cap( 'gravityview_moderate_entries' ) ) {
230  do_action( 'gravityview_log_error', __METHOD__ . ' User does not have the `gravityview_moderate_entries` capability.' );
231  return NULL;
232  }
233 
234 
235  if ( ! GravityView_Entry_Approval_Status::is_valid( $approved ) ) {
236  do_action( 'gravityview_log_error', __METHOD__ . ' Invalid approval status', $approved );
237  return NULL;
238  }
239 
240  // calculate approved field id once instead of looping through in the update_approved() method
241  $approved_column_id = self::get_approved_column( $form_id );
242 
243  $success = true;
244  foreach( $entries as $entry_id ) {
245  $update_success = self::update_approved( (int)$entry_id, $approved, $form_id, $approved_column_id );
246 
247  if( ! $update_success ) {
248  $success = false;
249  }
250  }
251 
252  return $success;
253  }
254 
255  /**
256  * update_approved function.
257  *
258  * @since 1.18 Moved to GravityView_Entry_Approval class
259  *
260  * @access public
261  * @static
262  * @param int $entry_id (default: 0)
263  * @param int $approved (default: 2)
264  * @param int $form_id (default: 0)
265  * @param int $approvedcolumn (default: 0)
266  *
267  * @return boolean True: It worked; False: it failed
268  */
269  public static function update_approved( $entry_id = 0, $approved = 2, $form_id = 0, $approvedcolumn = 0 ) {
270 
271  if( !class_exists( 'GFAPI' ) ) {
272  do_action( 'gravityview_log_error', __METHOD__ . 'GFAPI does not exist' );
273  return false;
274  }
275 
276  if( ! GravityView_Entry_Approval_Status::is_valid( $approved ) ) {
277  do_action( 'gravityview_log_error', __METHOD__ . ': Not a valid approval value.' );
278  return false;
279  }
280 
282 
283  $entry = GFAPI::get_entry( $entry_id );
284 
285  if ( is_wp_error( $entry ) ) {
286  do_action( 'gravityview_log_error', __METHOD__ . ': Entry does not exist' );
287  return false;
288  }
289 
290  // If the form has an Approve/Reject field, update that value
291  $result = self::update_approved_column( $entry_id, $approved, $form_id, $approvedcolumn );
292 
293  if( is_wp_error( $result ) ) {
294  do_action( 'gravityview_log_error', __METHOD__ . sprintf( ' - Entry approval not updated: %s', $result->get_error_message() ) );
295  return false;
296  }
297 
298  $form_id = intval( $form_id );
299 
300  // Update the entry meta
301  self::update_approved_meta( $entry_id, $approved, $form_id );
302 
303  // add note to entry if approval field updating worked or there was no approved field
304  // There's no validation for the meta
305  if( true === $result ) {
306 
307  // Add an entry note
308  self::add_approval_status_updated_note( $entry_id, $approved );
309 
310  /**
311  * Destroy the cache for this form
312  * @see class-cache.php
313  * @since 1.5.1
314  */
315  do_action( 'gravityview_clear_form_cache', $form_id );
316 
317  }
318 
319  return $result;
320  }
321 
322  /**
323  * Add a note when an entry is approved
324  *
325  * @see GravityView_Entry_Approval::update_approved
326  *
327  * @since 1.18
328  *
329  * @param int $entry_id Gravity Forms entry ID
330  * @param int $approved Approval status
331  *
332  * @return false|int|WP_Error Note ID if successful; WP_Error if error when adding note, FALSE if note not updated because of `gravityview/approve_entries/add-note` filter or `GravityView_Entry_Notes` class not existing
333  */
334  private static function add_approval_status_updated_note( $entry_id, $approved = 0 ) {
335  $note = '';
336 
337  switch ( $approved ) {
339  $note = __( 'Approved the Entry for GravityView', 'gravityview' );
340  break;
342  $note = __( 'Reset Entry approval for GravityView', 'gravityview' );
343  break;
345  $note = __( 'Disapproved the Entry for GravityView', 'gravityview' );
346  break;
347  }
348 
349  /**
350  * @filter `gravityview/approve_entries/add-note` Add a note when the entry has been approved or disapproved?
351  * @since 1.16.3
352  * @param bool $add_note True: Yep, add that note! False: Do not, under any circumstances, add that note!
353  */
354  $add_note = apply_filters( 'gravityview/approve_entries/add-note', true );
355 
356  $note_id = false;
357 
358  if( $add_note && class_exists( 'GravityView_Entry_Notes' ) ) {
359 
360  $current_user = wp_get_current_user();
361 
362  $note_id = GravityView_Entry_Notes::add_note( $entry_id, $current_user->ID, $current_user->display_name, $note );
363  }
364 
365  return $note_id;
366  }
367 
368  /**
369  * Update the Approve/Disapproved field value
370  *
371  * @param int $entry_id ID of the Gravity Forms entry
372  * @param string $status String whether entry is approved or not. `0` for not approved, `Approved` for approved.
373  * @param int $form_id ID of the form of the entry being updated. Improves query performance.
374  * @param string $approvedcolumn Gravity Forms Field ID
375  *
376  * @return true|WP_Error
377  */
378  private static function update_approved_column( $entry_id = 0, $status = '0', $form_id = 0, $approvedcolumn = 0 ) {
379 
380  if( empty( $approvedcolumn ) ) {
381  $approvedcolumn = self::get_approved_column( $form_id );
382  }
383 
384  if ( empty( $approvedcolumn ) ) {
385  return true;
386  }
387 
388  if ( ! GravityView_Entry_Approval_Status::is_valid( $status ) ) {
389  return new WP_Error( 'invalid_status', 'Invalid entry approval status', $status );
390  }
391 
392  //get the entry
393  $entry = GFAPI::get_entry( $entry_id );
394 
395  // Entry doesn't exist
396  if ( is_wp_error( $entry ) ) {
397  return $entry;
398  }
399 
401 
402  $new_value = '';
404  $new_value = self::get_approved_column_input_label( $form_id, $approvedcolumn );
405  }
406 
407  //update entry
408  $entry["{$approvedcolumn}"] = $new_value;
409 
410  /**
411  * Note: GFAPI::update_entry() doesn't trigger `gform_after_update_entry`, so we trigger updating the meta ourselves
412  * @see GravityView_Entry_Approval::after_update_entry_update_approved_meta
413  * @var true|WP_Error $result
414  */
415  $result = GFAPI::update_entry( $entry );
416 
417  return $result;
418  }
419 
420  /**
421  * Get the value for the approved field checkbox
422  *
423  * When approving a field via the entry meta, use the correct value for the new approved column input
424  *
425  * @since 1.19
426  *
427  * @param array|int $form Form ID or form array
428  * @param string $approved_column Approved column field ID
429  *
430  * @return string|null
431  */
432  private static function get_approved_column_input_label( $form, $approved_column ) {
433 
434  $field = gravityview_get_field( $form, $approved_column );
435 
436  // If the user has enabled a different value than the label (for some reason), use it.
437  // This is highly unlikely
438  if ( is_array( $field->choices ) && ! empty( $field->choices ) ) {
439  return isset( $field->choices[0]['value'] ) ? $field->choices[0]['value'] : $field->choices[0]['text'];
440  }
441 
442  // Otherwise, fall back on the inputs array
443  if ( is_array( $field->inputs ) && ! empty( $field->inputs ) ) {
444  return $field->inputs[0]['label'];
445  }
446 
447  return null;
448  }
449 
450  /**
451  * Update the `is_approved` entry meta value
452  *
453  * @since 1.7.6.1 `after_update_entry_update_approved_meta` was previously to be named `update_approved_meta`
454  * @since 1.17.1 Added $form_id parameter
455  *
456  * @param int $entry_id ID of the Gravity Forms entry
457  * @param string $status String whether entry is approved or not. `0` for not approved, `Approved` for approved.
458  * @param int $form_id ID of the form of the entry being updated. Improves query performance.
459  *
460  * @return void
461  */
462  private static function update_approved_meta( $entry_id, $status, $form_id = 0 ) {
463 
464  if ( ! GravityView_Entry_Approval_Status::is_valid( $status ) ) {
465  do_action('gravityview_log_error', __METHOD__ . ': $is_approved not valid value', $status );
466  return;
467  }
468 
470 
471  // update entry meta
472  if( function_exists('gform_update_meta') ) {
473 
475  gform_delete_meta( $entry_id, self::meta_key );
476  } else {
477  gform_update_meta( $entry_id, self::meta_key, $status, $form_id );
478  }
479 
480  /**
481  * @action `gravityview/approve_entries/updated` Triggered when an entry approval is updated
482  * @since 1.7.6.1
483  * @param int $entry_id ID of the Gravity Forms entry
484  * @param string|int $status String whether entry is approved or not. See GravityView_Entry_Approval_Status for valid statuses.
485  */
486  do_action( 'gravityview/approve_entries/updated', $entry_id, $status );
487 
488  $action = GravityView_Entry_Approval_Status::get_key( $status );
489 
490  /**
491  * @action `gravityview/approve_entries/{$action}` Triggered when an entry approval is reset.
492  * $action can be 'approved', 'unapproved', or 'disapproved'
493  * @since 1.7.6.1
494  * @since 1.18 Added "unapproved"
495  * @param int $entry_id ID of the Gravity Forms entry
496  */
497  do_action( 'gravityview/approve_entries/' . $action , $entry_id );
498 
499  } else {
500 
501  do_action('gravityview_log_error', __METHOD__ . ' - `gform_update_meta` does not exist.' );
502 
503  }
504  }
505 
506  /**
507  * Calculate the approve field.input id
508  *
509  * @access public
510  * @static
511  * @param mixed $form GF Form or Form ID
512  * @return false|null|string Returns the input ID of the approved field. Returns NULL if no approved fields were found. Returns false if $form_id wasn't set.
513  */
514  static public function get_approved_column( $form ) {
515 
516  if( empty( $form ) ) {
517  return null;
518  }
519 
520  if( !is_array( $form ) ) {
522  }
523 
524  $approved_column_id = null;
525 
526  /**
527  * @var string $key
528  * @var GF_Field $field
529  */
530  foreach( $form['fields'] as $key => $field ) {
531 
532  $inputs = $field->get_entry_inputs();
533 
534  if( !empty( $field->gravityview_approved ) ) {
535  if ( ! empty( $inputs ) && !empty( $inputs[0]['id'] ) ) {
536  $approved_column_id = $inputs[0]['id'];
537  break;
538  }
539  }
540 
541  // Note: This is just for backward compatibility from GF Directory plugin and old GV versions - when using i18n it may not work..
542  if( 'checkbox' === $field->type && ! empty( $inputs ) ) {
543  foreach ( $inputs as $input ) {
544  if ( 'approved' === strtolower( $input['label'] ) ) {
545  $approved_column_id = $input['id'];
546  break;
547  }
548  }
549  }
550  }
551 
552  return $approved_column_id;
553  }
554 
555 }
556 
after_submission($entry, $form)
Update the is_approved meta whenever the entry is submitted (and it contains a User Opt-in field) ...
static get_key($value)
Get the status key for a value.
__construct()
static update_approved_meta($entry_id, $status, $form_id=0)
Update the is_approved entry meta value.
new GravityView_Entry_Approval
static get_form($form_id)
Returns the form object for a given Form ID.
static update_bulk($entries=array(), $approved, $form_id)
Process a bulk of entries to update the approve field/property.
static is_valid($value=NULL)
Check whether the passed value is one of the defined values for entry approval.
static has_cap($caps= '', $object_id=null, $user_id=null)
Alias of GravityView_Roles_Capabilities::has_cap()
$entries
static get_entry_id($entry_id_or_slug= '', $force_allow_ids=false)
Get the entry ID from a string that may be the Entry ID or the Entry Slug.
gravityview_get_field($form, $field_id)
Returns the field details array of a specific form given the field id.
static add_approval_status_updated_note($entry_id, $approved=0)
Add a note when an entry is approved.
If this file is called directly, abort.
static maybe_convert_status($old_value= '')
Convert previously-used values to the current values, for backward compatibility. ...
static update_approved($entry_id=0, $approved=2, $form_id=0, $approvedcolumn=0)
update_approved function.
$current_status
static get_label($value_or_key)
Get the label for a specific approval value.
const APPROVED
ajax_update_approved()
Approve/Disapprove entries using the × or ✓ icons in the GF Entries screen.
const DISAPPROVED
static is_unapproved($status)
add_hooks()
Add actions and filters related to entry approval.
if(empty($created_by)) $form_id
const UNAPPROVED
after_update_entry_update_approved_meta($form, $entry_id=NULL)
Update the is_approved meta whenever the entry is updated.
static add_note($lead_id, $user_id, $user_name, $note= '', $note_type= 'gravityview')
Alias for GFFormsModel::add_note() with default note_type of &#39;gravityview&#39;.
$entry
Definition: notes.php:27
static get_entry_status($entry, $value_or_label= 'label')
Get the approval status for an entry.
static get_approved_column_input_label($form, $approved_column)
Get the value for the approved field checkbox.
const meta_key
$field
Definition: gquiz_grade.php:11