Completed
Push — develop ( 5b8f3d...365b4b )
by Zack
11s
created

includes/class-api.php (1 issue)

Upgrade to new PHP Analysis Engine

These results are based on our legacy PHP analysis, consider migrating to our new PHP analysis engine instead. Learn more

1
<?php
2
/**
3
 * GravityView template tags API
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.0.0
12
 */
13
14
class GravityView_API {
15
16
	/**
17
	 * Fetch Field Label
18
	 *
19
	 * @access public
20
	 * @static
21
	 * @param array $field GravityView field array
22
	 * @param array $entry Gravity Forms entry array
23
	 * @param boolean $force_show_label Whether to always show the label, regardless of field settings
24
	 * @return string
25
	 */
26
	public static function field_label( $field, $entry = array(), $force_show_label = false ) {
27
		$gravityview_view = GravityView_View::getInstance();
28
29
		$form = $gravityview_view->getForm();
30
31
		$label = '';
32
33
		if( !empty( $field['show_label'] ) || $force_show_label ) {
34
35
			$label = $field['label'];
36
37
			// Support Gravity Forms 1.9+
38
			if( class_exists( 'GF_Field' ) ) {
39
40
				$field_object = RGFormsModel::get_field( $form, $field['id'] );
41
42
				if( $field_object ) {
43
44
					$input = GFFormsModel::get_input( $field_object, $field['id'] );
45
46
					// This is a complex field, with labels on a per-input basis
47
					if( $input ) {
48
49
						// Does the input have a custom label on a per-input basis? Otherwise, default label.
50
						$label = ! empty( $input['customLabel'] ) ? $input['customLabel'] : $input['label'];
51
52
					} else {
53
54
						// This is a field with one label
55
						$label = $field_object->get_field_label( true, $field['label'] );
56
57
					}
58
59
				}
60
61
			}
62
63
			// Use Gravity Forms label by default, but if a custom label is defined in GV, use it.
64
			if ( !empty( $field['custom_label'] ) ) {
65
66
				$label = self::replace_variables( $field['custom_label'], $form, $entry );
67
68
			}
69
70
			/**
71
			 * @filter `gravityview_render_after_label` Append content to a field label
72
			 * @param[in,out] string $appended_content Content you can add after a label. Empty by default.
73
			 * @param[in] array $field GravityView field array
74
			 */
75
			$label .= apply_filters( 'gravityview_render_after_label', '', $field );
76
77
		} // End $field['show_label']
78
79
		/**
80
		 * @filter `gravityview/template/field_label` Modify field label output
81
		 * @since 1.7
82
		 * @param[in,out] string $label Field label HTML
83
		 * @param[in] array $field GravityView field array
84
		 * @param[in] array $form Gravity Forms form array
85
		 * @param[in] array $entry Gravity Forms entry array
86
		 */
87
		$label = apply_filters( 'gravityview/template/field_label', $label, $field, $form, $entry );
88
89
		return $label;
90
	}
91
92
	/**
93
	 * Alias for GravityView_Merge_Tags::replace_variables()
94
	 *
95
	 * @see GravityView_Merge_Tags::replace_variables() Moved in 1.8.4
96
	 *
97
	 * @param  string      $text       Text to replace variables in
98
	 * @param  array      $form        GF Form array
99
	 * @param  array      $entry        GF Entry array
100
	 * @return string                  Text with variables maybe replaced
101
	 */
102
	public static function replace_variables( $text, $form = array(), $entry = array() ) {
103
		return GravityView_Merge_Tags::replace_variables( $text, $form, $entry );
104
	}
105
106
	/**
107
	 * Get column width from the field setting
108
	 *
109
	 * @since 1.9
110
	 *
111
	 * @param array $field Array of settings for the field
112
	 * @param string $format Format for width. "%" (default) will return
113
	 *
114
	 * @return string|null If not empty, string in $format format. Otherwise, null.
115
	 */
116
	public static function field_width( $field, $format = '%d%%' ) {
117
118
		$width = NULL;
119
120
		if( !empty( $field['width'] ) ) {
121
			$width = absint( $field['width'] );
122
123
			// If using percentages, limit to 100%
124
			if( '%d%%' === $format && $width > 100 ) {
125
				$width = 100;
126
			}
127
128
			$width = sprintf( $format, $width );
129
		}
130
131
		return $width;
132
	}
133
134
	/**
135
	 * Fetch Field class
136
	 *
137
	 * @access public
138
	 * @static
139
	 * @param mixed $field
140
	 * @return string
141
	 */
142
	public static function field_class( $field, $form = NULL, $entry = NULL ) {
143
		$gravityview_view = GravityView_View::getInstance();
144
145
		$classes = array();
146
147
		if( !empty( $field['custom_class'] ) ) {
148
149
            $custom_class = $field['custom_class'];
150
151
            if( !empty( $entry ) ) {
152
153
                // We want the merge tag to be formatted as a class. The merge tag may be
154
                // replaced by a multiple-word value that should be output as a single class.
155
                // "Office Manager" will be formatted as `.OfficeManager`, not `.Office` and `.Manager`
156
                add_filter('gform_merge_tag_filter', 'sanitize_html_class');
157
158
                $custom_class = self::replace_variables( $custom_class, $form, $entry);
159
160
                // And then we want life to return to normal
161
                remove_filter('gform_merge_tag_filter', 'sanitize_html_class');
162
            }
163
164
			// And now we want the spaces to be handled nicely.
165
			$classes[] = gravityview_sanitize_html_class( $custom_class );
166
167
		}
168
169
		if(!empty($field['id'])) {
170
			if( !empty( $form ) && !empty( $form['id'] ) ) {
171
				$form_id = '-'.$form['id'];
172
			} else {
173
				$form_id = $gravityview_view->getFormId() ? '-'. $gravityview_view->getFormId() : '';
174
			}
175
176
			$classes[] = 'gv-field'.$form_id.'-'.$field['id'];
177
		}
178
179
		return esc_attr(implode(' ', $classes));
180
	}
181
182
	/**
183
	 * Fetch Field HTML ID
184
	 *
185
	 * @since 1.11
186
	 *
187
	 * @access public
188
	 * @static
189
	 * @param array $field GravityView field array passed to gravityview_field_output()
190
	 * @param array $form Gravity Forms form array, if set.
191
	 * @param array $entry Gravity Forms entry array
192
	 * @return string Sanitized unique HTML `id` attribute for the field
193
	 */
194
	public static function field_html_attr_id( $field, $form = array(), $entry = array() ) {
195
		$gravityview_view = GravityView_View::getInstance();
196
		$id = $field['id'];
197
198
		if ( ! empty( $id ) ) {
199
			if ( ! empty( $form ) && ! empty( $form['id'] ) ) {
200
				$form_id = '-' . $form['id'];
201
			} else {
202
				$form_id = $gravityview_view->getFormId() ? '-' . $gravityview_view->getFormId() : '';
203
			}
204
205
			$id = 'gv-field' . $form_id . '-' . $field['id'];
206
		}
207
208
		return esc_attr( $id );
209
	}
210
211
212
	/**
213
	 * Given an entry and a form field id, calculate the entry value for that field.
214
	 *
215
	 * @access public
216
	 * @param array $entry
217
	 * @param array $field
218
	 * @return null|string
219
	 */
220
	public static function field_value( $entry, $field_settings, $format = 'html' ) {
221
222
		if( empty( $entry['form_id'] ) || empty( $field_settings['id'] ) ) {
223
			return NULL;
224
		}
225
226
		$gravityview_view = GravityView_View::getInstance();
227
228
		$field_id = $field_settings['id'];
229
		$form = $gravityview_view->getForm();
230
		$field = gravityview_get_field( $form, $field_id );
231
232
		if( $field && is_numeric( $field_id ) ) {
233
			// Used as file name of field template in GV.
234
			// Don't use RGFormsModel::get_input_type( $field ); we don't care if it's a radio input; we want to know it's a 'quiz' field
235
			$field_type = $field->type;
236
			$value = RGFormsModel::get_lead_field_value( $entry, $field );
237
		} else {
238
			$field = GravityView_Fields::get_associated_field( $field_id );
239
			$field_type = $field_id; // Used as file name of field template in GV
240
		}
241
242
		// If a Gravity Forms Field is found, get the field display
243
		if( $field ) {
244
245
			// Prevent any PHP warnings that may be generated
246
			ob_start();
247
248
			$display_value = GFCommon::get_lead_field_display( $field, $value, $entry["currency"], false, $format );
249
250
			if ( $errors = ob_get_clean() ) {
251
				do_action( 'gravityview_log_error', 'GravityView_API[field_value] Errors when calling GFCommon::get_lead_field_display()', $errors );
252
			}
253
254
			$display_value = apply_filters( "gform_entry_field_value", $display_value, $field, $entry, $form );
255
256
			// prevent the use of merge_tags for non-admin fields
257
			if( !empty( $field->adminOnly ) ) {
258
				$display_value = self::replace_variables( $display_value, $form, $entry );
259
			}
260
		} else {
261
			$value = $display_value = rgar( $entry, $field_id );
262
			$display_value = $value;
263
		}
264
265
		// Check whether the field exists in /includes/fields/{$field_type}.php
266
		// This can be overridden by user template files.
267
		$field_path = $gravityview_view->locate_template("fields/{$field_type}.php");
268
269
		// Set the field data to be available in the templates
270
		$gravityview_view->setCurrentField( array(
271
			'form' => $form,
272
			'field_id' => $field_id,
273
			'field' => $field,
274
			'field_settings' => $field_settings,
275
			'value' => $value,
276
			'display_value' => $display_value,
277
			'format' => $format,
278
			'entry' => $entry,
279
			'field_type' => $field_type, /** {@since 1.6} */
280
		    'field_path' => $field_path, /** {@since 1.16} */
281
		));
282
283
		if( ! empty( $field_path ) ) {
284
285
			do_action( 'gravityview_log_debug', sprintf('[field_value] Rendering %s', $field_path ) );
286
287
			ob_start();
288
289
			load_template( $field_path, false );
290
291
			$output = ob_get_clean();
292
293
		} else {
294
295
			// Backup; the field template doesn't exist.
296
			$output = $display_value;
297
298
		}
299
300
		// Get the field settings again so that the field template can override the settings
301
		$field_settings = $gravityview_view->getCurrentField('field_settings');
302
303
		/**
304
		 * @filter `gravityview_field_entry_value_{$field_type}_pre_link` Modify the field value output for a field type before Show As Link setting is applied. Example: `gravityview_field_entry_value_number_pre_link`
305
		 * @since 1.16
306
		 * @param string $output HTML value output
307
		 * @param array  $entry The GF entry array
308
		 * @param array  $field_settings Settings for the particular GV field
309
		 * @param array  $field Field array, as fetched from GravityView_View::getCurrentField()
310
		 */
311
		$output = apply_filters( 'gravityview_field_entry_value_' . $field_type . '_pre_link', $output, $entry, $field_settings, $gravityview_view->getCurrentField() );
312
313
		/**
314
		 * Link to the single entry by wrapping the output in an anchor tag
315
		 *
316
		 * Fields can override this by modifying the field data variable inside the field. See /templates/fields/post_image.php for an example.
317
		 *
318
		 */
319
		if( !empty( $field_settings['show_as_link'] ) && ! gv_empty( $output, false, false ) ) {
320
321
			$link_atts = empty( $field_settings['new_window'] ) ? array() : array( 'target' => '_blank' );
322
323
			$output = self::entry_link_html( $entry, $output, $link_atts, $field_settings );
324
325
		}
326
327
		/**
328
		 * @filter `gravityview_field_entry_value_{$field_type}` Modify the field value output for a field type. Example: `gravityview_field_entry_value_number`
329
		 * @since 1.6
330
		 * @param string $output HTML value output
331
		 * @param array  $entry The GF entry array
332
		 * @param  array $field_settings Settings for the particular GV field
333
		 * @param array $field Current field being displayed
334
		 */
335
		$output = apply_filters( 'gravityview_field_entry_value_'.$field_type, $output, $entry, $field_settings, $gravityview_view->getCurrentField() );
336
337
		/**
338
		 * @filter `gravityview_field_entry_value` Modify the field value output for all field types
339
		 * @param string $output HTML value output
340
		 * @param array  $entry The GF entry array
341
		 * @param  array $field_settings Settings for the particular GV field
342
		 * @param array $field_data  {@since 1.6}
343
		 */
344
		$output = apply_filters( 'gravityview_field_entry_value', $output, $entry, $field_settings, $gravityview_view->getCurrentField() );
345
346
		return $output;
347
	}
348
349
	/**
350
	 * Generate an anchor tag that links to an entry.
351
	 *
352
	 * @since 1.6
353
	 * @see GVCommon::get_link_html()
354
	 *
355
	 * @param string $anchor_text The text or HTML inside the link
356
	 * @param array $entry Gravity Forms entry array
357
	 * @param array|string $passed_tag_atts Attributes to be added to the anchor tag, such as `title` or `rel`.
358
	 * @param array $field_settings Array of field settings. Optional, but passed to the `gravityview_field_entry_link` filter
359
	 *
360
	 * @return string|null Returns HTML for an anchor link. Null if $entry isn't defined or is missing an ID.
361
	 */
362
	public static function entry_link_html( $entry = array(), $anchor_text = '', $passed_tag_atts = array(), $field_settings = array() ) {
363
364
		if ( empty( $entry ) || ! is_array( $entry ) || ! isset( $entry['id'] ) ) {
365
			do_action( 'gravityview_log_debug', 'GravityView_API[entry_link_tag] Entry not defined; returning null', $entry );
366
			return NULL;
367
		}
368
369
		$href = self::entry_link( $entry );
370
371
		if( '' === $href ) {
372
			return NULL;
373
		}
374
375
		$link = gravityview_get_link( $href, $anchor_text, $passed_tag_atts );
376
377
		/**
378
		 * @filter `gravityview_field_entry_link` Modify the link HTML
379
		 * @param string $link HTML output of the link
380
		 * @param string $href URL of the link
381
		 * @param array  $entry The GF entry array
382
		 * @param  array $field_settings Settings for the particular GV field
383
		 */
384
		$output = apply_filters( 'gravityview_field_entry_link', $link, $href, $entry, $field_settings );
385
386
		return $output;
387
	}
388
389
	/**
390
	 * Get the "No Results" text depending on whether there were results.
391
	 * @param  boolean     $wpautop Apply wpautop() to the output?
392
	 * @return string               HTML of "no results" text
393
	 */
394
	public static function no_results($wpautop = true) {
395
		$gravityview_view = GravityView_View::getInstance();
396
397
		$is_search = false;
398
399
		if( $gravityview_view && ( $gravityview_view->curr_start || $gravityview_view->curr_end || $gravityview_view->curr_search ) ) {
400
			$is_search = true;
401
		}
402
403
		if($is_search) {
404
			$output = __('This search returned no results.', 'gravityview');
405
		} else {
406
			$output = __('No entries match your request.', 'gravityview');
407
		}
408
409
		/**
410
		 * @filter `gravitview_no_entries_text` Modify the text displayed when there are no entries.
411
		 * @param string $output The existing "No Entries" text
412
		 * @param boolean $is_search Is the current page a search result, or just a multiple entries screen?
413
		 */
414
		$output = apply_filters( 'gravitview_no_entries_text', $output, $is_search);
415
416
		return $wpautop ? wpautop($output) : $output;
417
	}
418
419
	/**
420
	 * Generate a URL to the Directory context
421
	 *
422
	 * Uses `wp_cache_get` and `wp_cache_get` (since 1.3) to speed up repeated requests to get permalink, which improves load time. Since we may be doing this hundreds of times per request, it adds up!
423
	 *
424
	 * @param int $post_id Post ID
425
	 * @param boolean $add_query_args Add pagination and sorting arguments
426
	 * @return string      Permalink to multiple entries view
427
	 */
428
	public static function directory_link( $post_id = NULL, $add_query_args = true ) {
429
		global $post;
430
431
		$gravityview_view = GravityView_View::getInstance();
432
433
		if( empty( $post_id ) ) {
434
435
			$post_id = false;
436
437
			// DataTables passes the Post ID
438
			if( defined('DOING_AJAX') && DOING_AJAX ) {
439
440
				$post_id = isset( $_POST['post_id'] ) ? (int)$_POST['post_id'] : false;
441
442
			} else {
443
444
				// The Post ID has been passed via the shortcode
445
				if( !empty( $gravityview_view ) && $gravityview_view->getPostId() ) {
446
447
					$post_id = $gravityview_view->getPostId();
448
449
				} else {
450
451
					// This is a GravityView post type
452
					if( GravityView_frontend::getInstance()->isGravityviewPostType() ) {
453
454
						$post_id = isset( $gravityview_view ) ? $gravityview_view->getViewId() : $post->ID;
455
456
					} else {
457
458
						// This is an embedded GravityView; use the embedded post's ID as the base.
459
						if( GravityView_frontend::getInstance()->isPostHasShortcode() && is_a( $post, 'WP_Post' ) ) {
460
461
							$post_id = $post->ID;
462
463
						} elseif( $gravityview_view->getViewId() ) {
464
465
							// The GravityView has been embedded in a widget or in a template, and
466
							// is not in the current content. Thus, we defer to the View's own ID.
467
							$post_id = $gravityview_view->getViewId();
468
469
						}
470
471
					}
472
473
				}
474
			}
475
		}
476
477
		// No post ID, get outta here.
478
		if( empty( $post_id ) ) {
479
			return NULL;
480
		}
481
482
		// If we've saved the permalink in memory, use it
483
		// @since 1.3
484
		$link = wp_cache_get( 'gv_directory_link_'.$post_id );
485
486
		if( empty( $link ) ) {
487
488
			$link = get_permalink( $post_id );
489
490
			// If not yet saved, cache the permalink.
491
			// @since 1.3
492
			wp_cache_set( 'gv_directory_link_'.$post_id, $link );
493
494
		}
495
496
		// Deal with returning to proper pagination for embedded views
497
		if( $link && $add_query_args ) {
498
499
			$args = array();
500
501
			if( $pagenum = rgget('pagenum') ) {
502
				$args['pagenum'] = intval( $pagenum );
503
			}
504
505
			if( $sort = rgget('sort') ) {
506
				$args['sort'] = $sort;
507
				$args['dir'] = rgget('dir');
508
			}
509
510
			$link = add_query_arg( $args, $link );
511
		}
512
513
		/**
514
		 * @filter `gravityview_directory_link` Modify the URL to the View "directory" context
515
		 * @since 1.19.4
516
		 * @param string $link URL to the View's "directory" context (Multiple Entries screen)
517
		 * @param int $post_id ID of the post to link to. If the View is embedded, it is the post or page ID
518
		 */
519
		$link = apply_filters( 'gravityview_directory_link', $link, $post_id );
520
521
		return $link;
522
	}
523
524
	/**
525
	 * Calculate an *unique* hash for an entry based on the entry ID
526
	 *
527
	 * This allows you to be more discrete as to the number of the entry - if you don't want users to know that you have made a certain number of sales, for example, or that their entry in the giveaway is entry #3.
528
	 *
529
	 * The hashed value MUST be unique, otherwise multiple entries will share the same URL, which leads to obvious problems.
530
	 *
531
	 * @param  int|string $id Entry ID to generate the hash for.
532
	 * @param  array  $entry        Entry data passed to provide additional information when generating the hash. Optional - don't rely on it being available.
533
	 * @return string               Hashed unique value for entry
534
	 */
535
	private static function get_custom_entry_slug( $id, $entry = array() ) {
536
537
		// Generate an unique hash to use as the default value
538
		$slug = substr( wp_hash( $id, 'gravityview'.$id ), 0, 8 );
539
540
		/**
541
		 * @filter `gravityview_entry_slug` Modify the unique hash ID generated, if you want to improve usability or change the format. This will allow for custom URLs, such as `{entryid}-{first-name}` or even, if unique, `{first-name}-{last-name}`
542
		 * @param string $hash Existing hash generated by GravityView
543
		 * @param  string $id The entry ID
544
		 * @param  array $entry Entry data array. May be empty.
545
		 */
546
		$slug = apply_filters( 'gravityview_entry_slug', $slug, $id, $entry );
547
548
		// Make sure we have something - use the original ID as backup.
549
		if( empty( $slug ) ) {
550
			$slug = $id;
551
		}
552
553
		return sanitize_title( $slug );
554
	}
555
556
	/**
557
	 * Get the entry slug for the entry. By default, it is the entry ID.
558
	 *
559
	 *
560
	 * @see gravityview_get_entry()
561
	 * @uses GravityView_API::get_custom_entry_slug() If using custom slug, gets the custom slug value
562
	 * @since 1.4
563
	 * @param  int|string $id_or_string ID of the entry, or custom slug string
564
	 * @param  array  $entry        Gravity Forms Entry array, optional. Used only to provide data to customize the `gravityview_entry_slug` filter
565
	 * @return string               Unique slug ID, passed through `sanitize_title()`
566
	 */
567
	public static function get_entry_slug( $id_or_string, $entry = array() ) {
568
569
		/**
570
		 * Default: use the entry ID as the unique identifier
571
		 */
572
		$slug = $id_or_string;
573
574
		/**
575
		 * @filter `gravityview_custom_entry_slug` Whether to enable and use custom entry slugs.
576
		 * @param boolean True: Allow for slugs based on entry values. False: always use entry IDs (default)
577
		 */
578
		$custom = apply_filters('gravityview_custom_entry_slug', false );
579
580
		// If we're using custom slug...
581
		if ( $custom ) {
582
583
			// Get the entry hash
584
			$hash = self::get_custom_entry_slug( $id_or_string, $entry );
585
586
			// See if the entry already has a hash set
587
			$value = gform_get_meta( $id_or_string, 'gravityview_unique_id' );
588
589
			// If it does have a hash set, and the hash is expected, use it.
590
			// This check allows users to change the hash structure using the
591
			// gravityview_entry_hash filter and have the old hashes expire.
592
			if( empty( $value ) || $value !== $hash ) {
593
				do_action( 'gravityview_log_debug', __METHOD__ . ' - Setting hash for entry "'.$id_or_string.'": ' . $hash );
594
				gform_update_meta( $id_or_string, 'gravityview_unique_id', $hash, rgar( $entry, 'form_id' ) );
595
			}
596
597
			$slug = $hash;
598
599
			unset( $value, $hash );
600
		}
601
602
		return sanitize_title( $slug );
603
	}
604
605
    /**
606
     * If using the entry custom slug feature, make sure the new entries have the custom slug created and saved as meta
607
     *
608
     * Triggered by add_action( 'gform_entry_created', array( 'GravityView_API', 'entry_create_custom_slug' ), 10, 2 );
609
     *
610
     * @param $entry array Gravity Forms entry object
611
     * @param $form array Gravity Forms form object
612
     */
613
    public static function entry_create_custom_slug( $entry, $form ) {
614
        /**
615
         * @filter `gravityview_custom_entry_slug` On entry creation, check if we are using the custom entry slug feature and update the meta
616
         * @param boolean $custom Should we process the custom entry slug?
617
         */
618
        $custom = apply_filters( 'gravityview_custom_entry_slug', false );
619
        if( $custom ) {
620
            // create the gravityview_unique_id and save it
621
622
            // Get the entry hash
623
            $hash = self::get_custom_entry_slug( $entry['id'], $entry );
624
625
	        do_action( 'gravityview_log_debug', __METHOD__ . ' - Setting hash for entry "'.$entry['id'].'": ' . $hash );
626
627
            gform_update_meta( $entry['id'], 'gravityview_unique_id', $hash, rgar( $entry, 'form_id' ) );
628
629
        }
630
    }
631
632
633
634
635
	/**
636
	 * return href for single entry
637
	 * @param  array|int $entry   Entry array or entry ID
638
	 * @param  int|null $post_id If wanting to define the parent post, pass a post ID
639
	 * @param boolean $add_directory_args True: Add args to help return to directory; False: only include args required to get to entry {@since 1.7.3}
640
	 * @return string          Link to the entry with the directory parent slug
641
	 */
642
	public static function entry_link( $entry, $post_id = NULL, $add_directory_args = true ) {
643
644
		if( ! empty( $entry ) && ! is_array( $entry ) ) {
645
			$entry = GVCommon::get_entry( $entry );
646
		} else if( empty( $entry ) ) {
647
			$entry = GravityView_frontend::getInstance()->getEntry();
648
		}
649
650
		// Second parameter used to be passed as $field; this makes sure it's not an array
651
		if( !is_numeric( $post_id ) ) {
652
			$post_id = NULL;
653
		}
654
655
		// Get the permalink to the View
656
		$directory_link = self::directory_link( $post_id, false );
657
658
		// No post ID? Get outta here.
659
		if( empty( $directory_link ) ) {
660
			return '';
661
		}
662
663
		if ( function_exists( 'gravityview' ) ) {
664
			$query_arg_name = \GV\Entry::get_endpoint_name();
665
		} else {
666
			/** Deprecated. Use \GV\Entry::get_endpoint_name instead. */
667
			$query_arg_name = GravityView_Post_Types::get_entry_var_name();
0 ignored issues
show
Deprecated Code introduced by
The method GravityView_Post_Types::get_entry_var_name() has been deprecated.

This method has been deprecated.

Loading history...
668
		}
669
670
		$entry_slug = self::get_entry_slug( $entry['id'], $entry );
671
672
		if( get_option('permalink_structure') && !is_preview() ) {
673
674
			$args = array();
675
676
			/**
677
			 * Make sure the $directory_link doesn't contain any query otherwise it will break when adding the entry slug.
678
			 * @since 1.16.5
679
			 */
680
			$link_parts = explode( '?', $directory_link );
681
682
			$query = !empty( $link_parts[1] ) ? '?'.$link_parts[1] : '';
683
684
			$directory_link = trailingslashit( $link_parts[0] ) . $query_arg_name . '/'. $entry_slug .'/' . $query;
685
686
		} else {
687
688
			$args = array( $query_arg_name => $entry_slug );
689
		}
690
691
		/**
692
		 * @since 1.7.3
693
		 */
694
		if( $add_directory_args ) {
695
696
			if( !empty( $_GET['pagenum'] ) ) {
697
				$args['pagenum'] = intval( $_GET['pagenum'] );
698
			}
699
700
			/**
701
			 * @since 1.7
702
			 */
703
			if( $sort = rgget('sort') ) {
704
				$args['sort'] = $sort;
705
				$args['dir'] = rgget('dir');
706
			}
707
708
		}
709
710
		/**
711
		 * Check if we have multiple views embedded in the same page and in that case make sure the single entry link
712
		 * has the view id so that Advanced Filters can be applied correctly when rendering the single view
713
		 * @see GravityView_frontend::get_context_view_id()
714
		 */
715
		if( class_exists( 'GravityView_View_Data' ) && GravityView_View_Data::getInstance()->has_multiple_views() ) {
716
			$args['gvid'] = gravityview_get_view_id();
717
		}
718
719
		return add_query_arg( $args, $directory_link );
720
721
	}
722
723
724
}
725
726
727
// inside loop functions
728
729
function gv_label( $field, $entry = NULL ) {
730
	return GravityView_API::field_label( $field, $entry );
731
}
732
733
function gv_class( $field, $form = NULL, $entry = array() ) {
734
	return GravityView_API::field_class( $field, $form, $entry  );
735
}
736
737
/**
738
 * Generate a CSS class to be added to the wrapper <div> of a View
739
 *
740
 * @since 1.5.4
741
 * @since 1.16 Added $echo param
742
 *
743
 * @param string $passed_css_class Default: `gv-container gv-container-{view id}`. If View is hidden until search, adds ` hidden`
744
 * @param boolean $echo Whether to echo the output. Default: true
745
 *
746
 * @return string CSS class, sanitized by gravityview_sanitize_html_class()
747
 */
