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