GravityView  2.17
The best, easiest way to display Gravity Forms entries on your website.
class-gravityview-entry-approval-merge-tags.php
Go to the documentation of this file.
1 <?php
2 /**
3  * @file class-gravityview-entry-moderation-merge-tags.php
4  * @package GravityView
5  * @license GPL2+
6  * @author GravityView <[email protected]>
7  * @link https://www.gravitykit.com
8  * @copyright Copyright 2023, Katz Web Services, Inc.
9  *
10  * @since 2.17
11  */
12 
13 /** If this file is called directly, abort. */
14 if ( ! defined( 'ABSPATH' ) ) {
15  die;
16 }
17 
18 /**
19  * Handles approval links
20  *
21  * @since 2.17
22  */
24 
25  /**
26  * The name of the query arg used to pass token information to the approval URL.
27  * Example: ?gv_token=eyJpYXQiOjE2NzM0ODgw[...]
28  */
29  const TOKEN_URL_ARG = 'gv_token';
30 
31  /**
32  * Default value for the expiration modifier.
33  */
35 
36  /**
37  * Default value for the expiration_unit modifier.
38  */
39  const DEFAULT_EXPIRATION_UNIT = 'hours';
40 
41  const FORM_SETTINGS_KEY = 'gravityview_entry_moderation';
42 
43  const NOTICE_URL_ARG = 'gv_approval_link_result';
44 
45  /**
46  * Initialization.
47  */
48  public function __construct() {
49  $this->add_hooks();
50  }
51 
52  /**
53  * Adds actions and filters related to entry approval links
54  *
55  * @return void
56  */
57  private function add_hooks() {
58  add_filter( 'gform_form_settings_fields', array( $this, '_filter_gform_form_settings_fields' ), 10, 2 );
59  add_filter( 'gform_custom_merge_tags', array( $this, '_filter_gform_custom_merge_tags' ), 10, 4 );
60  add_filter( 'gform_replace_merge_tags', array( $this, '_filter_gform_replace_merge_tags' ), 10, 7 );
61 
62  add_action( 'init', array( $this, 'maybe_update_approved' ) );
63  add_action( 'init', array( $this, 'maybe_show_approval_notice' ) );
64  }
65 
66  /**
67  * Filters existing GF Form Settings Fields
68  *
69  * @since 2.17
70  *
71  * @param array $fields Array of sections and settings fields
72  * @param array $form GF Form
73  *
74  * @return array Modified array of sections and settings fields
75  */
76  public function _filter_gform_form_settings_fields( $fields = array(), $form = array() ) {
77 
78  $global_default = gravityview()->plugin->settings->get( 'public_entry_moderation', '0' );
79 
80  $fields['restrictions']['fields'][] = array(
81  'name' => self::FORM_SETTINGS_KEY,
82  'type' => 'radio',
83  'horizontal' => true,
84  // translators: %s is replaced with a setting label
85  'label' => sprintf( esc_html__( 'GravityView - %s', 'gk-gravityview' ), esc_html__( 'Enable Public Entry Moderation', 'gk-gravityview' ) ),
86  'description' => strtr(
87  // translators: Do not translate the words inside the {} curly brackets; they are replaced.
88  __( 'If enabled, adding {public} to {link}entry moderation merge tags{/link} will allow logged-out users to approve or reject entries. If disabled, all entry moderation actions require the user to be logged-in and have the ability to edit the entry.', 'gk-gravityview' ),
89  array(
90  '{public}' => '<code style="font-size: .9em">:public</code>',
91  '{link}' => '<a href="https://docs.gravitykit.com/article/904-entry-moderation-merge-tags" target="_blank" rel="noopener noreferrer">',
92  '{/link}' => '<span class="screen-reader-text"> ' . esc_html__( '(This link opens in a new window.)', 'gk-gravityview' ) . '</span></a>',
93  )
94  ),
95  'choices' => array(
96  array(
97  'label' => _x( 'Enable', 'Setting: On or off', 'gk-gravityview' ),
98  'value' => '1',
99  ),
100  array(
101  'label' => _x( 'Disable', 'Setting: On or off', 'gk-gravityview' ),
102  'value' => '0',
103  ),
104  ),
105  'default_value' => (string) $global_default,
106  );
107 
108  return $fields;
109  }
110 
111  /**
112  * Adds custom merge tags to merge tag options.
113  *
114  * @since 2.17
115  *
116  * @param array $custom_merge_tags
117  * @param int $form_id GF Form ID
118  * @param GF_Field[] $fields Array of fields in the form
119  * @param string $element_id The ID of the input that Merge Tags are being used on
120  *
121  * @return array Modified merge tags
122  */
123  public function _filter_gform_custom_merge_tags( $custom_merge_tags = array(), $form_id = 0, $fields = array(), $element_id = '' ) {
124 
125  $entry_moderation_merge_tags = array(
126  array(
127  'label' => __( 'Moderation: Approve entry link', 'gravityview' ),
128  'tag' => '{gv_approve_entry}',
129  ),
130  array(
131  'label' => __( 'Moderation: Disapprove entry link', 'gravityview' ),
132  'tag' => '{gv_disapprove_entry}',
133  ),
134  array(
135  'label' => __( 'Moderation: Reset entry approval link', 'gravityview' ),
136  'tag' => '{gv_unapprove_entry}',
137  ),
138  );
139 
140  return array_merge( $custom_merge_tags, $entry_moderation_merge_tags );
141  }
142 
143  /**
144  * Matches the merge tag in replacement text for the field.
145  *
146  * @since 2.17
147  *
148  * @see replace_merge_tag Override replace_merge_tag() to handle any matches
149  *
150  * @param string $text Text to replace
151  * @param array $form Gravity Forms form array
152  * @param array $entry Entry array
153  * @param bool $url_encode Whether to URL-encode output
154  *
155  * @return string Original text if {_custom_merge_tag} isn't found. Otherwise, replaced text.
156  */
157  public function _filter_gform_replace_merge_tags( $text, $form = array(), $entry = array(), $url_encode = false, $esc_html = false ) {
158 
159  $matches = array();
160  preg_match_all( '/{gv_((?:dis|un)?approve)_entry:?(?:(\d+)([d|h|m|s]))?:?(public)?}/', $text, $matches, PREG_SET_ORDER );
161 
162  // If there are no matches, return original text
163  if ( empty( $matches ) ) {
164  return $text;
165  }
166 
167  if ( ! isset( $form[ self::FORM_SETTINGS_KEY ] ) ) {
168  $form[ self::FORM_SETTINGS_KEY ] = gravityview()->plugin->settings->get( 'public_entry_moderation' );
169  }
170 
171  return $this->replace_merge_tag( $matches, $text, $form, $entry, $url_encode, $esc_html );
172  }
173 
174  /**
175  * Replaces merge tags
176  *
177  * @since 2.17
178  *
179  * @param array $matches Array of Merge Tag matches found in text by preg_match_all
180  * @param string $text Text to replace
181  * @param array|bool $form Gravity Forms form array. When called inside {@see GFCommon::replace_variables()} (now deprecated), `false`
182  * @param array|bool $entry Entry array. When called inside {@see GFCommon::replace_variables()} (now deprecated), `false`
183  * @param bool $url_encode Whether to URL-encode output
184  * @param bool $esc_html Whether to apply `esc_html()` to output
185  *
186  * @return mixed
187  */
188  protected function replace_merge_tag( $matches = array(), $text = '', $form = array(), $entry = array(), $url_encode = false, $esc_html = false ) {
189 
190  foreach ( $matches as $match ) {
191 
192  $full_tag = $match[0];
193  $action = $match[1];
194  $expiration_value = ! empty( $match[2] ) ? (int) $match[2] : self::DEFAULT_EXPIRATION_VALUE;
195  $expiration_unit = ! empty( $match[3] ) ? $match[3] : self::DEFAULT_EXPIRATION_UNIT;
196  $privacy = isset( $match[4] ) ? $match[4] : 'private';
197 
198  switch ( $expiration_unit ) {
199  case 'd':
200  $expiration_unit = 'days';
201  break;
202  case 'h':
203  default:
204  $expiration_unit = 'hours';
205  break;
206  case 'm':
207  $expiration_unit = 'minutes';
208  break;
209  case 's': // Seconds should really only be used for testing purposes :-) But it's here if you need it.
210  $expiration_unit = 'seconds';
211  break;
212  }
213 
214  if ( false === (bool) \GV\Utils::get( $form, self::FORM_SETTINGS_KEY, false ) ) {
215  $privacy = 'private';
216  }
217 
218  $expiration_timestamp = strtotime( "+{$expiration_value} {$expiration_unit}" );
219  $expiration_seconds = $expiration_timestamp - time();
220 
221  $token = $this->get_token( $action, $expiration_timestamp, $privacy, $entry );
222 
223  if ( ! $token ) {
224  continue;
225  }
226 
227  $link_url = $this->get_link_url( $token, $expiration_seconds, $privacy );
228 
229  $anchor_text = GravityView_Entry_Approval_Status::get_action( $action . 'd' );
230 
231  $link = sprintf( '<a href="%s">%s</a>', esc_url_raw( $link_url ), esc_html( $anchor_text ) );
232 
233  $text = str_replace( $full_tag, $link, $text );
234  }
235 
236  return $text;
237  }
238 
239  /**
240  * Generates a JWT token based on the merge tag parameters.
241  *
242  * @see https://jwt.io
243  *
244  * @since 2.17
245  *
246  * @param string|bool $action Action to be taken by the merge tag.
247  * @param int $expiration_timestamp Timestamp when the token expires.
248  * @param string $privacy Approval link privacy. Accepted values are 'private' or 'public'.
249  * @param array $entry Entry array.
250  *
251  * @return string Encrypted token.
252  */
253  protected function get_token( $action = false, $expiration_timestamp = 0, $privacy = 'private', $entry = array() ) {
254 
255  if ( ! $action || ! $entry['id'] ) {
256  return false;
257  }
258 
259  if ( ! $expiration_timestamp ) {
260  return false;
261  }
262 
263  if ( ! $privacy ) {
264  $privacy = 'private';
265  }
266 
267  $approval_status = $this->get_approval_status( $action );
268 
269  if ( ! $approval_status ) {
270  return false;
271  }
272 
273  $jti = uniqid();
274  $expiration_seconds = $expiration_timestamp - time();
275 
276  $scopes = array(
277  'entry_id' => $entry['id'],
278  'approval_status' => $approval_status,
279  'expiration_seconds' => $expiration_seconds,
280  'privacy' => $privacy,
281  );
282 
283  $token_array = array(
284  'iat' => time(),
285  'exp' => $expiration_timestamp,
286  'scopes' => $scopes,
287  'jti' => $jti,
288  );
289 
290  $token = rawurlencode( base64_encode( json_encode( $token_array ) ) );
291 
292  $secret = wp_salt( 'nonce' );
293 
294  $sig = hash_hmac( 'sha256', $token, $secret );
295 
296  $token .= '.' . $sig;
297 
298  return $token;
299  }
300 
301  /**
302  * Returns an approval status based on the provided action
303  *
304  * @since 2.17
305  *
306  * @param string|bool $action
307  *
308  * @return int Value of respective approval status
309  */
310  protected function get_approval_status( $action = false ) {
311 
312  if ( ! $action ) {
313  return false;
314  }
315 
316  $key = GravityView_Entry_Approval_Status::get_key( $action . 'd' );
318 
319  return $values[ $key ];
320  }
321 
322  /**
323  * Generates an approval link URL
324  *
325  * @since 2.17
326  *
327  * @param string|bool $token
328  * @param string $privacy Approval link privacy. Accepted values are 'private' or 'public'.
329  *
330  * @return string Approval link URL
331  */
332  protected function get_link_url( $token = false, $expiration_seconds = DAY_IN_SECONDS, $privacy = 'private' ) {
333 
334  if ( 'public' === $privacy ) {
335  $base_url = home_url( '/' );
336  } else {
337  $base_url = admin_url( 'admin.php?page=gf_entries' );
338  }
339 
340  $query_args = array();
341 
342  if ( ! empty( $token ) ) {
343  $query_args[ self::TOKEN_URL_ARG ] = $token;
344  }
345 
346  if ( 'private' === $privacy && DAY_IN_SECONDS >= (int) $expiration_seconds ) {
347  $query_args['nonce'] = wp_create_nonce( self::TOKEN_URL_ARG );
348  }
349 
350  return add_query_arg( $query_args, $base_url );
351  }
352 
353  /**
354  * Checks page load for approval link token then maybe process it
355  *
356  * @since 2.17
357  *
358  * Expects a $_GET request with the following $_GET keys and values:
359  *
360  * @return void
361  * @global array $_GET {
362  * @type string $gv_token Approval link token
363  * @type string $nonce (optional) Nonce hash to be validated. Only available if $expiration_seconds is smaller than DAY_IN_SECONDS.
364  * }
365  *
366  */
367  public function maybe_update_approved() {
368 
369  $token_string = GV\Utils::_GET( self::TOKEN_URL_ARG );
370 
371  if ( ! $token_string ) {
372  return;
373  }
374 
375  $token = $this->decode_token( $token_string );
376 
377  if ( is_wp_error( $token ) ) {
378 
379  gravityview()->log->error( 'Decoding the entry approval token failed.', array( 'data' => $token ) );
380 
381  wp_die( sprintf( __( 'Entry moderation failed: %s', 'gravityview' ), $token->get_error_message() ) );
382  }
383 
384  // Ensure the token is formatted properly.
385  $is_valid_token = $this->is_token_valid( $token );
386 
387  if ( is_wp_error( $is_valid_token ) ) {
388 
389  gravityview()->log->error( 'Validating the entry approval token failed.', array( 'data' => $is_valid_token ) );
390 
391  wp_die( sprintf( __( 'Entry moderation failed: %s', 'gravityview' ), $is_valid_token->get_error_message() ) );
392  }
393 
394  $is_request_valid = $this->is_request_valid( $token );
395 
396  if ( is_wp_error( $is_request_valid ) ) {
397 
398  gravityview()->log->error( 'Validating the entry approval token failed.', array( 'data' => $is_request_valid ) );
399 
400  wp_die( sprintf( __( 'Entry moderation failed: %s', 'gravityview' ), $is_request_valid->get_error_message() ) );
401  }
402 
403  $scopes = $token['scopes'];
404 
405  $entry_id = $scopes['entry_id'];
406  $approval_status = $scopes['approval_status'];
407 
408  $entry = GFAPI::get_entry( $entry_id );
409 
410  if ( is_wp_error( $entry ) ) {
411  gravityview()->log->error( 'Entry moderation failed: the entry was not found.', array( 'data' => $entry ) );
412 
413  wp_die( $entry->get_error_message() );
414  }
415 
416  $form_id = $entry['form_id'];
417 
418  if ( 'private' === $scopes['privacy'] ) {
419  $return_url = admin_url( '/admin.php?page=gf_entries&s=' . $entry_id . '&field_id=entry_id&operator=is&id=' . $form_id );
420  } else {
421  $return_url = home_url( '/' );
422  }
423 
424  // Valid status
425  if ( ! GravityView_Entry_Approval_Status::is_valid( $approval_status ) ) {
426 
427  gravityview()->log->error( 'Invalid approval status', array( 'data' => $scopes ) );
428 
429  wp_safe_redirect( add_query_arg( array( self::NOTICE_URL_ARG => 'error' ), $return_url ) );
430 
431  exit;
432  }
433 
434  if ( empty( $entry_id ) || empty( $form_id ) ) {
435 
436  gravityview()->log->error( 'entry_id or form_id are empty.', array( 'data' => $scopes ) );
437 
438  wp_safe_redirect( add_query_arg( array( self::NOTICE_URL_ARG => 'error' ), $return_url ) );
439 
440  exit;
441  }
442 
443  if ( 'private' === $scopes['privacy'] && ! GVCommon::has_cap( 'gravityview_moderate_entries', $entry_id ) ) {
444 
445  gravityview()->log->error( 'User does not have the `gravityview_moderate_entries` capability.' );
446 
447  wp_safe_redirect( add_query_arg( array( self::NOTICE_URL_ARG => 'error' ), $return_url ) );
448 
449  exit;
450  }
451 
452  $this->update_approved( $entry_id, $approval_status, $form_id, $scopes, $return_url );
453  }
454 
455  /**
456  * Verifies the token
457  *
458  * @since 2.17
459  *
460  * @param array $token
461  *
462  * @return bool|WP_Error
463  */
464  protected function is_request_valid( $token ) {
465 
466  if ( 'private' === $token['scopes']['privacy'] && ! is_user_logged_in() ) {
467  return new WP_Error( 'user_not_logged_in', __( 'You are not allowed to perform this operation.', 'gravityview' ) );
468  }
469 
470  if ( $token['exp'] < time() ) {
471  gravityview()->log->error( 'The entry moderation link expired.', array( 'data' => $is_valid_token ) );
472 
473  return new WP_Error( 'link_expired', esc_html__( 'The link has expired.', 'gk-gravityview' ) );
474  }
475 
476  // Since nonces are only valid for 24 hours, we only check the nonce if the token is valid for less than 24 hours.
477  if ( 'private' === $token['scopes']['privacy'] && DAY_IN_SECONDS >= $token['scopes']['expiration_seconds'] ) {
478 
479  if ( ! isset( $_REQUEST['nonce'] ) ) {
480  gravityview()->log->error( 'Entry moderation failed: No nonce was set for entry approval.' );
481 
482  return new WP_Error( 'missing_nonce', esc_html__( 'The link is invalid.', 'gk-gravityview' ) );
483  }
484 
485  $nonce_validation = wp_verify_nonce( GV\Utils::_GET( 'nonce' ), self::TOKEN_URL_ARG );
486 
487  if ( ! $nonce_validation ) {
488  gravityview()->log->error( 'Entry moderation failed: Nonce was invalid.', array( 'data' => $nonce_validation ) );
489 
490  return new WP_Error( 'invalid_nonce', esc_html__( 'The link has expired.', 'gk-gravityview' ) );
491  }
492  }
493 
494  return true;
495  }
496 
497  /**
498  * Checks page load for approval link result then maybe show notice
499  *
500  * @since 2.17
501  *
502  * Expects a $_GET request with the following $_GET keys and values:
503  *
504  * @return void
505  * @global array $_GET {
506  * @type string $gv_approval_link_result Approval link result
507  * }
508  *
509  */
510  public function maybe_show_approval_notice() {
511 
512  $result = GV\Utils::_GET( self::NOTICE_URL_ARG );
513  $approval_status = \GV\Utils::_GET( 'approval_status' );
514  $entry_id = \GV\Utils::_GET( 'entry_id' );
515 
516  if ( ! $result || ! $approval_status || ! $entry_id ) {
517  return;
518  }
519 
520  $approval_label = GravityView_Entry_Approval_Status::get_label( (int) $approval_status );
521  $approval_label = mb_strtolower( $approval_label );
522 
523  if ( 'success' === $result ) {
524 
525  // translators: Do not translate the words inside the {} curly brackets; they are replaced.
526  $message = esc_html__( 'Success: Entry #{entry_id} has been {approval_label}.', 'gk-gravityview' );
527 
528  $css_class = 'updated';
529  } else {
530 
531  // translators: Do not translate the words inside the {} curly brackets; they are replaced.
532  $message = esc_html__( 'There was an error updating entry #{entry_id}.', 'gk-gravityview' );
533 
534  $css_class = 'error';
535  }
536 
537  $message = strtr( $message, array(
538  '{entry_id}' => esc_html( $entry_id ),
539  '{approval_label}' => esc_html( $approval_label ),
540  ) );
541 
542  $message = \GVCommon::generate_notice( wpautop( $message ), $css_class );
543 
544  if ( is_admin() ) {
545  echo $message;
546  } else {
547  wp_die( $message );
548  }
549  }
550 
551  /**
552  * Decodes received token to its original form.
553  *
554  * @since 2.17
555  *
556  * @param string|bool $token
557  *
558  * @return array|WP_Error Original scopes or WP Error object
559  */
560  protected function decode_token( $token = false ) {
561 
562  if ( ! $token ) {
563  return new WP_Error( 'missing_token', __( 'Invalid security token.', 'gk-gravityview' ) );
564  }
565 
566  $parts = explode( '.', $token );
567 
568  if ( count( $parts ) < 2 ) {
569  return new WP_Error( 'missing_period', __( 'Invalid security token.', 'gk-gravityview' ) );
570  }
571 
572  /**
573  * @param string $body_64 $parts[0]
574  * @param string $sig $parts[1]
575  */
576  list( $body_64, $sig ) = $parts;
577 
578  if ( empty( $sig ) ) {
579  return new WP_Error( 'approve_link_no_signature', esc_html__( 'The link is invalid.', 'gk-gravityview' ) );
580  }
581 
582  $secret = wp_salt( 'nonce' );
583  $verification_sig = hash_hmac( 'sha256', $body_64, $secret );
584  $verification_sig2 = hash_hmac( 'sha256', rawurlencode( $body_64 ), $secret );
585 
586  if ( ! hash_equals( $sig, $verification_sig ) && ! hash_equals( $sig, $verification_sig2 ) ) {
587  return new WP_Error( 'approve_link_failed_signature_verification', esc_html__( 'The link is invalid.', 'gk-gravityview' ) );
588  }
589 
590  $body_json = base64_decode( $body_64 );
591  $decoded_token = json_decode( $body_json, true );
592 
593  if ( empty( $body_json ) || empty( $decoded_token ) ) {
594  $decoded_token = base64_decode( urldecode( $body_64 ) );
595  }
596 
597  if ( empty( $decoded_token ) ) {
598  return new WP_Error( 'approve_link_failed_base64_decode', esc_html__( 'The link is invalid.', 'gk-gravityview' ) );
599  }
600 
601  return $decoded_token;
602  }
603 
604  /**
605  * Validates an approval token
606  *
607  * @since 2.17
608  *
609  * @param array $token
610  *
611  * @return true|WP_Error Token is valid or there was an error.
612  */
613  protected function is_token_valid( array $token ) {
614 
615  $required_keys = array(
616  'jti',
617  'exp',
618  'scopes',
619  );
620 
621  foreach ( $required_keys as $required_key ) {
622  if ( ! isset( $token[ $required_key ] ) ) {
623  return new WP_Error( 'approve_link_no_' . $required_key, esc_html__( 'The link is invalid.', 'gk-gravityview' ) );
624  }
625  }
626 
627  $required_scopes = array(
628  'expiration_seconds',
629  'privacy',
630  'entry_id',
631  'approval_status',
632  );
633 
634  foreach ( $required_scopes as $required_scope ) {
635  if ( ! isset( $token['scopes'][ $required_scope ] ) ) {
636  return new WP_Error( 'approve_link_no_' . $required_scope . '_scope', esc_html__( 'The link is invalid.', 'gk-gravityview' ) );
637  }
638  }
639 
640  return true;
641  }
642 
643  /**
644  * Updates the entry approval status and redirects to $return_url.
645  *
646  * @param int $entry_id Entry ID.
647  * @param int $approval_status Approval status.
648  * @param int $form_id Form ID.
649  * @param array $scopes Token scopes to be passed to the return URL and used in {@see maybe_show_approval_notice()}.
650  * @param string $return_url Url to redirect to once moderation happens.
651  *
652  * @return void
653  */
654  protected function update_approved( $entry_id, $approval_status, $form_id, $scopes, $return_url ) {
655 
656  $result = GravityView_Entry_Approval::update_approved( $entry_id, $approval_status, $form_id );
657 
658  $query_args = $scopes;
659 
660  $query_args[ self::NOTICE_URL_ARG ] = $result ? 'success' : 'error';
661 
662  $return_url = add_query_arg( $query_args, $return_url );
663 
664  wp_safe_redirect( esc_url_raw( $return_url ) );
665 
666  exit;
667  }
668 }
669 
_filter_gform_replace_merge_tags( $text, $form=array(), $entry=array(), $url_encode=false, $esc_html=false)
Matches the merge tag in replacement text for the field.
is_request_valid( $token)
Verifies the token.
static get_values()
Get the status values as an array.
static _GET( $name, $default=null)
Grab a value from the _GET superglobal or default.
replace_merge_tag( $matches=array(), $text='', $form=array(), $entry=array(), $url_encode=false, $esc_html=false)
Replaces merge tags.
_filter_gform_form_settings_fields( $fields=array(), $form=array())
Filters existing GF Form Settings Fields.
_filter_gform_custom_merge_tags( $custom_merge_tags=array(), $form_id=0, $fields=array(), $element_id='')
Adds custom merge tags to merge tag options.
maybe_update_approved()
Checks page load for approval link token then maybe process it.
update_approved( $entry_id, $approval_status, $form_id, $scopes, $return_url)
Updates the entry approval status and redirects to $return_url.
maybe_show_approval_notice()
Checks page load for approval link result then maybe show notice.
static generate_notice( $notice, $class='', $cap='', $object_id=null)
Display updated/error notice.
const NOTICE_URL_ARG
get_approval_status( $action=false)
Returns an approval status based on the provided action.
if( $add_query_args) $link
static get_action( $value_or_key)
Get the label for a specific approval value.
static get_key( $value)
Get the status key for a value.
new GravityView_Entry_Approval_Merge_Tags
if(gravityview() ->plugin->is_GF_25()) $form
If this file is called directly, abort.
decode_token( $token=false)
Decodes received token to its original form.
static is_valid( $value=NULL)
Check whether the passed value is one of the defined values for entry approval.
const DEFAULT_EXPIRATION_UNIT
Default value for the expiration_unit modifier.
static update_approved( $entry_id=0, $approved=2, $form_id=0, $approvedcolumn=0)
update_approved function.
is_token_valid(array $token)
Validates an approval token.
get_token( $action=false, $expiration_timestamp=0, $privacy='private', $entry=array())
Generates a JWT token based on the merge tag parameters.
const FORM_SETTINGS_KEY
const DEFAULT_EXPIRATION_VALUE
Default value for the expiration modifier.
if(empty( $created_by)) $form_id
__construct()
Initialization.
get_link_url( $token=false, $expiration_seconds=DAY_IN_SECONDS, $privacy='private')
Generates an approval link URL.
gravityview()
The main GravityView wrapper function.
add_hooks()
Adds actions and filters related to entry approval links.
static has_cap( $caps='', $object_id=null, $user_id=null)
Alias of GravityView_Roles_Capabilities::has_cap()
$entry
Definition: notes.php:27
const TOKEN_URL_ARG
The name of the query arg used to pass token information to the approval URL.
static get_label( $value_or_key)
Get the label for a specific approval value.