748
function gv_container_class( $passed_css_class = '', $echo = true ) {
749
750
	$passed_css_class = trim( $passed_css_class );
751
752
	$view_id = GravityView_View::getInstance()->getViewId();
753
754
	$default_css_class = ! empty( $view_id ) ? sprintf( 'gv-container gv-container-%d', $view_id ) : 'gv-container';
755
756
	if( GravityView_View::getInstance()->isHideUntilSearched() ) {
757
		$default_css_class .= ' hidden';
758
	}
759
760
	if( 0 === GravityView_View::getInstance()->getTotalEntries() ) {
761
		$default_css_class .= ' gv-container-no-results';
762
	}
763
764
	$css_class = trim( $passed_css_class . ' '. $default_css_class );
765
766
	/**
767
	 * @filter `gravityview/render/container/class` Modify the CSS class to be added to the wrapper <div> of a View
768
	 * @since 1.5.4
769
	 * @param[in,out] string $css_class Default: `gv-container gv-container-{view id}`. If View is hidden until search, adds ` hidden`. If the View has no results, adds `gv-container-no-results`
770
	 */
771
	$css_class = apply_filters( 'gravityview/render/container/class', $css_class );
772
773
	$css_class = gravityview_sanitize_html_class( $css_class );
774
775
	if( $echo ) {
776
		echo $css_class;
777
	}
778
779
	return $css_class;
780
}
781
782
function gv_value( $entry, $field ) {
783
784
	$value = GravityView_API::field_value( $entry, $field );
785
786
	if( $value === '' ) {
787
		/**
788
		 * @filter `gravityview_empty_value` What to display when a field is empty
789
		 * @param string $value (empty string)
790
		 */
791
		$value = apply_filters( 'gravityview_empty_value', '' );
792
	}
793
794
	return $value;
795
}
796
797
function gv_directory_link( $post = NULL, $add_pagination = true ) {
798
	return GravityView_API::directory_link( $post, $add_pagination );
799
}
800
801
function gv_entry_link( $entry, $post_id = NULL ) {
802
	return GravityView_API::entry_link( $entry, $post_id );
803
}
804
805
function gv_no_results($wpautop = true) {
806
	return GravityView_API::no_results( $wpautop );
807
}
808
809
/**
810
 * Generate HTML for the back link from single entry view
811
 * @since 1.0.1
812
 * @return string|null      If no GV post exists, null. Otherwise, HTML string of back link.
813
 */
