GravityView  2.9.2
The best, easiest way to display Gravity Forms entries on your website.
class-common.php
Go to the documentation of this file.
1 <?php
2 /**
3  * Set of common functions to separate main plugin from Gravity Forms API and other cross-plugin methods
4  *
5  * @package GravityView
6  * @license GPL2+
7  * @author GravityView <hello@gravityview.co>
8  * @link http://gravityview.co
9  * @copyright Copyright 2014, Katz Web Services, Inc.
10  *
11  * @since 1.5.2
12  */
13 
14 /** If this file is called directly, abort. */
15 if ( ! defined( 'ABSPATH' ) ) {
16  die;
17 }
18 
19 class GVCommon {
20 
21  /**
22  * Returns the form object for a given Form ID.
23  *
24  * @param mixed $form_id
25  * @return array|false Array: Form object returned from Gravity Forms; False: no form ID specified or Gravity Forms isn't active.
26  */
27  public static function get_form( $form_id ) {
28  if ( empty( $form_id ) ) {
29  return false;
30  }
31 
32  // Only get_form_meta is cached. ::facepalm::
33  if ( class_exists( 'GFFormsModel' ) ) {
34  return GFFormsModel::get_form_meta( $form_id );
35  }
36 
37  if ( class_exists( 'GFAPI' ) ) {
38  return GFAPI::get_form( $form_id );
39  }
40 
41  return false;
42  }
43 
44  /**
45  * Alias of GravityView_Roles_Capabilities::has_cap()
46  *
47  * @since 1.15
48  *
49  * @see GravityView_Roles_Capabilities::has_cap()
50  *
51  * @param string|array $caps Single capability or array of capabilities
52  * @param int $object_id (optional) Parameter can be used to check for capabilities against a specific object, such as a post or user
53  * @param int|null $user_id (optional) Check the capabilities for a user who is not necessarily the currently logged-in user
54  *
55  * @return bool True: user has at least one passed capability; False: user does not have any defined capabilities
56  */
57  public static function has_cap( $caps = '', $object_id = null, $user_id = null ) {
58  return GravityView_Roles_Capabilities::has_cap( $caps, $object_id, $user_id );
59  }
60 
61  /**
62  * Return a Gravity Forms field array, whether using GF 1.9 or not
63  *
64  * @since 1.7
65  *
66  * @param array|GF_Fields $field Gravity Forms field or array
67  * @return array Array version of $field
68  */
69  public static function get_field_array( $field ) {
70 
71  if ( class_exists( 'GF_Fields' ) ) {
72 
73  $field_object = GF_Fields::create( $field );
74 
75  // Convert the field object in 1.9 to an array for backward compatibility
76  $field_array = get_object_vars( $field_object );
77 
78  } else {
79  $field_array = $field;
80  }
81 
82  return $field_array;
83  }
84 
85  /**
86  * Get all existing Views
87  *
88  * @since 1.5.4 Added $args array
89  *
90  * @param array $args Pass custom array of args, formatted as if for `get_posts()`
91  *
92  * @return WP_Post[] Array of Views as `WP_Post`. Empty array if none found.
93  */
94  public static function get_all_views( $args = array() ) {
95 
96  $default_params = array(
97  'post_type' => 'gravityview',
98  'posts_per_page' => -1,
99  'post_status' => 'publish',
100  );
101 
102  $params = wp_parse_args( $args, $default_params );
103 
104  /**
105  * @filter `gravityview/get_all_views/params` Modify the parameters sent to get all views.
106  * @param[in,out] array $params Array of parameters to pass to `get_posts()`
107  */
108  $views_params = apply_filters( 'gravityview/get_all_views/params', $params );
109 
110  $views = get_posts( $views_params );
111 
112  return $views;
113  }
114 
115 
116  /**
117  * Get the form array for an entry based only on the entry ID
118  * @param int|string $entry_slug Entry slug
119  * @return array|false Array: Form object returned from Gravity Forms; False: form doesn't exist, or $entry didn't exist or $entry didn't specify form ID
120  */
121  public static function get_form_from_entry_id( $entry_slug ) {
122 
123  $entry = self::get_entry( $entry_slug, true, false );
124 
125  $form = false;
126 
127  if( $entry ) {
128  $form = GFAPI::get_form( $entry['form_id'] );
129  }
130 
131  return $form;
132  }
133 
134  /**
135  * Check whether a form has product fields
136  *
137  * @since 1.16
138  * @since 1.20 Refactored the field types to get_product_field_types() method
139  *
140  * @param array $form Gravity Forms form array
141  *
142  * @return bool|GF_Field[]
143  */
144  public static function has_product_field( $form = array() ) {
145 
146  $product_fields = self::get_product_field_types();
147 
148  $fields = GFAPI::get_fields_by_type( $form, $product_fields );
149 
150  return empty( $fields ) ? false : $fields;
151  }
152 
153  /**
154  * Return array of product field types
155  *
156  * Modify the value using the `gform_product_field_types` filter
157  *
158  * @since 1.20
159  *
160  * @return array
161  */
162  public static function get_product_field_types() {
163 
164  $product_fields = apply_filters( 'gform_product_field_types', array( 'option', 'quantity', 'product', 'total', 'shipping', 'calculation', 'price', 'hiddenproduct', 'singleproduct', 'singleshipping' ) );
165 
166  return $product_fields;
167  }
168 
169  /**
170  * Check if an entry has transaction data
171  *
172  * Checks the following keys to see if they are set: 'payment_status', 'payment_date', 'transaction_id', 'payment_amount', 'payment_method'
173  *
174  * @since 1.20
175  *
176  * @param array $entry Gravity Forms entry array
177  *
178  * @return bool True: Entry has metadata suggesting it has communicated with a payment gateway; False: it does not have that data.
179  */
180  public static function entry_has_transaction_data( $entry = array() ) {
181 
182  if ( ! is_array( $entry ) ) {
183  return false;
184  }
185 
186  $has_transaction_data = false;
187 
188  $payment_meta = array( 'payment_status', 'payment_date', 'transaction_id', 'payment_amount', 'payment_method' );
189 
190  foreach ( $payment_meta as $meta ) {
191 
192  $has_transaction_data = \GV\Utils::get( $entry, $meta, false );
193 
194  if ( is_numeric( $has_transaction_data ) && ( ! floatval( $has_transaction_data ) > 0 ) ) {
195  $has_transaction_data = false;
196  continue;
197  }
198 
199  if ( ! empty( $has_transaction_data ) ) {
200  break;
201  }
202  }
203 
204  return (bool) $has_transaction_data;
205  }
206 
207  /**
208  * Get the entry ID from the entry slug, which may or may not be the entry ID
209  *
210  * @since 1.5.2
211  * @param string $slug The entry slug, as returned by GravityView_API::get_entry_slug()
212  * @return int|null The entry ID, if exists; `NULL` if not
213  */
214  public static function get_entry_id_from_slug( $slug ) {
215  global $wpdb;
216 
217  $search_criteria = array(
218  'field_filters' => array(
219  array(
220  'key' => 'gravityview_unique_id', // Search the meta values
221  'value' => $slug,
222  'operator' => 'is',
223  'type' => 'meta',
224  ),
225  )
226  );
227 
228  // Limit to one for speed
229  $paging = array(
230  'page_size' => 1,
231  );
232 
233  /**
234  * @filter `gravityview/common/get_entry_id_from_slug/form_id` The form ID used to get the custom entry ID. Change this to avoid collisions with data from other forms with the same values and the same field ID.
235  * @since 1.17.2
236  * @param int $form_id ID of the form to search. Default: `0` (searches all forms)
237  */
238  $form_id = apply_filters( 'gravityview/common/get_entry_id_from_slug/form_id', 0 );
239 
240  $results = GFAPI::get_entries( intval( $form_id ), $search_criteria, null, $paging );
241 
242  $result = ( ! empty( $results ) && ! empty( $results[0]['id'] ) ) ? $results[0]['id'] : null;
243 
244  return $result;
245  }
246 
247  /**
248  * Alias of GFAPI::get_forms()
249  *
250  * @see GFAPI::get_forms()
251  *
252  * @since 1.19 Allow "any" $active status option
253  * @since 2.7.2 Allow sorting forms using wp_list_sort()
254  *
255  * @param bool|string $active Status of forms. Use `any` to get array of forms with any status. Default: `true`
256  * @param bool $trash Include forms in trash? Default: `false`
257  * @param string|array $order_by Optional. Either the field name to order by or an array of multiple orderby fields as $orderby => $order.
258  * @param string $order Optional. Either 'ASC' or 'DESC'. Only used if $orderby is a string.
259  *
260  * @return array Empty array if GFAPI class isn't available or no forms. Otherwise, the array of Forms
261  */
262  public static function get_forms( $active = true, $trash = false, $order_by = 'id', $order = 'ASC' ) {
263  $forms = array();
264  if ( ! class_exists( 'GFAPI' ) ) {
265  return array();
266  }
267 
268  if( 'any' === $active ) {
269  $active_forms = GFAPI::get_forms( true, $trash );
270  $inactive_forms = GFAPI::get_forms( false, $trash );
271  $forms = array_merge( array_filter( $active_forms ), array_filter( $inactive_forms ) );
272  } else {
273  $forms = GFAPI::get_forms( $active, $trash );
274  }
275 
276  $forms = wp_list_sort( $forms, $order_by, $order, true );
277 
278  return $forms;
279  }
280 
281  /**
282  * Return array of fields' id and label, for a given Form ID
283  *
284  * @param string|array $form_id (default: '') or $form object
285  * @param bool $add_default_properties
286  * @param bool $include_parent_field
287  * @return array
288  */
289  public static function get_form_fields( $form = '', $add_default_properties = false, $include_parent_field = true ) {
290 
291  if ( ! is_array( $form ) ) {
292  $form = self::get_form( $form );
293  }
294 
295  $fields = array();
296  $has_product_fields = false;
297  $has_post_fields = false;
298 
299  if ( $form ) {
300  foreach ( $form['fields'] as $field ) {
301  if ( $include_parent_field || empty( $field['inputs'] ) ) {
302  $fields["{$field['id']}"] = array(
303  'label' => \GV\Utils::get( $field, 'label' ),
304  'parent' => null,
305  'type' => \GV\Utils::get( $field, 'type' ),
306  'adminLabel' => \GV\Utils::get( $field, 'adminLabel' ),
307  'adminOnly' => \GV\Utils::get( $field, 'adminOnly' ),
308  );
309  }
310 
311  if ( $add_default_properties && ! empty( $field['inputs'] ) ) {
312  foreach ( $field['inputs'] as $input ) {
313 
314  if( ! empty( $input['isHidden'] ) ) {
315  continue;
316  }
317 
318  /**
319  * @hack
320  * In case of email/email confirmation, the input for email has the same id as the parent field
321  */
322  if( 'email' === $field['type'] && false === strpos( $input['id'], '.' ) ) {
323  continue;
324  }
325  $fields["{$input['id']}"] = array(
326  'label' => \GV\Utils::get( $input, 'label' ),
327  'customLabel' => \GV\Utils::get( $input, 'customLabel' ),
328  'parent' => $field,
329  'type' => \GV\Utils::get( $field, 'type' ),
330  'adminLabel' => \GV\Utils::get( $field, 'adminLabel' ),
331  'adminOnly' => \GV\Utils::get( $field, 'adminOnly' ),
332  );
333  }
334  }
335 
336 
337  if( GFCommon::is_product_field( $field['type'] ) ){
338  $has_product_fields = true;
339  }
340 
341  if ( GFCommon::is_post_field( $field ) ) {
342  $has_post_fields = true;
343  }
344  }
345  }
346 
347  /**
348  * @since 1.7
349  */
350  if ( $has_post_fields ) {
351  $fields['post_id'] = array(
352  'label' => __( 'Post ID', 'gravityview' ),
353  'type' => 'post_id',
354  );
355  }
356 
357  if ( $has_product_fields ) {
358 
359  $payment_fields = GravityView_Fields::get_all( 'pricing' );
360 
361  foreach ( $payment_fields as $payment_field ) {
362 
363  // Either the field exists ($fields['shipping']) or the form explicitly contains a `shipping` field with numeric key
364  if( isset( $fields["{$payment_field->name}"] ) || GFCommon::get_fields_by_type( $form, $payment_field->name ) ) {
365  continue;
366  }
367 
368  $fields["{$payment_field->name}"] = array(
369  'label' => $payment_field->label,
370  'desc' => $payment_field->description,
371  'type' => $payment_field->name,
372  );
373  }
374  }
375 
376  /**
377  * @filter `gravityview/common/get_form_fields` Modify the form fields shown in the Add Field field picker.
378  * @since 1.17
379  * @param array $fields Associative array of fields, with keys as field type, values an array with the following keys: (string) `label` (required), (string) `type` (required), `desc`, (string) `customLabel`, (GF_Field) `parent`, (string) `adminLabel`, (bool)`adminOnly`
380  * @param array $form GF Form array
381  * @param bool $include_parent_field Whether to include the parent field when getting a field with inputs
382  */
383  $fields = apply_filters( 'gravityview/common/get_form_fields', $fields, $form, $include_parent_field );
384 
385  return $fields;
386 
387  }
388 
389  /**
390  * get extra fields from entry meta
391  * @param string $form_id (default: '')
392  * @return array
393  */
394  public static function get_entry_meta( $form_id, $only_default_column = true ) {
395 
396  $extra_fields = GFFormsModel::get_entry_meta( $form_id );
397 
398  $fields = array();
399 
400  foreach ( $extra_fields as $key => $field ){
401  if ( ! empty( $only_default_column ) && ! empty( $field['is_default_column'] ) ) {
402  $fields[ $key ] = array( 'label' => $field['label'], 'type' => 'entry_meta' );
403  }
404  }
405 
406  return $fields;
407  }
408 
409 
410  /**
411  * Wrapper for the Gravity Forms GFFormsModel::search_lead_ids() method
412  *
413  * @see GFEntryList::leads_page()
414  * @param int $form_id ID of the Gravity Forms form
415  * @since 1.1.6
416  * @return array|void Array of entry IDs. Void if Gravity Forms isn't active.
417  */
418  public static function get_entry_ids( $form_id, $search_criteria = array() ) {
419 
420  if ( ! class_exists( 'GFFormsModel' ) ) {
421  return;
422  }
423 
424  return GFFormsModel::search_lead_ids( $form_id, $search_criteria );
425  }
426 
427  /**
428  * Calculates the Search Criteria used on the self::get_entries / self::get_entry methods
429  *
430  * @since 1.7.4
431  *
432  * @param array $passed_criteria array Input Criteria (search_criteria, sorting, paging)
433  * @param array $form_ids array Gravity Forms form IDs
434  * @return array
435  */
436  public static function calculate_get_entries_criteria( $passed_criteria = array(), $form_ids = array() ) {
437 
438  $search_criteria_defaults = array(
439  'search_criteria' => null,
440  'sorting' => null,
441  'paging' => null,
442  'cache' => (isset( $passed_criteria['cache'] ) ? (bool) $passed_criteria['cache'] : true),
443  'context_view_id' => null,
444  );
445 
446  $criteria = wp_parse_args( $passed_criteria, $search_criteria_defaults );
447 
448  if ( ! empty( $criteria['search_criteria']['field_filters'] ) && is_array( $criteria['search_criteria']['field_filters'] ) ) {
449  foreach ( $criteria['search_criteria']['field_filters'] as &$filter ) {
450 
451  if ( ! is_array( $filter ) ) {
452  continue;
453  }
454 
455  // By default, we want searches to be wildcard for each field.
456  $filter['operator'] = empty( $filter['operator'] ) ? 'contains' : $filter['operator'];
457 
458  /**
459  * @filter `gravityview_search_operator` Modify the search operator for the field (contains, is, isnot, etc)
460  * @param string $operator Existing search operator
461  * @param array $filter array with `key`, `value`, `operator`, `type` keys
462  */
463  $filter['operator'] = apply_filters( 'gravityview_search_operator', $filter['operator'], $filter );
464  }
465 
466  // don't send just the [mode] without any field filter.
467  if( count( $criteria['search_criteria']['field_filters'] ) === 1 && array_key_exists( 'mode' , $criteria['search_criteria']['field_filters'] ) ) {
468  unset( $criteria['search_criteria']['field_filters']['mode'] );
469  }
470 
471  }
472 
473 
474 
475  /**
476  * Prepare date formats to be in Gravity Forms DB format;
477  * $passed_criteria may include date formats incompatible with Gravity Forms.
478  */
479  foreach ( array('start_date', 'end_date' ) as $key ) {
480 
481  if ( ! empty( $criteria['search_criteria'][ $key ] ) ) {
482 
483  // Use date_create instead of new DateTime so it returns false if invalid date format.
484  $date = date_create( $criteria['search_criteria'][ $key ] );
485 
486  if ( $date ) {
487  // Gravity Forms wants dates in the `Y-m-d H:i:s` format.
488  $criteria['search_criteria'][ $key ] = $date->format( 'Y-m-d H:i:s' );
489  } else {
490  gravityview()->log->error( '{key} Date format not valid:', array( 'key' => $key, $criteria['search_criteria'][ $key ] ) );
491 
492  // If it's an invalid date, unset it. Gravity Forms freaks out otherwise.
493  unset( $criteria['search_criteria'][ $key ] );
494  }
495  }
496  }
497 
498  if ( empty( $criteria['context_view_id'] ) ) {
499  // Calculate the context view id and send it to the advanced filter
500  if ( GravityView_frontend::getInstance()->getSingleEntry() ) {
501  $criteria['context_view_id'] = GravityView_frontend::getInstance()->get_context_view_id();
502  } else if ( class_exists( 'GravityView_View_Data' ) && GravityView_View_Data::getInstance() && GravityView_View_Data::getInstance()->has_multiple_views() ) {
503  $criteria['context_view_id'] = GravityView_frontend::getInstance()->get_context_view_id();
504  } else if ( 'delete' === GFForms::get( 'action' ) ) {
505  $criteria['context_view_id'] = isset( $_GET['view_id'] ) ? intval( $_GET['view_id'] ) : null;
506  }
507  }
508 
509  /**
510  * @filter `gravityview_search_criteria` Apply final criteria filter (Used by the Advanced Filter extension)
511  * @param array $criteria Search criteria used by GravityView
512  * @param array $form_ids Forms to search
513  * @param int $view_id ID of the view being used to search
514  */
515  $criteria = apply_filters( 'gravityview_search_criteria', $criteria, $form_ids, $criteria['context_view_id'] );
516 
517  return (array)$criteria;
518  }
519 
520 
521  /**
522  * Retrieve entries given search, sort, paging criteria
523  *
524  * @see GFAPI::get_entries()
525  * @see GFFormsModel::get_field_filters_where()
526  * @param int|array $form_ids The ID of the form or an array IDs of the Forms. Zero for all forms.
527  * @param mixed $passed_criteria (default: null)
528  * @param mixed &$total Optional. An output parameter containing the total number of entries. Pass a non-null value to generate the total count. (default: null)
529  *
530  * @deprecated See \GV\View::get_entries.
531  *
532  * @return mixed False: Error fetching entries. Array: Multi-dimensional array of Gravity Forms entry arrays
533  */
534  public static function get_entries( $form_ids = null, $passed_criteria = null, &$total = null ) {
535 
536  gravityview()->log->notice( '\GVCommon::get_entries is deprecated. Use \GV\View::get_entries instead.' );
537 
538  // Filter the criteria before query (includes Adv Filter)
539  $criteria = self::calculate_get_entries_criteria( $passed_criteria, $form_ids );
540 
541  gravityview()->log->debug( '[gravityview_get_entries] Final Parameters', array( 'data' => $criteria ) );
542 
543  // Return value
544  $return = null;
545 
546  /** Reduce # of database calls */
547  add_filter( 'gform_is_encrypted_field', '__return_false' );
548 
549  if ( ! empty( $criteria['cache'] ) ) {
550 
551  $Cache = new GravityView_Cache( $form_ids, $criteria );
552 
553  if ( $entries = $Cache->get() ) {
554 
555  // Still update the total count when using cached results
556  if ( ! is_null( $total ) ) {
557  $total = GFAPI::count_entries( $form_ids, $criteria['search_criteria'] );
558  }
559 
560  $return = $entries;
561  }
562  }
563 
564  if ( is_null( $return ) && class_exists( 'GFAPI' ) && ( is_numeric( $form_ids ) || is_array( $form_ids ) ) ) {
565 
566  /**
567  * @filter `gravityview_pre_get_entries` Define entries to be used before GFAPI::get_entries() is called
568  * @since 1.14
569  * @param null $return If you want to override GFAPI::get_entries() and define entries yourself, tap in here.
570  * @param array $criteria The final search criteria used to generate the request to `GFAPI::get_entries()`
571  * @param array $passed_criteria The original search criteria passed to `GVCommon::get_entries()`
572  * @param int|null $total Optional. An output parameter containing the total number of entries. Pass a non-null value to generate
573  * @since 2.1 The $total parameter can now be overriden by reference.
574  * @deprecated
575  */
576  $entries = apply_filters_ref_array( 'gravityview_before_get_entries', array( null, $criteria, $passed_criteria, &$total ) );
577 
578  // No entries returned from gravityview_before_get_entries
579  if( is_null( $entries ) ) {
580 
581  $entries = GFAPI::get_entries( $form_ids, $criteria['search_criteria'], $criteria['sorting'], $criteria['paging'], $total );
582 
583  if ( is_wp_error( $entries ) ) {
584  gravityview()->log->error( '{error}', array( 'error' => $entries->get_error_message(), 'data' => $entries ) );
585 
586  /** Remove filter added above */
587  remove_filter( 'gform_is_encrypted_field', '__return_false' );
588  return false;
589  }
590  }
591 
592  if ( ! empty( $criteria['cache'] ) && isset( $Cache ) ) {
593 
594  // Cache results
595  $Cache->set( $entries, 'entries' );
596 
597  }
598 
599  $return = $entries;
600  }
601 
602  /** Remove filter added above */
603  remove_filter( 'gform_is_encrypted_field', '__return_false' );
604 
605  /**
606  * @filter `gravityview_entries` Modify the array of entries returned to GravityView after it has been fetched from the cache or from `GFAPI::get_entries()`.
607  * @param array|null $entries Array of entries as returned by the cache or by `GFAPI::get_entries()`
608  * @param array $criteria The final search criteria used to generate the request to `GFAPI::get_entries()`
609  * @param array $passed_criteria The original search criteria passed to `GVCommon::get_entries()`
610  * @param int|null $total Optional. An output parameter containing the total number of entries. Pass a non-null value to generate
611  * @since 2.1 The $total parameter can now be overriden by reference.
612  * @deprecated
613  */
614  $return = apply_filters_ref_array( 'gravityview_entries', array( $return, $criteria, $passed_criteria, &$total ) );
615 
616  return $return;
617  }
618 
619 
620  /**
621  * Get the entry ID from a string that may be the Entry ID or the Entry Slug
622  *
623  * @since 1.18
624  *
625  * @param string $entry_id_or_slug The ID or slug of an entry.
626  * @param bool $force_allow_ids Whether to force allowing getting the ID of an entry, even if custom slugs are enabled
627  *
628  * @return false|int|null Returns the ID of the entry found, if custom slugs is enabled. Returns original value if custom slugs is disabled. Returns false if not allowed to convert slug to ID. Returns NULL if entry not found for the passed slug.
629  */
630  public static function get_entry_id( $entry_id_or_slug = '', $force_allow_ids = false ) {
631 
632  $entry_id = false;
633 
634  /**
635  * @filter `gravityview_custom_entry_slug` Whether to enable and use custom entry slugs.
636  * @param boolean True: Allow for slugs based on entry values. False: always use entry IDs (default)
637  */
638  $custom_slug = apply_filters( 'gravityview_custom_entry_slug', false );
639 
640  /**
641  * @filter `gravityview_custom_entry_slug_allow_id` When using a custom slug, allow access to the entry using the original slug (the Entry ID).
642  * - If disabled (default), only allow access to an entry using the custom slug value. (example: `/entry/custom-slug/` NOT `/entry/123/`)
643  * - If enabled, you could access using the custom slug OR the entry id (example: `/entry/custom-slug/` OR `/entry/123/`)
644  * @param boolean $custom_slug_id_access True: allow accessing the slug by ID; False: only use the slug passed to the method.
645  */
646  $custom_slug_id_access = $force_allow_ids || apply_filters( 'gravityview_custom_entry_slug_allow_id', false );
647 
648  /**
649  * If we're using custom entry slugs, we do a meta value search
650  * instead of doing a straightup ID search.
651  */
652  if ( $custom_slug ) {
653  // Search for IDs matching $entry_id_or_slug
654  $entry_id = self::get_entry_id_from_slug( $entry_id_or_slug );
655  }
656 
657  // If custom slug is off, search using the entry ID
658  // ID allow ID access is on, also use entry ID as a backup
659  if ( false === $custom_slug || true === $custom_slug_id_access ) {
660  // Search for IDs matching $entry_slug
661  $entry_id = $entry_id_or_slug;
662  }
663 
664  return $entry_id;
665  }
666 
667  /**
668  * Return a single entry object
669  *
670  * Since 1.4, supports custom entry slugs. The way that GravityView fetches an entry based on the custom slug is by searching `gravityview_unique_id` meta. The `$entry_slug` is fetched by getting the current query var set by `is_single_entry()`
671  *
672  * @param string|int $entry_slug Either entry ID or entry slug string
673  * @param boolean $force_allow_ids Force the get_entry() method to allow passed entry IDs, even if the `gravityview_custom_entry_slug_allow_id` filter returns false.
674  * @param boolean $check_entry_display Check whether the entry is visible for the current View configuration. Default: true. {@since 1.14}
675  * @param \GV\View|null $view The View if $check_entry_display is set to true. In legacy context mocks, can be null. {@since develop}
676  * @return array|boolean
677  */
678  public static function get_entry( $entry_slug, $force_allow_ids = false, $check_entry_display = true, $view = null ) {
679 
680  if ( ! class_exists( 'GFAPI' ) || empty( $entry_slug ) ) {
681  return false;
682  }
683 
684 
685  $entry_id = self::get_entry_id( $entry_slug, $force_allow_ids );
686 
687  if ( empty( $entry_id ) ) {
688  return false;
689  }
690 
691  // fetch the entry
692  $entry = GFAPI::get_entry( $entry_id );
693 
694  /**
695  * @filter `gravityview/common/get_entry/check_entry_display` Override whether to check entry display rules against filters
696  * @since 1.16.2
697  * @since 2.6 Added $view parameter
698  * @param bool $check_entry_display Check whether the entry is visible for the current View configuration. Default: true.
699  * @param array $entry Gravity Forms entry array
700  * @param \GV\View|null $view The View
701  */
702  $check_entry_display = apply_filters( 'gravityview/common/get_entry/check_entry_display', $check_entry_display, $entry, $view );
703 
704  // Is the entry allowed
705  if( $check_entry_display ) {
706 
707  $gvid = \GV\Utils::_GET( 'gvid' );
708 
709  if( $gvid ) {
710  $view = \GV\View::by_id( $gvid );
711  }
712 
713  $entry = self::check_entry_display( $entry, $view );
714  }
715 
716  if( is_wp_error( $entry ) ) {
717  gravityview()->log->error( '{error}', array( 'error' => $entry->get_error_message() ) );
718  return false;
719  }
720 
721  return $entry;
722  }
723 
724  /**
725  * Wrapper for the GFFormsModel::matches_operation() method that adds additional comparisons, including:
726  * 'equals', 'greater_than_or_is', 'greater_than_or_equals', 'less_than_or_is', 'less_than_or_equals',
727  * 'not_contains', 'in', and 'not_in'
728  *
729  * @since 1.13 You can define context, which displays/hides based on what's being displayed (single, multiple, edit)
730  * @since 1.22.1 Added 'in' and 'not_in' for JSON-encoded array values, serialized non-strings
731  *
732  * @see https://docs.gravityview.co/article/252-gvlogic-shortcode
733  * @uses GFFormsModel::matches_operation
734  * @since 1.7.5
735  *
736  * @param mixed $val1 Left side of comparison
737  * @param mixed $val2 Right side of comparison
738  * @param string $operation Type of comparison
739  *
740  * @return bool True: matches, false: not matches
741  */
742  public static function matches_operation( $val1, $val2, $operation ) {
743 
744  // Only process strings
745  $val1 = ! is_string( $val1 ) ? wp_json_encode( $val1 ) : $val1;
746  $val2 = ! is_string( $val2 ) ? wp_json_encode( $val2 ) : $val2;
747 
748  $value = false;
749 
750  if( 'context' === $val1 ) {
751 
752  $matching_contexts = array( $val2 );
753 
754  // We allow for non-standard contexts.
755  switch( $val2 ) {
756  // Check for either single or edit
757  case 'singular':
758  $matching_contexts = array( 'single', 'edit' );
759  break;
760  // Use multiple as alias for directory for consistency
761  case 'multiple':
762  $matching_contexts = array( 'directory' );
763  break;
764  }
765 
766  $val1 = in_array( gravityview_get_context(), $matching_contexts ) ? $val2 : false;
767  }
768 
769  switch ( $operation ) {
770  case 'equals':
771  $value = self::matches_operation( $val1, $val2, 'is' );
772  break;
773  case 'greater_than_or_is':
774  case 'greater_than_or_equals':
775  $is = self::matches_operation( $val1, $val2, 'is' );
776  $gt = self::matches_operation( $val1, $val2, 'greater_than' );
777  $value = ( $is || $gt );
778  break;
779  case 'less_than_or_is':
780  case 'less_than_or_equals':
781  $is = self::matches_operation( $val1, $val2, 'is' );
782  $gt = self::matches_operation( $val1, $val2, 'less_than' );
783  $value = ( $is || $gt );
784  break;
785  case 'not_contains':
786  $contains = self::matches_operation( $val1, $val2, 'contains' );
787  $value = ! $contains;
788  break;
789  /**
790  * @since 1.22.1 Handle JSON-encoded comparisons
791  */
792  case 'in':
793  case 'not_in':
794 
795  $json_val_1 = json_decode( $val1, true );
796  $json_val_2 = json_decode( $val2, true );
797 
798  if( ! empty( $json_val_1 ) || ! empty( $json_val_2 ) ) {
799 
800  $json_in = false;
801  $json_val_1 = $json_val_1 ? (array) $json_val_1 : array( $val1 );
802  $json_val_2 = $json_val_2 ? (array) $json_val_2 : array( $val2 );
803 
804  // For JSON, we want to compare as "in" or "not in" rather than "contains"
805  foreach ( $json_val_1 as $item_1 ) {
806  foreach ( $json_val_2 as $item_2 ) {
807  $json_in = self::matches_operation( $item_1, $item_2, 'is' );
808 
809  if( $json_in ) {
810  break 2;
811  }
812  }
813  }
814 
815  $value = ( $operation === 'in' ) ? $json_in : ! $json_in;
816  }
817  break;
818 
819  case 'less_than':
820  case '<' :
821  if ( is_string( $val1 ) && is_string( $val2 ) ) {
822  $value = $val1 < $val2;
823  } else {
824  $value = GFFormsModel::matches_operation( $val1, $val2, $operation );
825  }
826  break;
827  case 'greater_than':
828  case '>' :
829  if ( is_string( $val1 ) && is_string( $val2 ) ) {
830  $value = $val1 > $val2;
831  } else {
832  $value = GFFormsModel::matches_operation( $val1, $val2, $operation );
833  }
834  break;
835  default:
836  $value = GFFormsModel::matches_operation( $val1, $val2, $operation );
837  }
838 
839  return $value;
840  }
841 
842  /**
843  *
844  * Checks if a certain entry is valid according to the View search filters (specially the Adv Filters)
845  *
846  * @uses GVCommon::calculate_get_entries_criteria();
847  * @see GFFormsModel::is_value_match()
848  *
849  * @since 1.7.4
850  * @since 2.1 Added $view parameter
851  *
852  * @param array $entry Gravity Forms Entry object
853  * @param \GV\View|\GV\View_Collection $view The View or a View Collection
854  *
855  * @return WP_Error|array Returns WP_Error if entry is not valid according to the view search filters (Adv Filter). Returns original $entry value if passes.
856  */
857  public static function check_entry_display( $entry, $view = null ) {
858 
859  if ( ! $entry || is_wp_error( $entry ) ) {
860  return new WP_Error('entry_not_found', 'Entry was not found.', $entry );
861  }
862 
863  if ( empty( $entry['form_id'] ) ) {
864  return new WP_Error( 'form_id_not_set', '[apply_filters_to_entry] Entry is empty!', $entry );
865  }
866 
867  if ( is_null( $view ) ) {
868  gravityview()->log->warning( '$view was not supplied to check_entry_display, results will be non-typical.' );
869  return new WP_Error( 'view_not_supplied', 'View is not supplied!', $entry );
870  }
871 
872  if ( ! gravityview()->plugin->supports( \GV\Plugin::FEATURE_GFQUERY ) ) {
873  return new WP_Error( 'no_gf_query', 'GF_Query is missing.', $entry );
874  }
875 
876  $_gvid = \GV\Utils::_GET( 'gvid' );
877 
878  if ( $_gvid && $view->ID !== (int) $_gvid ) {
879  return new WP_Error( 'view_id_not_match_gvid', 'View does not match passed $_GET["gvid"].', $view->ID );
880  }
881 
882  $view_form_id = $view->form->ID;
883 
884  if ( $view->joins ) {
885  if ( in_array( (int) $entry['form_id'], array_keys( $view::get_joined_forms( $view->ID ) ), true ) ) {
886  $view_form_id = $entry['form_id'];
887  }
888  }
889 
890  if ( (int) $view_form_id !== (int) $entry['form_id'] ) {
891  return new WP_Error( 'view_id_not_match', 'View form source does not match entry form source ID.', $entry );
892  }
893 
894  /**
895  * Check whether the entry is in the entries subset by running a modified query.
896  */
897  add_action( 'gravityview/view/query', $entry_subset_callback = function( &$query, $view, $request ) use ( $entry, $view_form_id ) {
898  $_tmp_query = new \GF_Query( $view_form_id, array(
899  'field_filters' => array(
900  'mode' => 'all',
901  array(
902  'key' => 'id',
903  'operation' => 'is',
904  'value' => $entry['id']
905  )
906  )
907  ) );
908 
909  $_tmp_query_parts = $_tmp_query->_introspect();
910 
911  /** @type \GF_Query $query */
912  $query_parts = $query->_introspect();
913 
914  $query->where( \GF_Query_Condition::_and( $_tmp_query_parts['where'], $query_parts['where'] ) );
915 
916  }, 10, 3 );
917 
918  // Prevent page offset from being applied to the single entry query; it's used to return to the referring page number
919  add_filter( 'gravityview_search_criteria', $remove_pagenum = function( $criteria ) {
920 
921  $criteria['paging'] = array(
922  'offset' => 0,
923  'page_size' => 25
924  );
925 
926  return $criteria;
927  } );
928 
929  $entries = $view->get_entries()->all();
930 
931  // Remove the modifying filter
932  remove_filter( 'gravityview_search_criteria', $remove_pagenum );
933 
934  if ( ! $entries ) {
935  remove_action( 'gravityview/view/query', $entry_subset_callback );
936  return new \WP_Error( 'failed_criteria', 'Entry failed search_criteria and field_filters' );
937  }
938 
939  // This entry is on a View with joins
940  if ( $entries[0]->is_multi() ) {
941 
942  $multi_entry_ids = array();
943 
944  foreach ( $entries[0]->entries as $multi_entry ) {
945  $multi_entry_ids[] = (int) $multi_entry->ID;
946  }
947 
948  if ( ! in_array( (int) $entry['id'], $multi_entry_ids, true ) ) {
949  remove_action( 'gravityview/view/query', $entry_subset_callback );
950  return new \WP_Error( 'failed_criteria', 'Entry failed search_criteria and field_filters' );
951  }
952 
953  } elseif ( (int) $entries[0]->ID !== (int) $entry['id'] ) {
954  remove_action( 'gravityview/view/query', $entry_subset_callback );
955  return new \WP_Error( 'failed_criteria', 'Entry failed search_criteria and field_filters' );
956  }
957 
958  remove_action( 'gravityview/view/query', $entry_subset_callback );
959  return $entry;
960  }
961 
962 
963  /**
964  * Allow formatting date and time based on GravityView standards
965  *
966  * @since 1.16
967  *
968  * @see GVCommon_Test::test_format_date for examples
969  *
970  * @param string $date_string The date as stored by Gravity Forms (`Y-m-d h:i:s` GMT)
971  * @param string|array $args Array or string of settings for output parsed by `wp_parse_args()`; Can use `raw=1` or `array('raw' => true)` \n
972  * - `raw` Un-formatted date string in original `Y-m-d h:i:s` format
973  * - `timestamp` Integer timestamp returned by GFCommon::get_local_timestamp()
974  * - `diff` "%s ago" format, unless other `format` is defined
975  * - `human` Set $is_human parameter to true for `GFCommon::format_date()`. Shows `diff` within 24 hours or date after. Format based on blog setting, unless `format` is defined.
976  * - `time` Include time in the `GFCommon::format_date()` output
977  * - `format` Define your own date format, or `diff` format
978  *
979  * @return int|null|string Formatted date based on the original date
980  */
981  public static function format_date( $date_string = '', $args = array() ) {
982 
983  $default_atts = array(
984  'raw' => false,
985  'timestamp' => false,
986  'diff' => false,
987  'human' => false,
988  'format' => '',
989  'time' => false,
990  );
991 
992  $atts = wp_parse_args( $args, $default_atts );
993 
994  /**
995  * Gravity Forms code to adjust date to locally-configured Time Zone
996  * @see GFCommon::format_date() for original code
997  */
998  $date_gmt_time = mysql2date( 'G', $date_string );
999  $date_local_timestamp = GFCommon::get_local_timestamp( $date_gmt_time );
1000 
1001  $format = \GV\Utils::get( $atts, 'format' );
1002  $is_human = ! empty( $atts['human'] );
1003  $is_diff = ! empty( $atts['diff'] );
1004  $is_raw = ! empty( $atts['raw'] );
1005  $is_timestamp = ! empty( $atts['timestamp'] );
1006  $include_time = ! empty( $atts['time'] );
1007 
1008  // If we're using time diff, we want to have a different default format
1009  if( empty( $format ) ) {
1010  /* translators: %s: relative time from now, used for generic date comparisons. "1 day ago", or "20 seconds ago" */
1011  $format = $is_diff ? esc_html__( '%s ago', 'gravityview' ) : get_option( 'date_format' );
1012  }
1013 
1014  // If raw was specified, don't modify the stored value
1015  if ( $is_raw ) {
1016  $formatted_date = $date_string;
1017  } elseif( $is_timestamp ) {
1018  $formatted_date = $date_local_timestamp;
1019  } elseif ( $is_diff ) {
1020  $formatted_date = sprintf( $format, human_time_diff( $date_gmt_time ) );
1021  } else {
1022  $formatted_date = GFCommon::format_date( $date_string, $is_human, $format, $include_time );
1023  }
1024 
1025  unset( $format, $is_diff, $is_human, $is_timestamp, $is_raw, $date_gmt_time, $date_local_timestamp, $default_atts );
1026 
1027  return $formatted_date;
1028  }
1029 
1030  /**
1031  * Retrieve the label of a given field id (for a specific form)
1032  *
1033  * @since 1.17 Added $field_value parameter
1034  *
1035  * @param array $form Gravity Forms form array
1036  * @param string $field_id ID of the field. If an input, full input ID (like `1.3`)
1037  * @param string|array $field_value Raw value of the field.
1038  * @return string
1039  */
1040  public static function get_field_label( $form = array(), $field_id = '', $field_value = '' ) {
1041 
1042  if ( empty( $form ) || empty( $field_id ) ) {
1043  return '';
1044  }
1045 
1046  $field = self::get_field( $form, $field_id );
1047 
1048  $label = \GV\Utils::get( $field, 'label' );
1049 
1050  if( floor( $field_id ) !== floatval( $field_id ) ) {
1051  $label = GFFormsModel::get_choice_text( $field, $field_value, $field_id );
1052  }
1053 
1054  return $label;
1055  }
1056 
1057 
1058  /**
1059  * Returns the field details array of a specific form given the field id
1060  *
1061  * Alias of GFFormsModel::get_field
1062  *
1063  * @since 1.19 Allow passing form ID as well as form array
1064  *
1065  * @uses GFFormsModel::get_field
1066  * @see GFFormsModel::get_field
1067  * @param array|int $form Form array or ID
1068  * @param string|int $field_id
1069  * @return GF_Field|null Gravity Forms field object, or NULL: Gravity Forms GFFormsModel does not exist or field at $field_id doesn't exist.
1070  */
1071  public static function get_field( $form, $field_id ) {
1072 
1073  if ( is_numeric( $form ) ) {
1074  $form = GFAPI::get_form( $form );
1075  }
1076 
1077  if ( class_exists( 'GFFormsModel' ) ){
1078  return GFFormsModel::get_field( $form, $field_id );
1079  } else {
1080  return null;
1081  }
1082  }
1083 
1084 
1085  /**
1086  * Check whether the post is GravityView
1087  *
1088  * - Check post type. Is it `gravityview`?
1089  * - Check shortcode
1090  *
1091  * @param WP_Post $post WordPress post object
1092  * @return boolean True: yep, GravityView; No: not!
1093  */
1094  public static function has_gravityview_shortcode( $post = null ) {
1095  if ( ! is_a( $post, 'WP_Post' ) ) {
1096  return false;
1097  }
1098 
1099  if ( 'gravityview' === get_post_type( $post ) ) {
1100  return true;
1101  }
1102 
1103  return self::has_shortcode_r( $post->post_content, 'gravityview' ) ? true : false;
1104 
1105  }
1106 
1107 
1108  /**
1109  * Placeholder until the recursive has_shortcode() patch is merged
1110  * @see https://core.trac.wordpress.org/ticket/26343#comment:10
1111  * @param string $content Content to check whether there's a shortcode
1112  * @param string $tag Current shortcode tag
1113  */
1114  public static function has_shortcode_r( $content, $tag = 'gravityview' ) {
1115  if ( false === strpos( $content, '[' ) ) {
1116  return false;
1117  }
1118 
1119  if ( shortcode_exists( $tag ) ) {
1120 
1121  $shortcodes = array();
1122 
1123  preg_match_all( '/' . get_shortcode_regex() . '/s', $content, $matches, PREG_SET_ORDER );
1124  if ( empty( $matches ) ){
1125  return false;
1126  }
1127 
1128  foreach ( $matches as $shortcode ) {
1129  if ( $tag === $shortcode[2] ) {
1130 
1131  // Changed this to $shortcode instead of true so we get the parsed atts.
1132  $shortcodes[] = $shortcode;
1133 
1134  } else if ( isset( $shortcode[5] ) && $results = self::has_shortcode_r( $shortcode[5], $tag ) ) {
1135  foreach( $results as $result ) {
1136  $shortcodes[] = $result;
1137  }
1138  }
1139  }
1140 
1141  return $shortcodes;
1142  }
1143  return false;
1144  }
1145 
1146 
1147 
1148  /**
1149  * Get the views for a particular form
1150  *
1151  * @since 1.15.2 Add $args array and limit posts_per_page to 500
1152  *
1153  * @uses get_posts()
1154  *
1155  * @param int $form_id Gravity Forms form ID
1156  * @param array $args Pass args sent to get_posts()
1157  *
1158  * @return array Array with view details, as returned by get_posts()
1159  */
1160  public static function get_connected_views( $form_id, $args = array() ) {
1161 
1162  global $wpdb;
1163 
1164  $defaults = array(
1165  'post_type' => 'gravityview',
1166  'posts_per_page' => 100,
1167  'meta_key' => '_gravityview_form_id',
1168  'meta_value' => (int) $form_id,
1169  );
1170  $args = wp_parse_args( $args, $defaults );
1171  $views = get_posts( $args );
1172 
1173  $views_with_joins = $wpdb->get_results( "SELECT `post_id`, `meta_value` FROM $wpdb->postmeta WHERE `meta_key` = '_gravityview_form_joins'" );
1174 
1175  $joined_forms = array();
1176  foreach ( $views_with_joins as $view ) {
1177 
1178  $data = unserialize( $view->meta_value );
1179 
1180  if( ! $data || ! is_array( $data ) ) {
1181  continue;
1182  }
1183 
1184  foreach ( $data as $datum ) {
1185  if ( ! empty( $datum[2] ) && (int) $datum[2] === (int) $form_id ) {
1186  $joined_forms[] = $view->post_id;
1187  }
1188  }
1189  }
1190 
1191  if ( $joined_forms ) {
1192  $joined_args = array(
1193  'post_type' => 'gravityview',
1194  'posts_per_page' => $args['posts_per_page'],
1195  'post__in' => $joined_forms,
1196  );
1197  $views = array_merge( $views, get_posts( $joined_args ) );
1198  }
1199 
1200  return $views;
1201  }
1202 
1203  /**
1204  * Get the Gravity Forms form ID connected to a View
1205  *
1206  * @param int $view_id The ID of the View to get the connected form of
1207  *
1208  * @return false|string ID of the connected Form, if exists. Empty string if not. False if not the View ID isn't valid.
1209  */
1210  public static function get_meta_form_id( $view_id ) {
1211  return get_post_meta( $view_id, '_gravityview_form_id', true );
1212  }
1213 
1214  /**
1215  * Get the template ID (`list`, `table`, `datatables`, `map`) for a View
1216  *
1217  * @see GravityView_Template::template_id
1218  *
1219  * @param int $view_id The ID of the View to get the layout of
1220  *
1221  * @return string GravityView_Template::template_id value. Empty string if not.
1222  */
1223  public static function get_meta_template_id( $view_id ) {
1224  return get_post_meta( $view_id, '_gravityview_directory_template', true );
1225  }
1226 
1227 
1228  /**
1229  * Get all the settings for a View
1230  *
1231  * @uses \GV\View_Settings::defaults() Parses the settings with the plugin defaults as backups.
1232  * @param int $post_id View ID
1233  * @return array Associative array of settings with plugin defaults used if not set by the View
1234  */
1235  public static function get_template_settings( $post_id ) {
1236 
1237  $settings = get_post_meta( $post_id, '_gravityview_template_settings', true );
1238 
1239  if ( class_exists( '\GV\View_Settings' ) ) {
1240 
1241  return wp_parse_args( (array)$settings, \GV\View_Settings::defaults() );
1242 
1243  }
1244 
1245  // Backup, in case GravityView_View_Data isn't loaded yet.
1246  return $settings;
1247  }
1248 
1249  /**
1250  * Get the setting for a View
1251  *
1252  * If the setting isn't set by the View, it returns the plugin default.
1253  *
1254  * @param int $post_id View ID
1255  * @param string $key Key for the setting
1256  * @return mixed|null Setting value, or NULL if not set.
1257  */
1258  public static function get_template_setting( $post_id, $key ) {
1259 
1260  $settings = self::get_template_settings( $post_id );
1261 
1262  if ( isset( $settings[ $key ] ) ) {
1263  return $settings[ $key ];
1264  }
1265 
1266  return null;
1267  }
1268 
1269  /**
1270  * Get the field configuration for the View
1271  *
1272  * array(
1273  *
1274  * [other zones]
1275  *
1276  * 'directory_list-title' => array(
1277  *
1278  * [other fields]
1279  *
1280  * '5372653f25d44' => array(
1281  * 'id' => string '9' (length=1)
1282  * 'label' => string 'Screenshots' (length=11)
1283  * 'show_label' => string '1' (length=1)
1284  * 'custom_label' => string '' (length=0)
1285  * 'custom_class' => string 'gv-gallery' (length=10)
1286  * 'only_loggedin' => string '0' (length=1)
1287  * 'only_loggedin_cap' => string 'read' (length=4)
1288  * )
1289  *
1290  * [other fields]
1291  * )
1292  *
1293  * [other zones]
1294  * )
1295  *
1296  * @since 1.17.4 Added $apply_filter parameter
1297  *
1298  * @param int $post_id View ID
1299  * @param bool $apply_filter Whether to apply the `gravityview/configuration/fields` filter [Default: true]
1300  * @return array Multi-array of fields with first level being the field zones. See code comment.
1301  */
1302  public static function get_directory_fields( $post_id, $apply_filter = true ) {
1303  $fields = get_post_meta( $post_id, '_gravityview_directory_fields', true );
1304 
1305  if ( $apply_filter ) {
1306  /**
1307  * @filter `gravityview/configuration/fields` Filter the View fields' configuration array
1308  * @since 1.6.5
1309  *
1310  * @param $fields array Multi-array of fields with first level being the field zones
1311  * @param $post_id int Post ID
1312  */
1313  $fields = apply_filters( 'gravityview/configuration/fields', $fields, $post_id );
1314 
1315  /**
1316  * @filter `gravityview/view/configuration/fields` Filter the View fields' configuration array.
1317  * @since 2.0
1318  *
1319  * @param array $fields Multi-array of fields with first level being the field zones.
1320  * @param \GV\View $view The View the fields are being pulled for.
1321  */
1322  $fields = apply_filters( 'gravityview/view/configuration/fields', $fields, \GV\View::by_id( $post_id ) );
1323  }
1324 
1325  return $fields;
1326  }
1327 
1328  /**
1329  * Get the widget configuration for a View
1330  *
1331  * @param int $view_id View ID
1332  * @param bool $json_decode Whether to JSON-decode the widget values. Default: `false`
1333  *
1334  * @return array Multi-array of widgets, with the slug of each widget "zone" being the key ("header_top"), and each widget having their own "id"
1335  */
1336  public static function get_directory_widgets( $view_id, $json_decode = false ) {
1337 
1338  $view_widgets = get_post_meta( $view_id, '_gravityview_directory_widgets', true );
1339 
1340  $defaults = array(
1341  'header_top' => array(),
1342  'header_left' => array(),
1343  'header_right' => array(),
1344  'footer_left' => array(),
1345  'footer_right' => array(),
1346  );
1347 
1348  $directory_widgets = wp_parse_args( $view_widgets, $defaults );
1349 
1350  if( $json_decode ) {
1351  $directory_widgets = gv_map_deep( $directory_widgets, 'gv_maybe_json_decode' );
1352  }
1353 
1354  return $directory_widgets;
1355  }
1356 
1357 
1358  /**
1359  * Render dropdown (select) with the list of sortable fields from a form ID
1360  *
1361  * @param int $formid Form ID
1362  * @return string html
1363  */
1364  public static function get_sortable_fields( $formid, $current = '' ) {
1365  $output = '<option value="" ' . selected( '', $current, false ).'>' . esc_html__( 'Default', 'gravityview' ) .'</option>';
1366 
1367  if ( empty( $formid ) ) {
1368  return $output;
1369  }
1370 
1371  $fields = self::get_sortable_fields_array( $formid );
1372 
1373  if ( ! empty( $fields ) ) {
1374 
1375  $blacklist_field_types = apply_filters( 'gravityview_blacklist_field_types', array( 'list', 'textarea' ), null );
1376 
1377  foreach ( $fields as $id => $field ) {
1378  if ( in_array( $field['type'], $blacklist_field_types ) ) {
1379  continue;
1380  }
1381 
1382  $output .= '<option value="'. $id .'" '. selected( $id, $current, false ).'>'. esc_attr( $field['label'] ) .'</option>';
1383  }
1384  }
1385 
1386  return $output;
1387  }
1388 
1389  /**
1390  *
1391  * @param int $formid Gravity Forms form ID
1392  * @param array $blacklist Field types to exclude
1393  *
1394  * @since 1.8
1395  *
1396  * @todo Get all fields, check if sortable dynamically
1397  *
1398  * @return array
1399  */
1400  public static function get_sortable_fields_array( $formid, $blacklist = array( 'list', 'textarea' ) ) {
1401 
1402  // Get fields with sub-inputs and no parent
1403  $fields = self::get_form_fields( $formid, true, false );
1404 
1405  $date_created = array(
1406  'date_created' => array(
1407  'type' => 'date_created',
1408  'label' => __( 'Date Created', 'gravityview' ),
1409  ),
1410  'date_updated' => array(
1411  'type' => 'date_updated',
1412  'label' => __( 'Date Updated', 'gravityview' ),
1413  ),
1414  );
1415 
1416  $fields = $date_created + $fields;
1417 
1418  $blacklist_field_types = apply_filters( 'gravityview_blacklist_field_types', $blacklist, NULL );
1419 
1420  // TODO: Convert to using array_filter
1421  foreach( $fields as $id => $field ) {
1422 
1423  if( in_array( $field['type'], $blacklist_field_types ) ) {
1424  unset( $fields[ $id ] );
1425  }
1426 
1427  /**
1428  * Merge date and time subfields.
1429  */
1430  if ( in_array( $field['type'], array( 'date', 'time' ) ) && ! empty( $field['parent'] ) ) {
1431  $fields[ intval( $id ) ] = array(
1432  'label' => \GV\Utils::get( $field, 'parent/label' ),
1433  'parent' => null,
1434  'type' => \GV\Utils::get( $field, 'parent/type' ),
1435  'adminLabel' => \GV\Utils::get( $field, 'parent/adminLabel' ),
1436  'adminOnly' => \GV\Utils::get( $field, 'parent/adminOnly' ),
1437  );
1438 
1439  unset( $fields[ $id ] );
1440  }
1441 
1442  }
1443 
1444  /**
1445  * @filter `gravityview/common/sortable_fields` Filter the sortable fields
1446  * @since 1.12
1447  * @param array $fields Sub-set of GF form fields that are sortable
1448  * @param int $formid The Gravity Forms form ID that the fields are from
1449  */
1450  $fields = apply_filters( 'gravityview/common/sortable_fields', $fields, $formid );
1451 
1452  return $fields;
1453  }
1454 
1455  /**
1456  * Returns the GF Form field type for a certain field(id) of a form
1457  * @param object $form Gravity Forms form
1458  * @param mixed $field_id Field ID or Field array
1459  * @return string field type
1460  */
1461  public static function get_field_type( $form = null, $field_id = '' ) {
1462 
1463  if ( ! empty( $field_id ) && ! is_array( $field_id ) ) {
1464  $field = self::get_field( $form, $field_id );
1465  } else {
1466  $field = $field_id;
1467  }
1468 
1469  return class_exists( 'RGFormsModel' ) ? RGFormsModel::get_input_type( $field ) : '';
1470 
1471  }
1472 
1473 
1474  /**
1475  * Checks if the field type is a 'numeric' field type (e.g. to be used when sorting)
1476  * @param int|array $form form ID or form array
1477  * @param int|array $field field key or field array
1478  * @return boolean
1479  */
1480  public static function is_field_numeric( $form = null, $field = '' ) {
1481 
1482  if ( ! is_array( $form ) && ! is_array( $field ) ) {
1483  $form = self::get_form( $form );
1484  }
1485 
1486  // If entry meta, it's a string. Otherwise, numeric
1487  if( ! is_numeric( $field ) && is_string( $field ) ) {
1488  $type = $field;
1489  } else {
1490  $type = self::get_field_type( $form, $field );
1491  }
1492 
1493  /**
1494  * @filter `gravityview/common/numeric_types` What types of fields are numeric?
1495  * @since 1.5.2
1496  * @param array $numeric_types Fields that are numeric. Default: `[ number, time ]`
1497  */
1498  $numeric_types = apply_filters( 'gravityview/common/numeric_types', array( 'number', 'time' ) );
1499 
1500  // Defer to GravityView_Field setting, if the field type is registered and `is_numeric` is true
1501  if( $gv_field = GravityView_Fields::get( $type ) ) {
1502  if( true === $gv_field->is_numeric ) {
1503  $numeric_types[] = $gv_field->is_numeric;
1504  }
1505  }
1506 
1507  $return = in_array( $type, $numeric_types );
1508 
1509  return $return;
1510  }
1511 
1512  /**
1513  * Encrypt content using Javascript so that it's hidden when JS is disabled.
1514  *
1515  * This is mostly used to hide email addresses from scraper bots.
1516  *
1517  * @param string $content Content to encrypt
1518  * @param string $message Message shown if Javascript is disabled
1519  *
1520  * @see https://github.com/katzwebservices/standalone-phpenkoder StandalonePHPEnkoder on Github
1521  *
1522  * @since 1.7
1523  *
1524  * @return string Content, encrypted
1525  */
1526  public static function js_encrypt( $content, $message = '' ) {
1527 
1528  $output = $content;
1529 
1530  if ( ! class_exists( 'StandalonePHPEnkoder' ) ) {
1531  include_once( GRAVITYVIEW_DIR . 'includes/lib/StandalonePHPEnkoder.php' );
1532  }
1533 
1534  if ( class_exists( 'StandalonePHPEnkoder' ) ) {
1535 
1536  $enkoder = new StandalonePHPEnkoder;
1537 
1538  $message = empty( $message ) ? __( 'Email hidden; Javascript is required.', 'gravityview' ) : $message;
1539 
1540  /**
1541  * @filter `gravityview/phpenkoder/msg` Modify the message shown when Javascript is disabled and an encrypted email field is displayed
1542  * @since 1.7
1543  * @param string $message Existing message
1544  * @param string $content Content to encrypt
1545  */
1546  $enkoder->enkode_msg = apply_filters( 'gravityview/phpenkoder/msg', $message, $content );
1547 
1548  $output = $enkoder->enkode( $content );
1549  }
1550 
1551  return $output;
1552  }
1553 
1554  /**
1555  *
1556  * Do the same than parse_str without max_input_vars limitation:
1557  * Parses $string as if it were the query string passed via a URL and sets variables in the current scope.
1558  * @param $string string string to parse (not altered like in the original parse_str(), use the second parameter!)
1559  * @param $result array If the second parameter is present, variables are stored in this variable as array elements
1560  * @return bool true or false if $string is an empty string
1561  * @since 1.5.3
1562  *
1563  * @see https://gist.github.com/rubo77/6821632
1564  **/
1565  public static function gv_parse_str( $string, &$result ) {
1566  if ( empty( $string ) ) {
1567  return false;
1568  }
1569 
1570  $result = array();
1571 
1572  // find the pairs "name=value"
1573  $pairs = explode( '&', $string );
1574 
1575  foreach ( $pairs as $pair ) {
1576  // use the original parse_str() on each element
1577  parse_str( $pair, $params );
1578 
1579  $k = key( $params );
1580  if ( ! isset( $result[ $k ] ) ) {
1581  $result += $params;
1582  } elseif ( array_key_exists( $k, $params ) && is_array( $params[ $k ] ) ) {
1583  $result[ $k ] = self::array_merge_recursive_distinct( $result[ $k ], $params[ $k ] );
1584  }
1585  }
1586  return true;
1587  }
1588 
1589 
1590  /**
1591  * Generate an HTML anchor tag with a list of supported attributes
1592  *
1593  * @see https://developer.mozilla.org/en-US/docs/Web/HTML/Element/a Supported attributes defined here
1594  * @uses esc_url_raw() to sanitize $href
1595  * @uses esc_attr() to sanitize $atts
1596  *
1597  * @since 1.6
1598  *
1599  * @param string $href URL of the link. Sanitized using `esc_url_raw()`
1600  * @param string $anchor_text The text or HTML inside the anchor. This is not sanitized in the function.
1601  * @param array|string $atts Attributes to be added to the anchor tag. Parsed by `wp_parse_args()`, sanitized using `esc_attr()`
1602  *
1603  * @return string HTML output of anchor link. If empty $href, returns NULL
1604  */
1605  public static function get_link_html( $href = '', $anchor_text = '', $atts = array() ) {
1606 
1607  // Supported attributes for anchor tags. HREF left out intentionally.
1608  $allowed_atts = array(
1609  'href' => null, // Will override the $href argument if set
1610  'title' => null,
1611  'rel' => null,
1612  'id' => null,
1613  'class' => null,
1614  'target' => null,
1615  'style' => null,
1616 
1617  // Used by GravityView
1618  'data-viewid' => null,
1619 
1620  // Not standard
1621  'hreflang' => null,
1622  'type' => null,
1623  'tabindex' => null,
1624 
1625  // Deprecated HTML4 but still used
1626  'name' => null,
1627  'onclick' => null,
1628  'onchange' => null,
1629  'onkeyup' => null,
1630 
1631  // HTML5 only
1632  'download' => null,
1633  'media' => null,
1634  'ping' => null,
1635  );
1636 
1637  /**
1638  * @filter `gravityview/get_link/allowed_atts` Modify the attributes that are allowed to be used in generating links
1639  * @param array $allowed_atts Array of attributes allowed
1640  */
1641  $allowed_atts = apply_filters( 'gravityview/get_link/allowed_atts', $allowed_atts );
1642 
1643  // Make sure the attributes are formatted as array
1644  $passed_atts = wp_parse_args( $atts );
1645 
1646  // Make sure the allowed attributes are only the ones in the $allowed_atts list
1647  $final_atts = shortcode_atts( $allowed_atts, $passed_atts );
1648 
1649  // Remove attributes with empty values
1650  $final_atts = array_filter( $final_atts );
1651 
1652  // If the href wasn't passed as an attribute, use the value passed to the function
1653  if ( empty( $final_atts['href'] ) && ! empty( $href ) ) {
1654  $final_atts['href'] = $href;
1655  }
1656 
1657  $final_atts['href'] = esc_url_raw( $href );
1658 
1659  /**
1660  * Fix potential security issue with target=_blank
1661  * @see https://dev.to/ben/the-targetblank-vulnerability-by-example
1662  */
1663  if( '_blank' === \GV\Utils::get( $final_atts, 'target' ) ) {
1664  $final_atts['rel'] = trim( \GV\Utils::get( $final_atts, 'rel', '' ) . ' noopener noreferrer' );
1665  }
1666 
1667  // Sort the attributes alphabetically, to help testing
1668  ksort( $final_atts );
1669 
1670  // For each attribute, generate the code
1671  $output = '';
1672  foreach ( $final_atts as $attr => $value ) {
1673  $output .= sprintf( ' %s="%s"', $attr, esc_attr( $value ) );
1674  }
1675 
1676  if( '' !== $output ) {
1677  $output = '<a' . $output . '>' . $anchor_text . '</a>';
1678  }
1679 
1680  return $output;
1681  }
1682 
1683  /**
1684  * array_merge_recursive does indeed merge arrays, but it converts values with duplicate
1685  * keys to arrays rather than overwriting the value in the first array with the duplicate
1686  * value in the second array, as array_merge does.
1687  *
1688  * @see http://php.net/manual/en/function.array-merge-recursive.php
1689  *
1690  * @since 1.5.3
1691  * @param array $array1
1692  * @param array $array2
1693  * @return array
1694  * @author Daniel <daniel@danielsmedegaardbuus.dk>
1695  * @author Gabriel Sobrinho <gabriel.sobrinho@gmail.com>
1696  */
1697  public static function array_merge_recursive_distinct( array &$array1, array &$array2 ) {
1698  $merged = $array1;
1699  foreach ( $array2 as $key => $value ) {
1700  if ( is_array( $value ) && isset( $merged[ $key ] ) && is_array( $merged[ $key ] ) ) {
1701  $merged[ $key ] = self::array_merge_recursive_distinct( $merged[ $key ], $value );
1702  } else if ( is_numeric( $key ) && isset( $merged[ $key ] ) ) {
1703  $merged[] = $value;
1704  } else {
1705  $merged[ $key ] = $value;
1706  }
1707  }
1708 
1709  return $merged;
1710  }
1711 
1712  /**
1713  * Get WordPress users with reasonable limits set
1714  *
1715  * @param string $context Where are we using this information (e.g. change_entry_creator, search_widget ..)
1716  * @param array $args Arguments to modify the user query. See get_users() {@since 1.14}
1717  * @return array Array of WP_User objects.
1718  */
1719  public static function get_users( $context = 'change_entry_creator', $args = array() ) {
1720 
1721  $default_args = array(
1722  'number' => 2000,
1723  'orderby' => 'display_name',
1724  'order' => 'ASC',
1725  'fields' => array( 'ID', 'display_name', 'user_login', 'user_nicename' )
1726  );
1727 
1728  // Merge in the passed arg
1729  $get_users_settings = wp_parse_args( $args, $default_args );
1730 
1731  /**
1732  * @filter `gravityview/get_users/{$context}` There are issues with too many users using [get_users()](http://codex.wordpress.org/Function_Reference/get_users) where it breaks the select. We try to keep it at a reasonable number. \n
1733  * `$context` is where are we using this information (e.g. change_entry_creator, search_widget ..)
1734  * @param array $settings Settings array, with `number` key defining the # of users to display
1735  */
1736  $get_users_settings = apply_filters( 'gravityview/get_users/'. $context, apply_filters( 'gravityview_change_entry_creator_user_parameters', $get_users_settings ) );
1737 
1738  return get_users( $get_users_settings );
1739  }
1740 
1741 
1742  /**
1743  * Display updated/error notice
1744  *
1745  * @since 1.19.2 Added $cap and $object_id parameters
1746  *
1747  * @param string $notice text/HTML of notice
1748  * @param string $class CSS class for notice (`updated` or `error`)
1749  * @param string $cap [Optional] Define a capability required to show a notice. If not set, displays to all caps.
1750  *
1751  * @return string
1752  */
1753  public static function generate_notice( $notice, $class = '', $cap = '', $object_id = null ) {
1754 
1755  // If $cap is defined, only show notice if user has capability
1756  if( $cap && ! GVCommon::has_cap( $cap, $object_id ) ) {
1757  return '';
1758  }
1759 
1760  return '<div class="gv-notice '.gravityview_sanitize_html_class( $class ) .'">'. $notice .'</div>';
1761  }
1762 
1763  /**
1764  * Inspired on \GFCommon::encode_shortcodes, reverse the encoding by replacing the ascii characters by the shortcode brackets
1765  * @since 1.16.5
1766  * @param string $string Input string to decode
1767  * @return string $string Output string
1768  */
1769  public static function decode_shortcodes( $string ) {
1770  $replace = array( '[', ']', '"' );
1771  $find = array( '&#91;', '&#93;', '&quot;' );
1772  $string = str_replace( $find, $replace, $string );
1773 
1774  return $string;
1775  }
1776 
1777 
1778  /**
1779  * Send email using GFCommon::send_email()
1780  *
1781  * @since 1.17
1782  *
1783  * @see GFCommon::send_email This just makes the method public
1784  *
1785  * @param string $from Sender address (required)
1786  * @param string $to Recipient address (required)
1787  * @param string $bcc BCC recipients (required)
1788  * @param string $reply_to Reply-to address (required)
1789  * @param string $subject Subject line (required)
1790  * @param string $message Message body (required)
1791  * @param string $from_name Displayed name of the sender
1792  * @param string $message_format If "html", sent text as `text/html`. Otherwise, `text/plain`. Default: "html".
1793  * @param string|array $attachments Optional. Files to attach. {@see wp_mail()} for usage. Default: "".
1794  * @param array|false $entry Gravity Forms entry array, related to the email. Default: false.
1795  * @param array|false $notification Gravity Forms notification that triggered the email. {@see GFCommon::send_notification}. Default:false.
1796  */
1797  public static function send_email( $from, $to, $bcc, $reply_to, $subject, $message, $from_name = '', $message_format = 'html', $attachments = '', $entry = false, $notification = false ) {
1798 
1799  $SendEmail = new ReflectionMethod( 'GFCommon', 'send_email' );
1800 
1801  // It was private; let's make it public
1802  $SendEmail->setAccessible( true );
1803 
1804  // Required: $from, $to, $bcc, $replyTo, $subject, $message
1805  // Optional: $from_name, $message_format, $attachments, $lead, $notification
1806  $SendEmail->invoke( new GFCommon, $from, $to, $bcc, $reply_to, $subject, $message, $from_name, $message_format, $attachments, $entry, $notification );
1807  }
1808 
1809 
1810 } //end class
1811 
1812 
1813 /**
1814  * Generate an HTML anchor tag with a list of supported attributes
1815  *
1816  * @see GVCommon::get_link_html()
1817  *
1818  * @since 1.6
1819  *
1820  * @param string $href URL of the link.
1821  * @param string $anchor_text The text or HTML inside the anchor. This is not sanitized in the function.
1822  * @param array|string $atts Attributes to be added to the anchor tag
1823  *
1824  * @return string HTML output of anchor link. If empty $href, returns NULL
1825  */
1826 function gravityview_get_link( $href = '', $anchor_text = '', $atts = array() ) {
1827  return GVCommon::get_link_html( $href, $anchor_text, $atts );
1828 }
const GRAVITYVIEW_DIR
"GRAVITYVIEW_DIR" "./" The absolute path to the plugin directory, with trailing slash ...
Definition: gravityview.php:40
static get_entry_meta( $form_id, $only_default_column=true)
get extra fields from entry meta
static has_product_field( $form=array())
Check whether a form has product fields.
static has_shortcode_r( $content, $tag='gravityview')
Placeholder until the recursive has_shortcode() patch is merged.
static js_encrypt( $content, $message='')
Encrypt content using Javascript so that it&#39;s hidden when JS is disabled.
static _GET( $name, $default=null)
Grab a value from the _GET superglobal or default.
$forms
Definition: data-source.php:19
static get_entry_id_from_slug( $slug)
Get the entry ID from the entry slug, which may or may not be the entry ID.
global $post
Definition: edit-entry.php:7
static array_merge_recursive_distinct(array &$array1, array &$array2)
array_merge_recursive does indeed merge arrays, but it converts values with duplicate keys to arrays ...
static get_directory_widgets( $view_id, $json_decode=false)
Get the widget configuration for a View.
static get_connected_views( $form_id, $args=array())
Get the views for a particular form.
static get_form_fields( $form='', $add_default_properties=false, $include_parent_field=true)
Return array of fields&#39; id and label, for a given Form ID.
static entry_has_transaction_data( $entry=array())
Check if an entry has transaction data.
static calculate_get_entries_criteria( $passed_criteria=array(), $form_ids=array())
Calculates the Search Criteria used on the self::get_entries / self::get_entry methods.
new GravityView_Cache
static get_form_from_entry_id( $entry_slug)
Get the form array for an entry based only on the entry ID.
static getInstance( $passed_post=NULL)
Definition: class-data.php:120
static get_template_setting( $post_id, $key)
Get the setting for a View.
if(gv_empty( $field['value'], false, false)) $format
static get_forms( $active=true, $trash=false, $order_by='id', $order='ASC')
Alias of GFAPI::get_forms()
static get( $field_name)
Alias for get_instance()
If this file is called directly, abort.
static get_meta_form_id( $view_id)
Get the Gravity Forms form ID connected to a View.
static has_cap( $caps_to_check='', $object_id=null, $user_id=null)
Check whether the current user has a capability.
static get_directory_fields( $post_id, $apply_filter=true)
Get the field configuration for the View.
static decode_shortcodes( $string)
Inspired on ::encode_shortcodes, reverse the encoding by replacing the ascii characters by the shortc...
$class
static generate_notice( $notice, $class='', $cap='', $object_id=null)
Display updated/error notice.
$entries
gravityview_get_link( $href='', $anchor_text='', $atts=array())
Generate an HTML anchor tag with a list of supported attributes.
static get_sortable_fields( $formid, $current='')
Render dropdown (select) with the list of sortable fields from a form ID.
static gv_parse_str( $string, &$result)
Do the same than parse_str without max_input_vars limitation: Parses $string as if it were the query ...
gravityview()
Definition: _stubs.php:26
get( $key, $default=null)
Retrieve a setting.
static matches_operation( $val1, $val2, $operation)
Wrapper for the GFFormsModel::matches_operation() method that adds additional comparisons, including: &#39;equals&#39;, &#39;greater_than_or_is&#39;, &#39;greater_than_or_equals&#39;, &#39;less_than_or_is&#39;, &#39;less_than_or_equals&#39;, &#39;not_contains&#39;, &#39;in&#39;, and &#39;not_in&#39;.
$criteria['paging']
Modify the search parameters before the entries are fetched.
static get_template_settings( $post_id)
Get all the settings for a View.
if(empty( $field_settings['content'])) $content
Definition: custom.php:37
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.
static get_entry_ids( $form_id, $search_criteria=array())
Wrapper for the Gravity Forms GFFormsModel::search_lead_ids() method.
gv_map_deep( $value, $callback)
Maps a function to all non-iterable elements of an array or an object.
static get_field_type( $form=null, $field_id='')
Returns the GF Form field type for a certain field(id) of a form.
static get_field_array( $field)
Return a Gravity Forms field array, whether using GF 1.9 or not.
static check_entry_display( $entry, $view=null)
Checks if a certain entry is valid according to the View search filters (specially the Adv Filters) ...
static get_product_field_types()
Return array of product field types.
static get_field( $form, $field_id)
Returns the field details array of a specific form given the field id.
$gv_field
Definition: time.php:11
static send_email( $from, $to, $bcc, $reply_to, $subject, $message, $from_name='', $message_format='html', $attachments='', $entry=false, $notification=false)
Send email using GFCommon::send_email()
static get_all( $group='')
Get all fields.
static is_field_numeric( $form=null, $field='')
Checks if the field type is a &#39;numeric&#39; field type (e.g.
static by_id( $post_id)
Construct a instance from a post ID.
static get_users( $context='change_entry_creator', $args=array())
Get WordPress users with reasonable limits set.
static format_date( $date_string='', $args=array())
Allow formatting date and time based on GravityView standards.
defaults()
Default settings.
$field_id
Definition: time.php:17
static get_entries( $form_ids=null, $passed_criteria=null, &$total=null)
Retrieve entries given search, sort, paging criteria.
static has_gravityview_shortcode( $post=null)
Check whether the post is GravityView.
if(empty( $field_settings['email_field'])) $settings
if(empty( $created_by)) $form_id
static get_sortable_fields_array( $formid, $blacklist=array( 'list', 'textarea'))
static get( $array, $key, $default=null)
Grab a value from an array or an object or default.
static get_field_label( $form=array(), $field_id='', $field_value='')
Retrieve the label of a given field id (for a specific form)
gravityview_get_context()
Returns the current GravityView context, or empty string if not GravityView.
Definition: class-api.php:1250
$entry_slug
Definition: notes.php:30
static get_entry( $entry_slug, $force_allow_ids=false, $check_entry_display=true, $view=null)
Return a single entry object.
static has_cap( $caps='', $object_id=null, $user_id=null)
Alias of GravityView_Roles_Capabilities::has_cap()
static get_meta_template_id( $view_id)
Get the template ID (list, table, datatables, map) for a View.
$entry
Definition: notes.php:27
static get_all_views( $args=array())
Get all existing Views.
static get_link_html( $href='', $anchor_text='', $atts=array())
Generate an HTML anchor tag with a list of supported attributes.
static get_form( $form_id)
Returns the form object for a given Form ID.
$field_value
Definition: checkbox.php:24
$field
Definition: gquiz_grade.php:11
static getInstance()
Get the one true instantiated self.