Completed
Pull Request — develop (#1487)
by Zack
14:14 queued 02:44
created

GVCommon::get_template_settings()   A

Complexity

Conditions 2
Paths 2

Size

Total Lines 13

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 4
CRAP Score 2.032

Importance

Changes 0
Metric Value
cc 2
nc 2
nop 1
dl 0
loc 13
ccs 4
cts 5
cp 0.8
crap 2.032
rs 9.8333
c 0
b 0
f 0
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 <[email protected]>
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 33
	public static function get_form( $form_id ) {
28 33
		if ( empty( $form_id ) ) {
29
			return false;
30
		}
31
32
		// Only get_form_meta is cached. ::facepalm::
33 33
		if ( class_exists( 'GFFormsModel' ) ) {
34 33
			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 48
	public static function has_cap( $caps = '', $object_id = null, $user_id = null ) {
58 48
		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 3
	public static function get_all_views( $args = array() ) {
95
96
		$default_params = array(
97 3
			'post_type' => 'gravityview',
98
			'posts_per_page' => -1,
99
			'post_status' => 'publish',
100
		);
101
102 3
		$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 3
		$views_params = apply_filters( 'gravityview/get_all_views/params', $params );
109
110 3
		$views = get_posts( $views_params );
111
112 3
		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 6
	public static function has_product_field( $form = array() ) {
145
146 6
		$product_fields = self::get_product_field_types();
147
148 6
		$fields = GFAPI::get_fields_by_type( $form, $product_fields );
149
150 6
		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 23
	public static function get_product_field_types() {
163
164 23
		$product_fields = apply_filters( 'gform_product_field_types', array( 'option', 'quantity', 'product', 'total', 'shipping', 'calculation', 'price', 'hiddenproduct', 'singleproduct', 'singleshipping' ) );
165
166 23
		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 23
	public static function entry_has_transaction_data( $entry = array() ) {
181
182 23
		if ( ! is_array( $entry ) ) {
183 1
			return false;
184
		}
185
186 23
		$has_transaction_data = false;
187
188 23
		$payment_meta = array( 'payment_status', 'payment_date', 'transaction_id', 'payment_amount', 'payment_method' );
189
190 23
		foreach ( $payment_meta as $meta ) {
191
192 23
			$has_transaction_data = \GV\Utils::get( $entry, $meta, false );
193
194 23
			if ( is_numeric( $has_transaction_data ) && ( ! floatval( $has_transaction_data ) > 0 ) ) {
195 3
				$has_transaction_data = false;
196 3
				continue;
197
			}
198
199 23
			if ( ! empty( $has_transaction_data ) ) {
200 17
				break;
201
			}
202
		}
203
204 23
		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 1
	public static function get_forms(  $active = true, $trash = false, $order_by = 'id', $order = 'ASC' ) {
263 1
		$forms = array();
264 1
		if ( ! class_exists( 'GFAPI' ) ) {
265
			return array();
266
		}
267
268 1
		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 1
			$forms = GFAPI::get_forms( $active, $trash );
274
		}
275
276 1
		$forms = wp_list_sort( $forms, $order_by, $order, true );
277
278 1
		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
0 ignored issues
show
Bug introduced by
There is no parameter named $form_id. Was it maybe removed?

This check looks for PHPDoc comments describing methods or function parameters that do not exist on the corresponding method or function.

Consider the following example. The parameter $italy is not defined by the method finale(...).

/**
 * @param array $germany
 * @param array $island
 * @param array $italy
 */
function finale($germany, $island) {
    return "2:1";
}

The most likely cause is that the parameter was removed, but the annotation was not.

Loading history...
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 76
	public static function calculate_get_entries_criteria( $passed_criteria = array(), $form_ids = array() ) {
437
438
		$search_criteria_defaults = array(
439 76
			'search_criteria' => null,
440
			'sorting' => null,
441
			'paging' => null,
442 76
			'cache' => (isset( $passed_criteria['cache'] ) ? (bool) $passed_criteria['cache'] : true),
443
			'context_view_id' => null,
444
		);
445
446 76
		$criteria = wp_parse_args( $passed_criteria, $search_criteria_defaults );
447
448 76
		if ( ! empty( $criteria['search_criteria']['field_filters'] ) && is_array( $criteria['search_criteria']['field_filters'] ) ) {
449 23
			foreach ( $criteria['search_criteria']['field_filters'] as &$filter ) {
450
451 23
				if ( ! is_array( $filter ) ) {
452 22
					continue;
453
				}
454
455
				// By default, we want searches to be wildcard for each field.
456 23
				$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 23
				$filter['operator'] = apply_filters( 'gravityview_search_operator', $filter['operator'], $filter );
464
			}
465
466
			// don't send just the [mode] without any field filter.
467 23
			if( count( $criteria['search_criteria']['field_filters'] ) === 1 && array_key_exists( 'mode' , $criteria['search_criteria']['field_filters'] ) ) {
468 1
				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 76
		foreach ( array('start_date', 'end_date' ) as $key ) {
480
481 76
			if ( ! empty( $criteria['search_criteria'][ $key ] ) ) {
482
483
				// Use date_create instead of new DateTime so it returns false if invalid date format.
484 2
				$date = date_create( $criteria['search_criteria'][ $key ] );
485
486 2
				if ( $date ) {
487
					// Gravity Forms wants dates in the `Y-m-d H:i:s` format.
488 2
					$criteria['search_criteria'][ $key ] = $date->format( 'Y-m-d H:i:s' );
489
				} else {
490 1
					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 1
					unset( $criteria['search_criteria'][ $key ] );
494
				}
495
			}
496
		}
497
498 76
		if ( empty( $criteria['context_view_id'] ) ) {
499
			// Calculate the context view id and send it to the advanced filter
500 2
			if ( GravityView_frontend::getInstance()->getSingleEntry() ) {
501 1
				$criteria['context_view_id'] = GravityView_frontend::getInstance()->get_context_view_id();
502 2
			} else if ( class_exists( 'GravityView_View_Data' ) && GravityView_View_Data::getInstance() && GravityView_View_Data::getInstance()->has_multiple_views() ) {
0 ignored issues
show
Deprecated Code introduced by
The method GravityView_View_Data::has_multiple_views() has been deprecated.

This method has been deprecated.

Loading history...
503 1
				$criteria['context_view_id'] = GravityView_frontend::getInstance()->get_context_view_id();
504 2
			} else if ( 'delete' === GFForms::get( 'action' ) ) {
505 1
				$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 76
		$criteria = apply_filters( 'gravityview_search_criteria', $criteria, $form_ids, $criteria['context_view_id'] );
516
517 76
		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 3
	public static function get_entry_id( $entry_id_or_slug = '', $force_allow_ids = false ) {
631
632 3
		$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 3
		$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 3
		$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 3
		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 3
		if ( false === $custom_slug || true === $custom_slug_id_access ) {
660
			// Search for IDs matching $entry_slug
661 3
			$entry_id = $entry_id_or_slug;
662
		}
663
664 3
		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 32
	public static function get_entry( $entry_slug, $force_allow_ids = false, $check_entry_display = true, $view = null ) {
679
680 32
		if ( ! class_exists( 'GFAPI' ) || empty( $entry_slug ) ) {
681 30
			return false;
682
		}
683
684
685 3
		$entry_id = self::get_entry_id( $entry_slug, $force_allow_ids );
686
687 3
		if ( empty( $entry_id ) ) {
688
			return false;
689
		}
690
691
		// fetch the entry
692 3
		$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 3
		$check_entry_display = apply_filters( 'gravityview/common/get_entry/check_entry_display', $check_entry_display, $entry, $view );
703
704
		// Is the entry allowed
705 3
		if( $check_entry_display ) {
706
707 1
			$gvid = \GV\Utils::_GET( 'gvid' );
708
709 1
			if( $gvid ) {
710
				$view = \GV\View::by_id( $gvid );
711
			}
712
713 1
			$entry = self::check_entry_display( $entry, $view );
714
		}
715
716 3
		if( is_wp_error( $entry ) ) {
717 2
			gravityview()->log->error( '{error}', array( 'error' => $entry->get_error_message() ) );
718 2
			return false;
719
		}
720
721 2
		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 25
	public static function matches_operation( $val1, $val2, $operation ) {
743
744
		// Only process strings
745 25
		$val1 = ! is_string( $val1 ) ? wp_json_encode( $val1 ) : $val1;
746 25
		$val2 = ! is_string( $val2 ) ? wp_json_encode( $val2 ) : $val2;
747
748 25
		$value = false;
749
750 25
		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;
0 ignored issues
show
Deprecated Code introduced by
The function gravityview_get_context() has been deprecated with message: since 2.0.6.2 Use `gravityview()->request`

This function has been deprecated. The supplier of the file has supplied an explanatory message.

The explanatory message should give you some clue as to whether and when the function will be removed from the class and what other function to use instead.

Loading history...
767
		}
768
769 25
		switch ( $operation ) {
770 25
			case 'equals':
771 7
				$value = self::matches_operation( $val1, $val2, 'is' );
772 7
				break;
773 25
			case 'greater_than_or_is':
774 25
			case 'greater_than_or_equals':
775 5
				$is    = self::matches_operation( $val1, $val2, 'is' );
776 5
				$gt    = self::matches_operation( $val1, $val2, 'greater_than' );
777 5
				$value = ( $is || $gt );
778 5
				break;
779 25
			case 'less_than_or_is':
780 25
			case 'less_than_or_equals':
781 3
				$is    = self::matches_operation( $val1, $val2, 'is' );
782 3
				$gt    = self::matches_operation( $val1, $val2, 'less_than' );
783 3
				$value = ( $is || $gt );
784 3
				break;
785 25
			case 'not_contains':
786 1
				$contains = self::matches_operation( $val1, $val2, 'contains' );
787 1
				$value    = ! $contains;
788 1
				break;
789
			/**
790
			 * @since 1.22.1 Handle JSON-encoded comparisons
791
			 */
792 25
			case 'in':
793 25
			case 'not_in':
794
795 1
				$json_val_1 = json_decode( $val1, true );
796 1
				$json_val_2 = json_decode( $val2, true );
797
798 1
				if( ! empty( $json_val_1 ) || ! empty( $json_val_2 ) ) {
799
800 1
					$json_in = false;
801 1
					$json_val_1 = $json_val_1 ? (array) $json_val_1 : array( $val1 );
802 1
					$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 1
					foreach ( $json_val_1 as $item_1 ) {
806 1
						foreach ( $json_val_2 as $item_2 ) {
807 1
							$json_in = self::matches_operation( $item_1, $item_2, 'is' );
808
809 1
							if( $json_in ) {
810 1
								break 2;
811
							}
812
						}
813
					}
814
815 1
					$value = ( $operation === 'in' ) ? $json_in : ! $json_in;
816
				}
817 1
				break;
818
819 25
			case 'less_than':
820 23
			case '<' :
821 5
				if ( is_string( $val1 ) && is_string( $val2 ) ) {
822 5
					$value = $val1 < $val2;
823
				} else {
824
					$value = GFFormsModel::matches_operation( $val1, $val2, $operation );
825
				}
826 5
				break;
827 23
			case 'greater_than':
828 21
			case '>' :
829 9
				if ( is_string( $val1 ) && is_string( $val2 ) ) {
830 9
					$value = $val1 > $val2;
831
				} else {
832
					$value = GFFormsModel::matches_operation( $val1, $val2, $operation );
833
				}
834 9
				break;
835
			default:
836 21
				$value = GFFormsModel::matches_operation( $val1, $val2, $operation );
837
		}
838
839 25
		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 13
	public static function check_entry_display( $entry, $view = null ) {
858
859 13
		if ( ! $entry || is_wp_error( $entry ) ) {
0 ignored issues
show
Bug Best Practice introduced by
The expression $entry of type array is implicitly converted to a boolean; are you sure this is intended? If so, consider using empty($expr) instead to make it clear that you intend to check for an array without elements.

This check marks implicit conversions of arrays to boolean values in a comparison. While in PHP an empty array is considered to be equal (but not identical) to false, this is not always apparent.

Consider making the comparison explicit by using empty(..) or ! empty(...) instead.

Loading history...
860 1
			return new WP_Error('entry_not_found', 'Entry was not found.', $entry );
861
		}
862
863 13
		if ( empty( $entry['form_id'] ) ) {
864 1
			return new WP_Error( 'form_id_not_set', '[apply_filters_to_entry] Entry is empty!', $entry );
865
		}
866
867 13
		if ( is_null( $view ) ) {
868 3
			gravityview()->log->warning( '$view was not supplied to check_entry_display, results will be non-typical.' );
869 3
			return new WP_Error( 'view_not_supplied', 'View is not supplied!', $entry );
870
		}
871
872 12
		if ( ! gravityview()->plugin->supports( \GV\Plugin::FEATURE_GFQUERY ) ) {
873
			return new WP_Error( 'no_gf_query', 'GF_Query is missing.', $entry );
874
		}
875
876 12
		$_gvid = \GV\Utils::_GET( 'gvid' );
877
878 12
		if ( $_gvid && $view->ID !== (int) $_gvid ) {
879 1
			return new WP_Error( 'view_id_not_match_gvid', 'View does not match passed $_GET["gvid"].', $view->ID );
880
		}
881
882 12
		$view_form_id = $view->form->ID;
883
884 12
		if ( $view->joins ) {
885 1
			if ( in_array( (int) $entry['form_id'], array_keys( $view::get_joined_forms( $view->ID ) ), true ) ) {
886 1
				$view_form_id = $entry['form_id'];
887
			}
888
		}
889
890 12
		if ( (int) $view_form_id !== (int) $entry['form_id'] ) {
891 1
			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 ) {
0 ignored issues
show
Unused Code introduced by
The parameter $view is not used and could be removed.

This check looks from parameters that have been defined for a function or method, but which are not used in the method body.

Loading history...
Unused Code introduced by
The parameter $request is not used and could be removed.

This check looks from parameters that have been defined for a function or method, but which are not used in the method body.

Loading history...
898 12
			$_tmp_query       = new \GF_Query( $view_form_id, array(
899
				'field_filters' => array(
900 12
					'mode' => 'all',
901
					array(
902 12
						'key' => 'id',
903 12
						'operation' => 'is',
904 12
						'value' => $entry['id']
905
					)
906
				)
907
			) );
908
909 12
			$_tmp_query_parts = $_tmp_query->_introspect();
910
911
			/** @type \GF_Query $query */
912 12
			$query_parts      = $query->_introspect();
913
914 12
			$query->where( \GF_Query_Condition::_and( $_tmp_query_parts['where'], $query_parts['where'] ) );
915
916 12
		}, 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 12
			$criteria['paging'] = array(
922
				'offset' => 0,
923
				'page_size' => 25
924
			);
925
926 12
			return $criteria;
927 12
		} );
928
929 12
		$entries = $view->get_entries()->all();
0 ignored issues
show
Bug introduced by
The method get_entries does only exist in GV\View, but not in GV\View_Collection.

It seems like the method you are trying to call exists only in some of the possible types.

Let’s take a look at an example:

class A
{
    public function foo() { }
}

class B extends A
{
    public function bar() { }
}

/**
 * @param A|B $x
 */
function someFunction($x)
{
    $x->foo(); // This call is fine as the method exists in A and B.
    $x->bar(); // This method only exists in B and might cause an error.
}

Available Fixes

  1. Add an additional type-check:

    /**
     * @param A|B $x
     */
    function someFunction($x)
    {
        $x->foo();
    
        if ($x instanceof B) {
            $x->bar();
        }
    }
    
  2. Only allow a single type to be passed if the variable comes from a parameter:

    function someFunction(B $x) { /** ... */ }
    
Loading history...
930
931
		// Remove the modifying filter
932 12
		remove_filter( 'gravityview_search_criteria', $remove_pagenum );
933
934 12
		if ( ! $entries ) {
935 8
			remove_action( 'gravityview/view/query', $entry_subset_callback );
936 8
			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 11
		if ( $entries[0]->is_multi() ) {
941
942 1
			$multi_entry_ids = array();
943
944 1
			foreach ( $entries[0]->entries as $multi_entry ) {
945 1
				$multi_entry_ids[] = (int) $multi_entry->ID;
946
			}
947
948 1
			if ( ! in_array( (int) $entry['id'], $multi_entry_ids, true ) ) {
949
				remove_action( 'gravityview/view/query', $entry_subset_callback );
950 1
				return new \WP_Error( 'failed_criteria', 'Entry failed search_criteria and field_filters' );
951
			}
952
953 10
		} 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 11
		remove_action( 'gravityview/view/query', $entry_subset_callback );
959 11
		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 6
	public static function format_date( $date_string = '', $args = array() ) {
982
983
		$default_atts = array(
984 6
			'raw' => false,
985
			'timestamp' => false,
986
			'diff' => false,
987
			'human' => false,
988
			'format' => '',
989
			'time' => false,
990
		);
991
992 6
		$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 6
		$date_gmt_time   = mysql2date( 'G', $date_string );
999 6
		$date_local_timestamp = GFCommon::get_local_timestamp( $date_gmt_time );
1000
1001 6
		$format  = \GV\Utils::get( $atts, 'format' );
1002 6
		$is_human  = ! empty( $atts['human'] );
1003 6
		$is_diff  = ! empty( $atts['diff'] );
1004 6
		$is_raw = ! empty( $atts['raw'] );
1005 6
		$is_timestamp = ! empty( $atts['timestamp'] );
1006 6
		$include_time = ! empty( $atts['time'] );
1007
1008
		// If we're using time diff, we want to have a different default format
1009 6
		if( empty( $format ) ) {
1010
			/* translators: %s: relative time from now, used for generic date comparisons. "1 day ago", or "20 seconds ago" */
1011 5
			$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 6
		if ( $is_raw ) {
1016 2
			$formatted_date = $date_string;
1017 6
		} elseif( $is_timestamp ) {
1018 3
			$formatted_date = $date_local_timestamp;
1019 5
		} elseif ( $is_diff ) {
1020 2
			$formatted_date = sprintf( $format, human_time_diff( $date_gmt_time ) );
1021
		} else {
1022 5
			$formatted_date = GFCommon::format_date( $date_string, $is_human, $format, $include_time );
1023
		}
1024
1025 6
		unset( $format, $is_diff, $is_human, $is_timestamp, $is_raw, $date_gmt_time, $date_local_timestamp, $default_atts );
1026
1027 6
		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 1
	public static function get_field_label( $form = array(), $field_id = '', $field_value = '' ) {
1041
1042 1
		if ( empty( $form ) || empty( $field_id ) ) {
1043
			return '';
1044
		}
1045
1046 1
		$field = self::get_field( $form, $field_id );
1047
1048 1
		$label = \GV\Utils::get( $field, 'label' );
1049
1050 1
		if( floor( $field_id ) !== floatval( $field_id ) ) {
1051 1
			$label = GFFormsModel::get_choice_text( $field, $field_value, $field_id );
1052
		}
1053
1054 1
		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 9
	public static function get_field( $form, $field_id ) {
1072
1073 9
		if ( is_numeric( $form ) ) {
1074
			$form = GFAPI::get_form( $form );
1075
		}
1076
1077 9
		if ( class_exists( 'GFFormsModel' ) ){
1078 9
			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 2
	public static function has_gravityview_shortcode( $post = null ) {
1095 2
		if ( ! is_a( $post, 'WP_Post' ) ) {
1096 1
			return false;
1097
		}
1098
1099 2
		if ( 'gravityview' === get_post_type( $post ) ) {
1100 2
			return true;
1101
		}
1102
1103 2
		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 4
	public static function has_shortcode_r( $content, $tag = 'gravityview' ) {
1115 4
		if ( false === strpos( $content, '[' ) ) {
1116 2
			return false;
1117
		}
1118
1119 4
		if ( shortcode_exists( $tag ) ) {
1120
1121 4
			$shortcodes = array();
1122
1123 4
			preg_match_all( '/' . get_shortcode_regex() . '/s', $content, $matches, PREG_SET_ORDER );
1124 4
			if ( empty( $matches ) ){
1125 1
				return false;
1126
			}
1127
1128 4
			foreach ( $matches as $shortcode ) {
1129 4
				if ( $tag === $shortcode[2] ) {
1130
1131
					// Changed this to $shortcode instead of true so we get the parsed atts.
1132 4
					$shortcodes[] = $shortcode;
1133
1134 1
				} else if ( isset( $shortcode[5] ) && $results = self::has_shortcode_r( $shortcode[5], $tag ) ) {
1135 1
					foreach( $results as $result ) {
1136 1
						$shortcodes[] = $result;
1137
					}
1138
				}
1139
			}
1140
1141 4
			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 1
	public static function get_connected_views( $form_id, $args = array() ) {
1161
1162 1
		global $wpdb;
1163
1164
		$defaults = array(
1165 1
			'post_type'      => 'gravityview',
1166 1
			'posts_per_page' => 100,
1167 1
			'meta_key'       => '_gravityview_form_id',
1168 1
			'meta_value'     => (int) $form_id,
1169
		);
1170 1
		$args     = wp_parse_args( $args, $defaults );
1171 1
		$views    = get_posts( $args );
1172
1173 1
		$views_with_joins = $wpdb->get_results( "SELECT `post_id`, `meta_value` FROM $wpdb->postmeta WHERE `meta_key` = '_gravityview_form_joins'" );
1174
1175 1
		$joined_forms = array();
1176 1
		foreach ( $views_with_joins as $view ) {
1177
1178 1
			$data = unserialize( $view->meta_value );
1179
1180 1
			if( ! $data || ! is_array( $data ) ) {
1181 1
				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 1
		if ( $joined_forms ) {
0 ignored issues
show
Bug Best Practice introduced by
The expression $joined_forms of type array is implicitly converted to a boolean; are you sure this is intended? If so, consider using ! empty($expr) instead to make it clear that you intend to check for an array without elements.

This check marks implicit conversions of arrays to boolean values in a comparison. While in PHP an empty array is considered to be equal (but not identical) to false, this is not always apparent.

Consider making the comparison explicit by using empty(..) or ! empty(...) instead.

Loading history...
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 1
		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 1
	public static function get_meta_form_id( $view_id ) {
1211 1
		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 184
	public static function get_meta_template_id( $view_id ) {
1224 184
		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 183
	public static function get_template_settings( $post_id ) {
1236
1237 183
		$settings = get_post_meta( $post_id, '_gravityview_template_settings', true );
1238
1239 183
		if ( class_exists( '\GV\View_Settings' ) ) {
1240
1241 183
			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 1
	public static function get_template_setting( $post_id, $key ) {
1259
1260 1
		$settings = self::get_template_settings( $post_id );
1261
1262 1
		if ( isset( $settings[ $key ] ) ) {
1263 1
			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 1
	public static function get_directory_fields( $post_id, $apply_filter = true ) {
1303 1
		$fields = get_post_meta( $post_id, '_gravityview_directory_fields', true );
1304
1305 1
		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 1
			$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 1
			$fields = apply_filters( 'gravityview/view/configuration/fields', $fields, \GV\View::by_id( $post_id ) );
1323
		}
1324
1325 1
		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
		// Are there custom content fields?
1419
		if ( is_admin() ) {
1420
			$view = \GV\View::by_id( \GV\Utils::_GET( 'post' ) );
1421
1422
			if ( $view ) {
1423
				foreach ( $view->fields->by_type( 'custom' )->all() as $custom ) {
1424
					$fields[ 'custom_' . $custom->UID ] = array(
1425
						'type'  => 'custom',
1426
						'label' => __( 'Custom Content', 'gravityview' ) . ': ' . $custom->admin_label,
0 ignored issues
show
Documentation introduced by
The property admin_label does not exist on object<GV\Field>. Since you implemented __get, maybe consider adding a @property annotation.

Since your code implements the magic getter _get, this function will be called for any read access on an undefined variable. You can add the @property annotation to your class or interface to document the existence of this variable.

<?php

/**
 * @property int $x
 * @property int $y
 * @property string $text
 */
class MyLabel
{
    private $properties;

    private $allowedProperties = array('x', 'y', 'text');

    public function __get($name)
    {
        if (isset($properties[$name]) && in_array($name, $this->allowedProperties)) {
            return $properties[$name];
        } else {
            return null;
        }
    }

    public function __set($name, $value)
    {
        if (in_array($name, $this->allowedProperties)) {
            $properties[$name] = $value;
        } else {
            throw new \LogicException("Property $name is not defined.");
        }
    }

}

If the property has read access only, you can use the @property-read annotation instead.

Of course, you may also just have mistyped another name, in which case you should fix the error.

See also the PhpDoc documentation for @property.

Loading history...
1427
					);
1428
				}
1429
			}
1430
		}
1431
1432
		$blacklist_field_types = apply_filters( 'gravityview_blacklist_field_types', $blacklist, NULL );
1433
1434
		// TODO: Convert to using array_filter
1435
		foreach( $fields as $id => $field ) {
1436
1437
			if( in_array( $field['type'], $blacklist_field_types ) ) {
1438
				unset( $fields[ $id ] );
1439
			}
1440
1441
			/**
1442
			 * Merge date and time subfields.
1443
			 */
1444
			if ( in_array( $field['type'], array( 'date', 'time' ) ) && ! empty( $field['parent'] ) ) {
1445
				$fields[ intval( $id ) ] = array(
1446
					'label' => \GV\Utils::get( $field, 'parent/label' ),
1447
					'parent' => null,
1448
					'type' => \GV\Utils::get( $field, 'parent/type' ),
1449
					'adminLabel' => \GV\Utils::get( $field, 'parent/adminLabel' ),
1450
					'adminOnly' => \GV\Utils::get( $field, 'parent/adminOnly' ),
1451
				);
1452
1453
				unset( $fields[ $id ] );
1454
			}
1455
1456
		}
1457
1458
        /**
1459
         * @filter `gravityview/common/sortable_fields` Filter the sortable fields
1460
         * @since 1.12
1461
         * @param array $fields Sub-set of GF form fields that are sortable
1462
         * @param int $formid The Gravity Forms form ID that the fields are from
1463
         */
1464
        $fields = apply_filters( 'gravityview/common/sortable_fields', $fields, $formid );
1465
1466
		return $fields;
1467
	}
1468
1469
	/**
1470
	 * Returns the GF Form field type for a certain field(id) of a form
1471
	 * @param  object $form     Gravity Forms form
1472
	 * @param  mixed $field_id Field ID or Field array
1473
	 * @return string field type
1474
	 */
1475 4
	public static function get_field_type( $form = null, $field_id = '' ) {
1476
1477 4
		if ( ! empty( $field_id ) && ! is_array( $field_id ) ) {
1478 4
			$field = self::get_field( $form, $field_id );
1479
		} else {
1480
			$field = $field_id;
1481
		}
1482
1483 4
		return class_exists( 'RGFormsModel' ) ? RGFormsModel::get_input_type( $field ) : '';
1484
1485
	}
1486
1487
1488
	/**
1489
	 * Checks if the field type is a 'numeric' field type (e.g. to be used when sorting)
1490
	 * @param  int|array  $form  form ID or form array
1491
	 * @param  int|array  $field field key or field array
1492
	 * @return boolean
1493
	 */
1494 6
	public static function is_field_numeric(  $form = null, $field = '' ) {
1495
1496 6
		if ( ! is_array( $form ) && ! is_array( $field ) ) {
1497 6
			$form = self::get_form( $form );
1498
		}
1499
1500
		// If entry meta, it's a string. Otherwise, numeric
1501 6
		if( ! is_numeric( $field ) && is_string( $field ) ) {
1502 2
			$type = $field;
1503
		} else {
1504 4
			$type = self::get_field_type( $form, $field );
1505
		}
1506
1507
		/**
1508
		 * @filter `gravityview/common/numeric_types` What types of fields are numeric?
1509
		 * @since 1.5.2
1510
		 * @param array $numeric_types Fields that are numeric. Default: `[ number, time ]`
1511
		 */
1512 6
		$numeric_types = apply_filters( 'gravityview/common/numeric_types', array( 'number', 'time' ) );
1513
1514
		// Defer to GravityView_Field setting, if the field type is registered and `is_numeric` is true
1515 6
		if( $gv_field = GravityView_Fields::get( $type ) ) {
1516 4
			if( true === $gv_field->is_numeric ) {
1517
				$numeric_types[] = $gv_field->is_numeric;
1518
			}
1519
		}
1520
1521 6
		$return = in_array( $type, $numeric_types );
1522
1523 6
		return $return;
1524
	}
1525
1526
	/**
1527
	 * Encrypt content using Javascript so that it's hidden when JS is disabled.
1528
	 *
1529
	 * This is mostly used to hide email addresses from scraper bots.
1530
	 *
1531
	 * @param string $content Content to encrypt
1532
	 * @param string $message Message shown if Javascript is disabled
1533
	 *
1534
	 * @see  https://github.com/katzwebservices/standalone-phpenkoder StandalonePHPEnkoder on Github
1535
	 *
1536
	 * @since 1.7
1537
	 *
1538
	 * @return string Content, encrypted
1539
	 */
1540
	public static function js_encrypt( $content, $message = '' ) {
1541
1542
		$output = $content;
1543
1544
		if ( ! class_exists( 'StandalonePHPEnkoder' ) ) {
1545
			include_once( GRAVITYVIEW_DIR . 'includes/lib/StandalonePHPEnkoder.php' );
1546
		}
1547
1548
		if ( class_exists( 'StandalonePHPEnkoder' ) ) {
1549
1550
			$enkoder = new StandalonePHPEnkoder;
1551
1552
			$message = empty( $message ) ? __( 'Email hidden; Javascript is required.', 'gravityview' ) : $message;
1553
1554
			/**
1555
			 * @filter `gravityview/phpenkoder/msg` Modify the message shown when Javascript is disabled and an encrypted email field is displayed
1556
			 * @since 1.7
1557
			 * @param string $message Existing message
1558
			 * @param string $content Content to encrypt
1559
			 */
1560
			$enkoder->enkode_msg = apply_filters( 'gravityview/phpenkoder/msg', $message, $content );
1561
1562
			$output = $enkoder->enkode( $content );
1563
		}
1564
1565
		return $output;
1566
	}
1567
1568
	/**
1569
	 *
1570
	 * Do the same than parse_str without max_input_vars limitation:
1571
	 * Parses $string as if it were the query string passed via a URL and sets variables in the current scope.
1572
	 * @param $string string string to parse (not altered like in the original parse_str(), use the second parameter!)
1573
	 * @param $result array  If the second parameter is present, variables are stored in this variable as array elements
1574
	 * @return bool true or false if $string is an empty string
1575
	 * @since  1.5.3
1576
	 *
1577
	 * @see https://gist.github.com/rubo77/6821632
1578
	 **/
1579
	public static function gv_parse_str( $string, &$result ) {
1580
		if ( empty( $string ) ) {
1581
			return false;
1582
		}
1583
1584
		$result = array();
1585
1586
		// find the pairs "name=value"
1587
		$pairs = explode( '&', $string );
1588
1589
		foreach ( $pairs as $pair ) {
1590
			// use the original parse_str() on each element
1591
			parse_str( $pair, $params );
1592
1593
			$k = key( $params );
1594
			if ( ! isset( $result[ $k ] ) ) {
1595
				$result += $params;
1596
			} elseif ( array_key_exists( $k, $params ) && is_array( $params[ $k ] ) ) {
1597
				$result[ $k ] = self::array_merge_recursive_distinct( $result[ $k ], $params[ $k ] );
1598
			}
1599
		}
1600
		return true;
1601
	}
1602
1603
1604
	/**
1605
	 * Generate an HTML anchor tag with a list of supported attributes
1606
	 *
1607
	 * @see https://developer.mozilla.org/en-US/docs/Web/HTML/Element/a Supported attributes defined here
1608
	 * @uses esc_url_raw() to sanitize $href
1609
	 * @uses esc_attr() to sanitize $atts
1610
	 *
1611
	 * @since 1.6
1612
	 *
1613
	 * @param string $href URL of the link. Sanitized using `esc_url_raw()`
1614
	 * @param string $anchor_text The text or HTML inside the anchor. This is not sanitized in the function.
1615
	 * @param array|string $atts Attributes to be added to the anchor tag. Parsed by `wp_parse_args()`, sanitized using `esc_attr()`
1616
	 *
1617
	 * @return string HTML output of anchor link. If empty $href, returns NULL
1618
	 */
1619 56
	public static function get_link_html( $href = '', $anchor_text = '', $atts = array() ) {
1620
1621
		// Supported attributes for anchor tags. HREF left out intentionally.
1622
		$allowed_atts = array(
1623 56
			'href' => null, // Will override the $href argument if set
1624
			'title' => null,
1625
			'rel' => null,
1626
			'id' => null,
1627
			'class' => null,
1628
			'target' => null,
1629
			'style' => null,
1630
1631
			// Used by GravityView
1632
			'data-viewid' => null,
1633
1634
			// Not standard
1635
			'hreflang' => null,
1636
			'type' => null,
1637
			'tabindex' => null,
1638
1639
			// Deprecated HTML4 but still used
1640
			'name' => null,
1641
			'onclick' => null,
1642
			'onchange' => null,
1643
			'onkeyup' => null,
1644
1645
			// HTML5 only
1646
			'download' => null,
1647
			'media' => null,
1648
			'ping' => null,
1649
		);
1650
1651
		/**
1652
		 * @filter `gravityview/get_link/allowed_atts` Modify the attributes that are allowed to be used in generating links
1653
		 * @since 1.6
1654
		 * @param array $allowed_atts Array of attributes allowed
1655
		 */
1656 56
		$allowed_atts = apply_filters( 'gravityview/get_link/allowed_atts', $allowed_atts );
1657
1658
		// Make sure the attributes are formatted as array
1659 56
		$passed_atts = wp_parse_args( $atts );
1660
1661
		// Make sure the allowed attributes are only the ones in the $allowed_atts list
1662 56
		$final_atts = shortcode_atts( $allowed_atts, $passed_atts );
1663
1664
		// Remove attributes with empty values
1665 56
		$final_atts = array_filter( $final_atts );
1666
1667
		// If the href wasn't passed as an attribute, use the value passed to the function
1668 56
		if ( empty( $final_atts['href'] ) && ! empty( $href ) ) {
1669 56
			$final_atts['href'] = $href;
1670
		}
1671
1672 56
		$final_atts['href'] = esc_url_raw( $href );
1673
1674
		/**
1675
		 * Fix potential security issue with target=_blank
1676
		 * @see https://dev.to/ben/the-targetblank-vulnerability-by-example
1677
		 */
1678 56
		if( '_blank' === \GV\Utils::get( $final_atts, 'target' ) ) {
1679 4
			$final_atts['rel'] = trim( \GV\Utils::get( $final_atts, 'rel', '' ) . ' noopener noreferrer' );
1680
		}
1681
1682
		// Sort the attributes alphabetically, to help testing
1683 56
		ksort( $final_atts );
1684
1685
		// For each attribute, generate the code
1686 56
		$output = '';
1687 56
		foreach ( $final_atts as $attr => $value ) {
1688 56
			$output .= sprintf( ' %s="%s"', $attr, esc_attr( $value ) );
1689
		}
1690
1691 56
		if( '' !== $output ) {
1692 56
			$output = '<a' . $output . '>' . $anchor_text . '</a>';
1693
		}
1694
1695 56
		return $output;
1696
	}
1697
1698
	/**
1699
	 * array_merge_recursive does indeed merge arrays, but it converts values with duplicate
1700
	 * keys to arrays rather than overwriting the value in the first array with the duplicate
1701
	 * value in the second array, as array_merge does.
1702
	 *
1703
	 * @see http://php.net/manual/en/function.array-merge-recursive.php
1704
	 *
1705
	 * @since  1.5.3
1706
	 * @param array $array1
1707
	 * @param array $array2
1708
	 * @return array
1709
	 * @author Daniel <[email protected]>
1710
	 * @author Gabriel Sobrinho <[email protected]>
1711
	 */
1712
	public static function array_merge_recursive_distinct( array &$array1, array &$array2 ) {
1713
		$merged = $array1;
1714
		foreach ( $array2 as $key => $value ) {
1715
			if ( is_array( $value ) && isset( $merged[ $key ] ) && is_array( $merged[ $key ] ) ) {
1716
				$merged[ $key ] = self::array_merge_recursive_distinct( $merged[ $key ], $value );
1717
			} else if ( is_numeric( $key ) && isset( $merged[ $key ] ) ) {
1718
				$merged[] = $value;
1719
			} else {
1720
				$merged[ $key ] = $value;
1721
			}
1722
		}
1723
1724
		return $merged;
1725
	}
1726
1727
	/**
1728
	 * Get WordPress users with reasonable limits set
1729
	 *
1730
	 * @param string $context Where are we using this information (e.g. change_entry_creator, search_widget ..)
1731
	 * @param array $args Arguments to modify the user query. See get_users() {@since 1.14}
1732
	 * @return array Array of WP_User objects.
1733
	 */
1734 1
	public static function get_users( $context = 'change_entry_creator', $args = array() ) {
1735
1736
		$default_args = array(
1737 1
			'number' => 2000,
1738
			'orderby' => 'display_name',
1739
			'order' => 'ASC',
1740
			'fields' => array( 'ID', 'display_name', 'user_login', 'user_nicename' )
1741
		);
1742
1743
		// Merge in the passed arg
1744 1
		$get_users_settings = wp_parse_args( $args, $default_args );
1745
1746
		/**
1747
		 * @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
1748
		 * `$context` is where are we using this information (e.g. change_entry_creator, search_widget ..)
1749
		 * @param array $settings Settings array, with `number` key defining the # of users to display
1750
		 */
1751 1
		$get_users_settings = apply_filters( 'gravityview/get_users/'. $context, apply_filters( 'gravityview_change_entry_creator_user_parameters', $get_users_settings ) );
1752
1753 1
		return get_users( $get_users_settings );
1754
	}
1755
1756
1757
    /**
1758
     * Display updated/error notice
1759
     *
1760
     * @since 1.19.2 Added $cap and $object_id parameters
1761
     *
1762
     * @param string $notice text/HTML of notice
1763
     * @param string $class CSS class for notice (`updated` or `error`)
1764
     * @param string $cap [Optional] Define a capability required to show a notice. If not set, displays to all caps.
1765
     *
1766
     * @return string
1767
     */
1768 29
    public static function generate_notice( $notice, $class = '', $cap = '', $object_id = null ) {
1769
1770
    	// If $cap is defined, only show notice if user has capability
1771 29
    	if( $cap && ! GVCommon::has_cap( $cap, $object_id ) ) {
1772 8
    		return '';
1773
	    }
1774
1775 23
        return '<div class="gv-notice '.gravityview_sanitize_html_class( $class ) .'">'. $notice .'</div>';
1776
    }
1777
1778
	/**
1779
	 * Inspired on \GFCommon::encode_shortcodes, reverse the encoding by replacing the ascii characters by the shortcode brackets
1780
	 * @since 1.16.5
1781
	 * @param string $string Input string to decode
1782
	 * @return string $string Output string
1783
	 */
1784
	public static function decode_shortcodes( $string ) {
1785
		$replace = array( '[', ']', '"' );
1786
		$find = array( '&#91;', '&#93;', '&quot;' );
1787
		$string = str_replace( $find, $replace, $string );
1788
1789
		return $string;
1790
	}
1791
1792
1793
	/**
1794
	 * Send email using GFCommon::send_email()
1795
	 *
1796
	 * @since 1.17
1797
	 *
1798
	 * @see GFCommon::send_email This just makes the method public
1799
	 *
1800
	 * @param string $from               Sender address (required)
1801
	 * @param string $to                 Recipient address (required)
1802
	 * @param string $bcc                BCC recipients (required)
1803
	 * @param string $reply_to           Reply-to address (required)
1804
	 * @param string $subject            Subject line (required)
1805
	 * @param string $message            Message body (required)
1806
	 * @param string $from_name          Displayed name of the sender
1807
	 * @param string $message_format     If "html", sent text as `text/html`. Otherwise, `text/plain`. Default: "html".
1808
	 * @param string|array $attachments  Optional. Files to attach. {@see wp_mail()} for usage. Default: "".
1809
	 * @param array|false $entry         Gravity Forms entry array, related to the email. Default: false.
1810
	 * @param array|false $notification  Gravity Forms notification that triggered the email. {@see GFCommon::send_notification}. Default:false.
1811
	 */
1812
	public static function send_email( $from, $to, $bcc, $reply_to, $subject, $message, $from_name = '', $message_format = 'html', $attachments = '', $entry = false, $notification = false ) {
1813
1814
		$SendEmail = new ReflectionMethod( 'GFCommon', 'send_email' );
1815
1816
		// It was private; let's make it public
1817
		$SendEmail->setAccessible( true );
1818
1819
		// Required: $from, $to, $bcc, $replyTo, $subject, $message
1820
		// Optional: $from_name, $message_format, $attachments, $lead, $notification
1821
		$SendEmail->invoke( new GFCommon, $from, $to, $bcc, $reply_to, $subject, $message, $from_name, $message_format, $attachments, $entry, $notification );
1822
	}
1823
1824
1825
} //end class
1826
1827
1828
/**
1829
 * Generate an HTML anchor tag with a list of supported attributes
1830
 *
1831
 * @see GVCommon::get_link_html()
1832
 *
1833
 * @since 1.6
1834
 *
1835
 * @param string $href URL of the link.
1836
 * @param string $anchor_text The text or HTML inside the anchor. This is not sanitized in the function.
1837
 * @param array|string $atts Attributes to be added to the anchor tag
1838
 *
1839
 * @return string HTML output of anchor link. If empty $href, returns NULL
1840
 */
1841
function gravityview_get_link( $href = '', $anchor_text = '', $atts = array() ) {
1842 55
	return GVCommon::get_link_html( $href, $anchor_text, $atts );
1843
}
1844