814
function gravityview_back_link() {
815
816
	$href = gv_directory_link();
817
818
	/**
819
	 * @filter `gravityview_go_back_url` Modify the back link URL
820
	 * @since 1.17.5
821
	 * @see gv_directory_link() Generated the original back link
822
	 * @param string $href Existing label URL
823
	 */
824
	$href = apply_filters( 'gravityview_go_back_url', $href );
825
826
	if( empty( $href ) ) { return NULL; }
827
828
	// calculate link label
829
	$gravityview_view = GravityView_View::getInstance();
830
831
	$label = $gravityview_view->getBackLinkLabel() ? $gravityview_view->getBackLinkLabel() : __( '&larr; Go back', 'gravityview' );
832
833
	/**
834
	 * @filter `gravityview_go_back_label` Modify the back link text
835
	 * @since 1.0.9
836
	 * @param string $label Existing label text
837
	 */
838
	$label = apply_filters( 'gravityview_go_back_label', $label );
839
840
	$link = gravityview_get_link( $href, esc_html( $label ), array(
841
		'data-viewid' => $gravityview_view->getViewId()
842
	));
843
844
	return $link;
845
}
846
847
/**
848
 * Handle getting values for complex Gravity Forms fields
849
 *
850
 * If the field is complex, like a product, the field ID, for example, 11, won't exist. Instead,
851
 * it will be 11.1, 11.2, and 11.3. This handles being passed 11 and 11.2 with the same function.
852
 *
853
 * @since 1.0.4
854
 * @param  array      $entry    GF entry array
855
 * @param  string      $field_id [description]
856
 * @param  string 	$display_value The value generated by Gravity Forms
857
 * @return string                Value
858
 */
859
function gravityview_get_field_value( $entry, $field_id, $display_value ) {
860
861
	if( floatval( $field_id ) === floor( floatval( $field_id ) ) ) {
862
863
		// For the complete field value as generated by Gravity Forms
864
		return $display_value;
865
866
	} else {
867
868
		// For one part of the address (City, ZIP, etc.)
869
		return isset( $entry[ $field_id ] ) ? $entry[ $field_id ] : '';
870
871
	}
872
873
}
874
875
/**
876
 * Take a passed CSV of terms and generate a linked list of terms
877
 *
878
 * Gravity Forms passes categories as "Name:ID" so we handle that using the ID, which
879
 * is more accurate than checking the name, which is more likely to change.
880
 *
881
 * @param  string      $value    Existing value
882
 * @param  string      $taxonomy Type of term (`post_tag` or `category`)
883
 * @return string                CSV of linked terms
884
 */
885
function gravityview_convert_value_to_term_list( $value, $taxonomy = 'post_tag' ) {
886
887
	$output = array();
888
889
	$terms = explode( ', ', $value );
890
891
	foreach ($terms as $term_name ) {
892
893
		// If we're processing a category,
894
		if( $taxonomy === 'category' ) {
895
896
			// Use rgexplode to prevent errors if : doesn't exist
897
			list( $term_name, $term_id ) = rgexplode( ':', $value, 2 );
898
899
			// The explode was succesful; we have the category ID
900
			if( !empty( $term_id )) {
901
				$term = get_term_by( 'id', $term_id, $taxonomy );
902
			} else {
903
			// We have to fall back to the name
904
				$term = get_term_by( 'name', $term_name, $taxonomy );
905
			}
906
907
		} else {
908
			// Use the name of the tag to get the full term information
909
			$term = get_term_by( 'name', $term_name, $taxonomy );
910
		}
911
912
		// There's still a tag/category here.
913
		if( $term ) {
914
915
			$term_link = get_term_link( $term, $taxonomy );
916
917
			// If there was an error, continue to the next term.
918
			if ( is_wp_error( $term_link ) ) {
919
			    continue;
920
			}
921
922
			$output[] = gravityview_get_link( $term_link, esc_html( $term->name ) );
923
		}
924
	}
925
926
	return implode(', ', $output );
927
}
928
929
/**
930
 * Get the links for post_tags and post_category output based on post ID
931
 * @param  int      $post_id  The ID of the post
932
 * @param  boolean     $link     Add links or no?
933
 * @param  string      $taxonomy Taxonomy of term to fetch.
934
 * @return string                String with terms
935
 */
936
function gravityview_get_the_term_list( $post_id, $link = true, $taxonomy = 'post_tag' ) {
937
938
	$output = get_the_term_list( $post_id, $taxonomy, NULL, ', ' );
939
940
	if( empty( $link ) ) {
941
		return strip_tags( $output);
942
	}
943
944
	return $output;
945
946
}
947
948
949
/**
950
 * Get all views processed so far for the current page load
951
 *
952
 * @see  GravityView_View_Data::add_view()
953
 * @return array Array of View data, each View data with `id`, `view_id`, `form_id`, `template_id`, `atts`, `fields`, `widgets`, `form` keys.
954
 */
955
function gravityview_get_current_views() {
956
957
	$fe = GravityView_frontend::getInstance();
958
959
	// Solve problem when loading content via admin-ajax.php
960
	if( ! $fe->getGvOutputData() ) {
961
962
		do_action( 'gravityview_log_debug', '[gravityview_get_current_views] gv_output_data not defined; parsing content.' );
963
964
		$fe->parse_content();
965
	}
966
967
	// Make 100% sure that we're dealing with a properly called situation
968
	if( !is_a( $fe->getGvOutputData(), 'GravityView_View_Data' ) ) {
969
970
		do_action( 'gravityview_log_debug', '[gravityview_get_current_views] gv_output_data not an object or get_view not callable.', $fe->getGvOutputData() );
971
972
		return array();
973
	}
974
975
	return $fe->getGvOutputData()->get_views();
976
}
977
978
/**
979
 * Get data for a specific view
980
 *
981
 * @see  GravityView_View_Data::get_view()
982
 * @return array View data with `id`, `view_id`, `form_id`, `template_id`, `atts`, `fields`, `widgets`, `form` keys.
983
 */
984
function gravityview_get_current_view_data( $view_id = 0 ) {
985
986
	$fe = GravityView_frontend::getInstance();
987
988
	if( ! $fe->getGvOutputData() ) { return array(); }
989
990
	// If not set, grab the current view ID
991
	if( empty( $view_id ) ) {
992
		$view_id = $fe->get_context_view_id();
993
	}
994
995
	return $fe->getGvOutputData()->get_view( $view_id );
996
}
997
998
// Templates' hooks
999
function gravityview_before() {
1000
	/**
1001
	 * @action `gravityview_before` Display content before a View. Used to render widget areas. Rendered outside the View container `<div>`
1002
	 * @param int $view_id The ID of the View being displayed
1003
	 */
1004
	do_action( 'gravityview_before', gravityview_get_view_id() );
1005
}
1006
1007
function gravityview_header() {
1008
	/**
1009
	 * @action `gravityview_header` Prepend content to the View container `<div>`
1010
	 * @param int $view_id The ID of the View being displayed
1011
	 */
1012
	do_action( 'gravityview_header', gravityview_get_view_id() );
1013
}
1014
1015
function gravityview_footer() {
1016
	/**
1017
	 * @action `gravityview_after` Display content after a View. Used to render footer widget areas. Rendered outside the View container `<div>`
1018
	 * @param int $view_id The ID of the View being displayed
1019
	 */
1020
	do_action( 'gravityview_footer', gravityview_get_view_id() );
1021
}
1022
1023
function gravityview_after() {
1024
	/**
1025
	 * @action `gravityview_after` Append content to the View container `<div>`
1026
	 * @param int $view_id The ID of the View being displayed
1027
	 */
1028
	do_action( 'gravityview_after', gravityview_get_view_id() );
1029
}
1030
1031
/**
1032
 * Get the current View ID being rendered
1033
 *
1034
 * @global GravityView_View $gravityview_view
1035
 * @return string View context "directory" or "single"
1036
 */
1037
function gravityview_get_view_id() {
1038
	return GravityView_View::getInstance()->getViewId();
1039
}
1040
1041
/**
1042
 * @global GravityView_View $gravityview_view
1043
 * @return string View context "directory", "single", or "edit"
1044
 */
1045
function gravityview_get_context() {
1046
1047
	$context = '';
1048
1049
	/**
1050
	 * @filter `gravityview_is_edit_entry` Whether we're currently on the Edit Entry screen \n
1051
	 * The Edit Entry functionality overrides this value.
1052
	 * @param boolean $is_edit_entry
1053
	 */
1054
	$is_edit_entry = apply_filters( 'gravityview_is_edit_entry', false );
1055
1056
	if( $is_edit_entry ) {
1057
		$context = 'edit';
1058
	} else if( class_exists( 'GravityView_frontend' ) && $single = GravityView_frontend::is_single_entry() ) {
1059
		$context = 'single';
1060
	} else if( class_exists( 'GravityView_View' ) ) {
1061
		$context = GravityView_View::getInstance()->getContext();
1062
	}
1063
1064
	return $context;
1065
}
1066
1067
1068
/**
1069
 * Return an array of files prepared for output. Wrapper for GravityView_Field_FileUpload::get_files_array()
1070
 *
1071
 * Processes files by file type and generates unique output for each.
1072
 *
1073
 * Returns array for each file, with the following keys:
1074
 *
1075
 * `file_path` => The file path of the file, with a line break
1076
 * `html` => The file output HTML formatted
1077
 *
1078
 * @see GravityView_Field_FileUpload::get_files_array()
1079
 *
1080
 * @since  1.2
1081
 * @param  string $value    Field value passed by Gravity Forms. String of file URL, or serialized string of file URL array
1082
 * @param  string $gv_class Field class to add to the output HTML
1083
 * @return array           Array of file output, with `file_path` and `html` keys (see comments above)
1084
 */
1085
function gravityview_get_files_array( $value, $gv_class = '' ) {
1086
	/** @define "GRAVITYVIEW_DIR" "../" */
1087
1088
	if( !class_exists( 'GravityView_Field' ) ) {
1089
		include_once( GRAVITYVIEW_DIR .'includes/fields/class-gravityview-field.php' );
1090
	}
1091
1092
	if( !class_exists( 'GravityView_Field_FileUpload' ) ) {
1093
		include_once( GRAVITYVIEW_DIR .'includes/fields/fileupload.php' );
1094
	}
1095
1096
	return GravityView_Field_FileUpload::get_files_array( $value, $gv_class );
1097
}
1098
1099
/**
1100
 * Generate a mapping link from an address
1101
 *
1102
 * The address should be plain text with new line (`\n`) or `<br />` line breaks separating sections
1103
 *
1104
 * @todo use GF's field get_export_value() instead
1105
 *
1106
 * @see https://gravityview.co/support/documentation/201608159 Read how to modify the link
1107
 * @param  string $address Address
1108
 * @return string          URL of link to map of address
1109
 */
1110
function gravityview_get_map_link( $address ) {
1111
1112
	$address_qs = str_replace( array( '<br />', "\n" ), ' ', $address ); // Replace \n with spaces
1113
	$address_qs = urlencode( $address_qs );
1114
1115
	$url = "https://maps.google.com/maps?q={$address_qs}";
1116
1117
	$link_text = esc_html__( 'Map It', 'gravityview' );
1118
1119
	$link = gravityview_get_link( $url, $link_text, 'class=map-it-link' );
1120
1121
	/**
1122
	 * @filter `gravityview_map_link` Modify the map link generated. You can use a different mapping service, for example.
1123
	 * @param[in,out]  string $link Map link
1124
	 * @param[in] string $address Address to generate link for
1125
	 * @param[in] string $url URL generated by the function
1126
	 */
1127
	$link = apply_filters( 'gravityview_map_link', $link, $address, $url );
1128
1129
	return $link;
1130
}
1131
1132
1133
/**
1134
 * Output field based on a certain html markup
1135
 *
1136
 *   markup - string to be used on a sprintf statement.
1137
 *      Use:
1138
 *         {{label}} - field label
1139
 *         {{value}} - entry field value
1140
 *         {{class}} - field class
1141
 *
1142
 *   wpautop - true will filter the value using wpautop function
1143
 *
1144
 * @since  1.1.5
1145
 * @param  array $passed_args Associative array with field data. `field` and `form` are required.
1146
 * @return string Field output. If empty value and hide empty is true, return empty.
1147
 */
1148
function gravityview_field_output( $passed_args ) {
1149
	$defaults = array(
1150
		'entry' => null,
1151
		'field' => null,
1152
		'form' => null,
1153
		'hide_empty' => true,
1154
		'markup' => '<div id="{{ field_id }}" class="{{ class }}">{{label}}{{value}}</div>',
1155
		'label_markup' => '',
1156
		'wpautop' => false,
1157
		'zone_id' => null,
1158
	);
1159
1160
	$args = wp_parse_args( $passed_args, $defaults );
1161
1162
	/**
1163
	 * @filter `gravityview/field_output/args` Modify the args before generation begins
1164
	 * @since 1.7
1165
	 * @param array $args Associative array; `field` and `form` is required.
1166
	 * @param array $passed_args Original associative array with field data. `field` and `form` are required.
1167
	 */
1168
	$args = apply_filters( 'gravityview/field_output/args', $args, $passed_args );
1169
1170
	// Required fields.
1171
	if ( empty( $args['field'] ) || empty( $args['form'] ) ) {
1172
		do_action( 'gravityview_log_error', '[gravityview_field_output] Field or form are empty.', $args );
1173
		return '';
1174
	}
1175
1176
	$entry = empty( $args['entry'] ) ? array() : $args['entry'];
1177
1178
	/**
1179
	 * Create the content variables for replacing.
1180
	 * @since 1.11
1181
	 */
1182
	$context = array(
1183
		'value' => '',
1184
		'width' => '',
1185
		'width:style' => '',
1186
		'label' => '',
1187
		'label_value' => '',
1188
		'class' => '',
1189
		'field_id' => '',
1190
	);
1191
1192
	$context['value'] = gv_value( $entry, $args['field'] );
1193
1194
	// If the value is empty and we're hiding empty, return empty.
1195
	if ( $context['value'] === '' && ! empty( $args['hide_empty'] ) ) {
1196
		return '';
1197
	}
1198
1199
	if ( $context['value'] !== '' && ! empty( $args['wpautop'] ) ) {
1200
		$context['value'] = wpautop( $context['value'] );
1201
	}
1202
1203
	// Get width setting, if exists
1204
	$context['width'] = GravityView_API::field_width( $args['field'] );
1205
1206
	// If replacing with CSS inline formatting, let's do it.
1207
	$context['width:style'] = GravityView_API::field_width( $args['field'], 'width:' . $context['width'] . '%;' );
1208
1209
	// Grab the Class using `gv_class`
1210
	$context['class'] = gv_class( $args['field'], $args['form'], $entry );
1211
	$context['field_id'] = GravityView_API::field_html_attr_id( $args['field'], $args['form'], $entry );
1212
1213
	// Get field label if needed
1214
	if ( ! empty( $args['label_markup'] ) && ! empty( $args['field']['show_label'] ) ) {
1215
		$context['label'] = str_replace( array( '{{label}}', '{{ label }}' ), '<span class="gv-field-label">{{ label_value }}</span>', $args['label_markup'] );
1216
	}
1217
1218
	// Default Label value
1219
	$context['label_value'] = gv_label( $args['field'], $entry );
1220
1221
	if ( empty( $context['label'] ) && ! empty( $context['label_value'] ) ){
1222
		$context['label'] = '<span class="gv-field-label">{{ label_value }}</span>';
1223
	}
1224
1225
	/**
1226
	 * @filter `gravityview/field_output/pre_html` Allow Pre filtering of the HTML
1227
	 * @since 1.11
1228
	 * @param string $markup The HTML for the markup
1229
	 * @param array $args All args for the field output
1230
	 */
1231
	$html = apply_filters( 'gravityview/field_output/pre_html', $args['markup'], $args );
1232
1233
	/**
1234
	 * @filter `gravityview/field_output/open_tag` Modify the opening tags for the template content placeholders
1235
	 * @since 1.11
1236
	 * @param string $open_tag Open tag for template content placeholders. Default: `{{`
1237
	 */
1238
	$open_tag = apply_filters( 'gravityview/field_output/open_tag', '{{', $args );
1239
1240
	/**
1241
	 * @filter `gravityview/field_output/close_tag` Modify the closing tags for the template content placeholders
1242
	 * @since 1.11
1243
	 * @param string $close_tag Close tag for template content placeholders. Default: `}}`
1244
	 */
1245
	$close_tag = apply_filters( 'gravityview/field_output/close_tag', '}}', $args );
1246
1247
	/**
1248
	 * Loop through each of the tags to replace and replace both `{{tag}}` and `{{ tag }}` with the values
1249
	 * @since 1.11
1250
	 */
1251
	foreach ( $context as $tag => $value ) {
1252
1253
		// If the tag doesn't exist just skip it
1254
		if ( false === strpos( $html, $open_tag . $tag . $close_tag ) && false === strpos( $html, $open_tag . ' ' . $tag . ' ' . $close_tag ) ){
1255
			continue;
1256
		}
1257
1258
		// Array to search
1259
		$search = array(
1260
			$open_tag . $tag . $close_tag,
1261
			$open_tag . ' ' . $tag . ' ' . $close_tag,
1262
		);
1263
1264
		/**
1265
		 * `gravityview/field_output/context/{$tag}` Allow users to filter content on context
1266
		 * @since 1.11
1267
		 * @param string $value The content to be shown instead of the {{tag}} placeholder
1268
		 * @param array $args Arguments passed to the function
1269
		 */
1270
		$value = apply_filters( 'gravityview/field_output/context/' . $tag, $value, $args );
1271
1272
		// Finally do the replace
1273
		$html = str_replace( $search, $value, $html );
1274
	}
1275
1276
	/**
1277
	 * @todo  Depricate `gravityview_field_output`
1278
	 */
1279
	$html = apply_filters( 'gravityview_field_output', $html, $args );
1280
1281
	/**
1282
	 * @filter `gravityview/field_output/html` Modify field HTML output
1283
	 * @param string $html Existing HTML output
1284
	 * @param array $args Arguments passed to the function
1285
	 */
1286
	$html = apply_filters( 'gravityview/field_output/html', $html, $args );
1287
1288
	// Just free up a tiny amount of memory
1289
	unset( $value, $args, $passed_args, $entry, $context, $search, $open_tag, $tag, $close_tag );
1290
1291
	return $html;
1292
}
1293