Completed
Pull Request — develop (#1561)
by Zack
39:35 queued 19:32
created

class-api.php ➔ gv_get_query_args()   A

Complexity

Conditions 4
Paths 6

Size

Total Lines 34

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 21
CRAP Score 4

Importance

Changes 0
Metric Value
cc 4
nc 6
nop 0
dl 0
loc 34
ccs 21
cts 21
cp 1
crap 4
rs 9.376
c 0
b 0
f 0
1
<?php
2
/**
3
 * GravityView template tags API
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.0.0
12
 */
13
14
class GravityView_API {
15
16
	/**
17
	 * Fetch Field Label
18
	 *
19
	 * @deprecated Use \GV\Field::get_label()
20
	 *
21
	 * @static
22
	 * @param array $field GravityView field array
23
	 * @param array $entry Gravity Forms entry array
24
	 * @param boolean $force_show_label Whether to always show the label, regardless of field settings
25
	 * @return string
26
	 */
27 3
	public static function field_label( $field, $entry = array(), $force_show_label = false ) {
28
29 3
		$gravityview_view = GravityView_View::getInstance();
30
31 3
		$form = $gravityview_view->getForm();
32
33 3
		if ( defined( 'DOING_GRAVITYVIEW_TESTS' ) && ! empty( $GLOBALS['GravityView_API_field_label_override'] ) ) {
34
			/** Allow to fall through for back compatibility testing purposes. */
35
		} else {
36 3
			return \GV\Mocks\GravityView_API_field_label( $form, $field, $entry, $force_show_label );
37
		}
38
39 1
		$label = '';
40
41 1
		if( !empty( $field['show_label'] ) || $force_show_label ) {
42
43 1
			$label = $field['label'];
44
45
			// Support Gravity Forms 1.9+
46 1
			if( class_exists( 'GF_Field' ) ) {
47
48 1
				$field_object = RGFormsModel::get_field( $form, $field['id'] );
49
50 1
				if( $field_object ) {
51
52 1
					$input = GFFormsModel::get_input( $field_object, $field['id'] );
53
54
					// This is a complex field, with labels on a per-input basis
55 1
					if( $input ) {
56
57
						// Does the input have a custom label on a per-input basis? Otherwise, default label.
58 1
						$label = ! empty( $input['customLabel'] ) ? $input['customLabel'] : $input['label'];
59
60
					} else {
61
62
						// This is a field with one label
63 1
						$label = $field_object->get_field_label( true, $field['label'] );
64
65
					}
66
67
				}
68
69
			}
70
71
			// Use Gravity Forms label by default, but if a custom label is defined in GV, use it.
72 1
			if ( !empty( $field['custom_label'] ) ) {
73
74 1
				$label = self::replace_variables( $field['custom_label'], $form, $entry );
75
76
			}
77
78
			/**
79
			 * @filter `gravityview_render_after_label` Append content to a field label
80
			 * @param[in,out] string $appended_content Content you can add after a label. Empty by default.
81
			 * @param[in] array $field GravityView field array
82
			 */
83 1
			$label .= apply_filters( 'gravityview_render_after_label', '', $field );
84
85
		} // End $field['show_label']
86
87
		/**
88
		 * @filter `gravityview/template/field_label` Modify field label output
89
		 * @since 1.7
90
		 * @param[in,out] string $label Field label HTML
91
		 * @param[in] array $field GravityView field array
92
		 * @param[in] array $form Gravity Forms form array
93
		 * @param[in] array $entry Gravity Forms entry array
94
		 *
95
		 * @deprecated Use the context-aware version `gravityview/template/field/label`
96
		 */
97 1
		$label = apply_filters( 'gravityview/template/field_label', $label, $field, $form, $entry );
98
99 1
		return $label;
100
	}
101
102
	/**
103
	 * Alias for GravityView_Merge_Tags::replace_variables()
104
	 *
105
	 * @see GravityView_Merge_Tags::replace_variables() Moved in 1.8.4
106
	 * @since 1.22.4 - Added $nl2br, $format, $aux_data args
107
	 *
108
	 * @param  string     $text         Text to replace variables in
109
	 * @param  array      $form         GF Form array
110
	 * @param  array      $entry        GF Entry array
111
	 * @param  bool       $url_encode   Pass return value through `url_encode()`
112
	 * @param  bool       $esc_html     Pass return value through `esc_html()`
113
	 * @param  bool       $nl2br        Convert newlines to <br> HTML tags
114
	 * @param  string     $format       The format requested for the location the merge is being used. Possible values: html, text or url.
115
	 * @param  array      $aux_data     Additional data to be used to replace merge tags {@see https://www.gravityhelp.com/documentation/article/gform_merge_tag_data/}
116
	 * @return string                   Text with variables maybe replaced
117
	 */
118 50
	public static function replace_variables( $text, $form = array(), $entry = array(), $url_encode = false, $esc_html = true, $nl2br = true, $format = 'html', $aux_data = array() ) {
119 50
		return GravityView_Merge_Tags::replace_variables( $text, $form, $entry, $url_encode, $esc_html, $nl2br, $format, $aux_data );
120
	}
121
122
	/**
123
	 * Get column width from the field setting
124
	 *
125
	 * @since 1.9
126
	 *
127
	 * @param array $field Array of settings for the field
128
	 * @param string $format Format for width. "%" (default) will return
129
	 *
130
	 * @return string|null If not empty, string in $format format. Otherwise, null.
131
	 */
132 35
	public static function field_width( $field, $format = '%d%%' ) {
133
134 35
		$width = NULL;
135
136 35
		if( !empty( $field['width'] ) ) {
137 1
			$width = absint( $field['width'] );
138
139
			// If using percentages, limit to 100%
140 1
			if( '%d%%' === $format && $width > 100 ) {
141 1
				$width = 100;
142
			}
143
144 1
			$width = sprintf( $format, $width );
145
		}
146
147 35
		return $width;
148
	}
149
150
	/**
151
	 * Fetch Field class
152
	 *
153
	 * @static
154
	 * @param mixed $field
155
	 * @return string
156
	 */
157 38
	public static function field_class( $field, $form = NULL, $entry = NULL ) {
158 38
		$classes = array();
159
160 38
		if( !empty( $field['custom_class'] ) ) {
161
162 2
            $custom_class = $field['custom_class'];
163
164 2
            if( !empty( $entry ) ) {
165
166
                // We want the merge tag to be formatted as a class. The merge tag may be
167
                // replaced by a multiple-word value that should be output as a single class.
168
                // "Office Manager" will be formatted as `.OfficeManager`, not `.Office` and `.Manager`
169 2
                add_filter('gform_merge_tag_filter', 'sanitize_html_class');
170
171 2
                $custom_class = self::replace_variables( $custom_class, $form, $entry);
172
173
                // And then we want life to return to normal
174 2
                remove_filter('gform_merge_tag_filter', 'sanitize_html_class');
175
            }
176
177
			// And now we want the spaces to be handled nicely.
178 2
			$classes[] = gravityview_sanitize_html_class( $custom_class );
179
180
		}
181
182 38
		if(!empty($field['id'])) {
183 38
			if( !empty( $form ) && !empty( $form['id'] ) ) {
184 38
				$form_id = '-'.$form['id'];
185
			} else {
186
				// @deprecated path. Form should always be given.
187
				gravityview()->log->warning( 'GravityView_View::getInstance() legacy API called' );
188
				$gravityview_view = GravityView_View::getInstance();
189
				$form_id = $gravityview_view->getFormId() ? '-'. $gravityview_view->getFormId() : '';
190
			}
191
192 38
			$classes[] = 'gv-field'.$form_id.'-'.$field['id'];
193
		}
194
195 38
		return esc_attr(implode(' ', $classes));
196
	}
197
198
	/**
199
	 * Fetch Field HTML ID
200
	 *
201
	 * @since 1.11
202
	 *
203
	 * @static
204
	 * @param array $field GravityView field array passed to gravityview_field_output()
205
	 * @param array $form Gravity Forms form array, if set.
206
	 * @param array $entry Gravity Forms entry array
207
	 * @return string Sanitized unique HTML `id` attribute for the field
208
	 */
209 34
	public static function field_html_attr_id( $field, $form = array(), $entry = array() ) {
0 ignored issues
show
Unused Code introduced by
The parameter $entry 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...
210 34
		$id = $field['id'];
211
212 34
		if ( ! empty( $id ) ) {
213 34
			if ( ! empty( $form ) && ! empty( $form['id'] ) ) {
214 34
				$form_id = '-' . $form['id'];
215
			} else {
216
				// @deprecated path. Form should always be given.
217
				gravityview()->log->warning( 'GravityView_View::getInstance() legacy API called' );
218
				$gravityview_view = GravityView_View::getInstance();
219
				$form_id = $gravityview_view->getFormId() ? '-' . $gravityview_view->getFormId() : '';
220
			}
221
222 34
			$id = 'gv-field' . $form_id . '-' . $field['id'];
223
		}
224
225 34
		return esc_attr( $id );
226
	}
227
228
229
	/**
230
	 * Given an entry and a form field id, calculate the entry value for that field.
231
	 *
232
	 * @deprecated Use \GV\Field_Template::render() or the more low-level \GV\Field::get_value()
233
	 *
234
	 * @param array $entry
235
	 * @param array $field
0 ignored issues
show
Bug introduced by
There is no parameter named $field. 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...
236
	 * @return null|string
237
	 */
238 3
	public static function field_value( $entry, $field_settings, $format = 'html' ) {
239 3
		gravityview()->log->notice( '\GravityView_API::field_value is deprecated. Use \GV\Field_Template::render() or \GV\Field::get_value()' );
240 3
		return \GV\Mocks\GravityView_API_field_value( $entry, $field_settings, $format );
0 ignored issues
show
Deprecated Code introduced by
The function GV\Mocks\GravityView_API_field_value() has been deprecated with message: Use \GV\Field_Template::render()

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...
241
	}
242
243
	/**
244
	 * Generate an anchor tag that links to an entry.
245
	 *
246
	 * @since 1.6
247
	 * @see GVCommon::get_link_html()
248
	 *
249
	 * @param string $anchor_text The text or HTML inside the link
250
	 * @param array $entry Gravity Forms entry array
251
	 * @param array|string $passed_tag_atts Attributes to be added to the anchor tag, such as `title` or `rel`.
252
	 * @param array $field_settings Array of field settings. Optional, but passed to the `gravityview_field_entry_link` filter
253
	 *
254
	 * @since 2.0
255
	 * @param int $base_id The post or the view that this entry is linked from.
256
	 *
257
	 * @return string|null Returns HTML for an anchor link. Null if $entry isn't defined or is missing an ID.
258
	 */
259 2
	public static function entry_link_html( $entry = array(), $anchor_text = '', $passed_tag_atts = array(), $field_settings = array(), $base_id = null ) {
260
261 2
		if ( empty( $entry ) || ! is_array( $entry ) || ! isset( $entry['id'] ) ) {
262 1
			gravityview()->log->debug( 'Entry not defined; returning null', array( 'data' => $entry ) );
263 1
			return NULL;
264
		}
265
266 2
		$href = self::entry_link( $entry, $base_id );
267
268 2
		if( '' === $href ) {
269
			return NULL;
270
		}
271
272 2
		$link = gravityview_get_link( $href, $anchor_text, $passed_tag_atts );
273
274
		/**
275
		 * @filter `gravityview_field_entry_link` Modify the link HTML
276
		 * @param string $link HTML output of the link
277
		 * @param string $href URL of the link
278
		 * @param array  $entry The GF entry array
279
		 * @param  array $field_settings Settings for the particular GV field
280
		 */
281 2
		$output = apply_filters( 'gravityview_field_entry_link', $link, $href, $entry, $field_settings );
282
283 2
		return $output;
284
	}
285
286
	/**
287
	 * Get the "No Results" text depending on whether there were results.
288
	 * @param  boolean     $wpautop Apply wpautop() to the output?
289
	 *
290
	 * @since 2.0
291
	 * @param \GV\Template_Context $context The context
292
	 *
293
	 * @return string               HTML of "no results" text
294
	 */
295 10
	public static function no_results( $wpautop = true, $context = null ) {
296 10
		$is_search = false;
297
298 10
		if ( $context instanceof \GV\Template_Context ) {
299 9
			if ( $context->request->is_search() ) {
300 9
				$is_search = true;
301
			}
302
		} else {
303 2
			$gravityview_view = GravityView_View::getInstance();
304
305 2
			if( $gravityview_view && ( $gravityview_view->curr_start || $gravityview_view->curr_end || $gravityview_view->curr_search ) ) {
0 ignored issues
show
Documentation introduced by
The property curr_start does not exist on object<GravityView_View>. 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...
Documentation introduced by
The property curr_end does not exist on object<GravityView_View>. 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...
Documentation introduced by
The property curr_search does not exist on object<GravityView_View>. 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...
306 1
				$is_search = true;
307
			}
308
		}
309
310 10
		$setting = '';
311
312 10
		if ( $is_search ) {
313
314 1
			$output = esc_html__( 'This search returned no results.', 'gravityview' );
315
316 1
			if( $context ) {
317 1
				$setting = $context->view->settings->get( 'no_search_results_text', $output );
318
			}
319
320
		} else {
321
322 10
			$output = esc_html__( 'No entries match your request.', 'gravityview' );
323
324 10
			if( $context ) {
325 9
				$setting = $context->view->settings->get( 'no_results_text', $output );
326
			}
327
		}
328
329 10
		if ( '' !== $setting ) {
330 1
			$output = $setting;
331
		}
332
333
		/**
334
		 * Added now that users are able to modify via View settings
335
		 * @since 2.8.2
336
		 */
337 10
		$output = wp_kses(
338 10
			$output,
339
			array(
340 10
				'p'      => array( 'class' => array(), 'id' => array() ),
341
				'h1'     => array( 'class' => array(), 'id' => array() ),
342
				'h2'     => array( 'class' => array(), 'id' => array() ),
343
				'h3'     => array( 'class' => array(), 'id' => array() ),
344
				'h4'     => array( 'class' => array(), 'id' => array() ),
345
				'h5'     => array( 'class' => array(), 'id' => array() ),
346
				'strong' => array( 'class' => array(), 'id' => array() ),
347
				'span'   => array( 'class' => array(), 'id' => array() ),
348
				'b'      => array( 'class' => array(), 'id' => array() ),
349
				'em'     => array( 'class' => array(), 'id' => array() ),
350
				'a'      => array( 'class' => array(), 'id' => array(), 'href' => array(), 'title' => array(), 'rel' => array(), 'target' => array() ),
351
				'div'    => array( 'class' => array(), 'id' => array() ),
352
				'br'     => array(),
353
			)
354
		);
355
356
		/**
357
		 * @filter `gravitview_no_entries_text` Modify the text displayed when there are no entries.
358
		 * Note: this filter is, and always has been, misspelled. This will not be fixed, since the filter is deprecated.
359
		 * @param string $output The existing "No Entries" text
360
		 * @param boolean $is_search Is the current page a search result, or just a multiple entries screen?
361
		 * @return string The modified text.
362
		 * @deprecated Use `gravityview/template/text/no_entries`
363
		 */
364 10
		$output = apply_filters( 'gravitview_no_entries_text', $output, $is_search );
365
366
		/**
367
		 * @filter `gravityview/template/text/no_entries` Modify the text displayed when there are no entries.
368
		 * @since 2.0
369
		 * @param string $output The existing "No Entries" text
370
		 * @param boolean $is_search Is the current page a search result, or just a multiple entries screen?
371
		 * @param \GV\Template_Context $context The context.
372
		 * @return string The modified text.
373
		 */
374 10
		$output = apply_filters( 'gravityview/template/text/no_entries', $output, $is_search, $context );
375
376 10
		return $wpautop ? wpautop( $output ) : $output;
377
	}
378
379
	/**
380
	 * Generate a URL to the Directory context
381
	 *
382
	 * 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!
383
	 *
384
	 * @param int $post_id Post ID
385
	 * @param boolean $add_query_args Add pagination and sorting arguments
386
	 *
387
	 * @since 2.0
388
	 * @param \GV\Template_Context $context The context this is being used in.
389
	 *
390
	 * @return string      Permalink to multiple entries view
391
	 */
392 46
	public static function directory_link( $post_id = NULL, $add_query_args = true, $context = null ) {
393 46
		global $post;
394
395 46
		if ( empty( $post_id ) ) {
396
			// DataTables passes the Post ID
397 21
			if ( defined( 'DOING_AJAX' ) && DOING_AJAX ) {
398
				$post_id = \GV\Utils::_POST( 'post_id', false );
399
			} else {
400 21
				if ( $context instanceof \GV\Template_Context ) {
401
					// Shortcodes, embeds
402 17
					if ( is_a( $post, 'WP_Post' ) ) {
403 5
						$post_id = $post->ID;
404
405
					// Actual views
406
					} else {
407 17
						$post_id = $context->view ? $context->view->ID : false;
408
					}
409
				} else {
410
					/** @deprecated path of execution */
411 4
					$gravityview_view = GravityView_View::getInstance();
412
413
					// The Post ID has been passed via the shortcode
414 4
					if ( ! empty( $gravityview_view ) && $gravityview_view->getPostId() ) {
0 ignored issues
show
Bug Best Practice introduced by
The expression $gravityview_view->getPostId() of type integer|null is loosely compared to true; this is ambiguous if the integer can be zero. You might want to explicitly use !== null instead.

In PHP, under loose comparison (like ==, or !=, or switch conditions), values of different types might be equal.

For integer values, zero is a special case, in particular the following results might be unexpected:

0   == false // true
0   == null  // true
123 == false // false
123 == null  // false

// It is often better to use strict comparison
0 === false // false
0 === null  // false
Loading history...
415 2
						$post_id = $gravityview_view->getPostId();
416
					} else {
417
						// This is a GravityView post type
418 2
						if ( GravityView_frontend::getInstance()->isGravityviewPostType() ) {
419
							$post_id = isset( $gravityview_view ) ? $gravityview_view->getViewId() : $post->ID;
420
						} else {
421
							// This is an embedded GravityView; use the embedded post's ID as the base.
422 2
							if ( GravityView_frontend::getInstance()->isPostHasShortcode() && is_a( $post, 'WP_Post' ) ) {
423
								$post_id = $post->ID;
424 2
							} elseif ( $gravityview_view->getViewId() ) {
425
								// The GravityView has been embedded in a widget or in a template, and
426
								// is not in the current content. Thus, we defer to the View's own ID.
427 1
								$post_id = $gravityview_view->getViewId();
428
							}
429
						}
430
					}
431
				}
432
			}
433
		}
434
435
		// No post ID, get outta here.
436 46
		if ( empty( $post_id ) ) {
437 1
			return null;
438
		}
439
440
		// If we've saved the permalink in memory, use it
441
		// @since 1.3
442 45
		$link = wp_cache_get( 'gv_directory_link_'.$post_id );
443
444 45
		if ( (int) $post_id === (int) get_option( 'page_on_front' ) ) {
445
			$link = home_url();
446
		}
447
448 45
		if ( empty( $link ) ) {
449 45
			$link = get_permalink( $post_id );
450
451
			// If not yet saved, cache the permalink.
452
			// @since 1.3
453 45
			wp_cache_set( 'gv_directory_link_'.$post_id, $link );
454
		}
455
456
		// Deal with returning to proper pagination for embedded views
457 45
		if ( $link && $add_query_args ) {
458
459 41
			$args = isset( $_GET ) ? $_GET : array();
460
461 41
			if( $pagenum = \GV\Utils::_GET( 'pagenum' ) ) {
462 2
				$args['pagenum'] = intval( $pagenum );
463
			}
464
465 41
			if( $sort = \GV\Utils::_GET( 'sort' ) ) {
466
				$args['sort'] = $sort;
467
				$args['dir'] = \GV\Utils::_GET( 'dir' );
468
			}
469
470 41
			$link = add_query_arg( $args, $link );
471
		}
472
473
		/**
474
		 * @filter `gravityview_directory_link` Modify the URL to the View "directory" context
475
		 * @since 1.19.4
476
		 * @param string $link URL to the View's "directory" context (Multiple Entries screen)
477
		 * @param int $post_id ID of the post to link to. If the View is embedded, it is the post or page ID
478
		 */
479 45
		$link = apply_filters( 'gravityview_directory_link', $link, $post_id );
480
481
		/**
482
		 * @filter `gravityview/view/links/directory` Modify the URL to the View "directory" context
483
		 * @since 2.0
484
		 * @param string $link URL to the View's "directory" context (Multiple Entries screen)
485
		 * @param \GV\Template_Context $context
486
		 */
487 45
		return apply_filters( 'gravityview/view/links/directory', $link, $context );
488
	}
489
490
	/**
491
	 * Calculate an *unique* hash for an entry based on the entry ID
492
	 *
493
	 * 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.
494
	 *
495
	 * The hashed value MUST be unique, otherwise multiple entries will share the same URL, which leads to obvious problems.
496
	 *
497
	 * @param  int|string $id Entry ID to generate the hash for.
498
	 * @param  array  $entry        Entry data passed to provide additional information when generating the hash. Optional - don't rely on it being available.
499
	 * @return string               Hashed unique value for entry
500
	 */
501 3
	private static function get_custom_entry_slug( $id, $entry = array() ) {
502
503
		// Generate an unique hash to use as the default value
504 3
		$slug = substr( wp_hash( $id, 'gravityview'.$id ), 0, 8 );
505
506
		/**
507
		 * @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}`
508
		 * @param string $hash Existing hash generated by GravityView
509
		 * @param  string $id The entry ID
510
		 * @param  array $entry Entry data array. May be empty.
511
		 */
512 3
		$slug = apply_filters( 'gravityview_entry_slug', $slug, $id, $entry );
513
514
		// Make sure we have something - use the original ID as backup.
515 3
		if( empty( $slug ) ) {
516
			$slug = $id;
517
		}
518
519 3
		return sanitize_title( $slug );
520
	}
521
522
	/**
523
	 * Get the entry slug for the entry. By default, it is the entry ID.
524
	 *
525
	 *
526
	 * @see gravityview_get_entry()
527
	 * @uses GravityView_API::get_custom_entry_slug() If using custom slug, gets the custom slug value
528
	 * @since 1.4
529
	 * @param  int|string $id_or_string ID of the entry, or custom slug string
530
	 * @param  array  $entry        Gravity Forms Entry array, optional. Used only to provide data to customize the `gravityview_entry_slug` filter
531
	 * @return string               Unique slug ID, passed through `sanitize_title()`
532
	 */
533 157
	public static function get_entry_slug( $id_or_string, $entry = array() ) {
534
535
		/**
536
		 * Default: use the entry ID as the unique identifier
537
		 */
538 157
		$slug = $id_or_string;
539
540
		/**
541
		 * @filter `gravityview_custom_entry_slug` Whether to enable and use custom entry slugs.
542
		 * @param boolean True: Allow for slugs based on entry values. False: always use entry IDs (default)
543
		 */
544 157
		$custom = apply_filters( 'gravityview_custom_entry_slug', false );
545
546
		// If we're using custom slug...
547 157
		if ( $custom ) {
548
549
			// Get the entry hash
550 3
			$hash = self::get_custom_entry_slug( $id_or_string, $entry );
551
552
			// Cache the slugs
553 3
			static $cache = array();
554
555 3
			if ( ! isset( $cache[ $id_or_string ] ) ) {
556 3
				global $wpdb;
557
558 3
				if ( version_compare( GFFormsModel::get_database_version(), '2.3-dev-1', '>=' ) ) {
559 3
					$table = GFFormsModel::get_entry_meta_table_name();
560 3
					$column = 'entry_id';
561
				} else {
562
					$table = RGFormsModel::get_lead_meta_table_name();
563
					$column = 'lead_id';
564
				}
565
566 3
				$results = $wpdb->get_results( $wpdb->prepare( "SELECT $column, meta_value FROM $table WHERE form_id = (SELECT form_id FROM $table WHERE $column = %d LIMIT 1) AND meta_key = 'gravityview_unique_id'", $id_or_string ) );
567
568 3
				if ( $results ) {
569
					$cache = array_replace( $cache, array_combine( wp_list_pluck( $results, $column ), wp_list_pluck( $results, 'meta_value' ) ) );
570
				}
571
572 3
				if ( ! isset( $cache[ $id_or_string ] ) ) {
573 3
					$cache[ $id_or_string ] = false;
574
				}
575
			}
576
577 3
			$value = $cache[ $id_or_string ];
578
579
			// If it does have a hash set, and the hash is expected, use it.
580
			// This check allows users to change the hash structure using the
581
			// gravityview_entry_hash filter and have the old hashes expire.
582 3
			if ( empty( $value ) || $value !== $hash ) {
583 3
				gravityview()->log->debug( 'Setting hash for entry {entry}: {hash}', array( 'entry' => $id_or_string, 'hash' => $hash ) );
584 3
				gform_update_meta( $id_or_string, 'gravityview_unique_id', $hash, \GV\Utils::get( $entry, 'form_id' ) );
585
			}
586
587 3
			$slug = $hash;
588
589 3
			unset( $value, $hash );
590
		}
591
592 157
		return sanitize_title( $slug );
593
	}
594
595
    /**
596
     * If using the entry custom slug feature, make sure the new entries have the custom slug created and saved as meta
597
     *
598
     * Triggered by add_action( 'gform_entry_created', array( 'GravityView_API', 'entry_create_custom_slug' ), 10, 2 );
599
     *
600
     * @param $entry array Gravity Forms entry object
601
     * @param $form array Gravity Forms form object
602
     */
603
    public static function entry_create_custom_slug( $entry, $form ) {
0 ignored issues
show
Unused Code introduced by
The parameter $form 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...
604
        /**
605
         * @filter `gravityview_custom_entry_slug` On entry creation, check if we are using the custom entry slug feature and update the meta
606
         * @param boolean $custom Should we process the custom entry slug?
607
         */
608
        $custom = apply_filters( 'gravityview_custom_entry_slug', false );
609
        if( $custom ) {
610
            // create the gravityview_unique_id and save it
611
612
            // Get the entry hash
613
            $hash = self::get_custom_entry_slug( $entry['id'], $entry );
614
615
	        gravityview()->log->debug( 'Setting hash for entry {entry_id}: {hash}', array( 'entry_id' => $entry['id'], 'hash' => $hash ) );
616
617
            gform_update_meta( $entry['id'], 'gravityview_unique_id', $hash, \GV\Utils::get( $entry, 'form_id' ) );
618
619
        }
620
    }
621
622
623
624
625
	/**
626
	 * return href for single entry
627
	 *
628
	 * @since 1.7.3 Added $add_directory_args parameter
629
	 * @since 2.7.2 Added $view_id parameter
630
	 * @since 2.10  Added $_GET args to links by default. Use `gravityview/entry_link/add_query_args` filter to override.
631
	 *
632
	 * @param  array|int $entry   Entry array or entry ID.
633
	 * @param  int|null $post_id If wanting to define the parent post, pass a post ID.
634
	 * @param boolean $add_directory_args True: Add args to help return to directory; False: only include args required to get to entry.
635
	 * @param int $view_id
636
	 *
637
	 * @return string Link to the entry with the directory parent slug, or empty string if embedded post or View doesn't exist
638 6
	 */
639
	public static function entry_link( $entry, $post_id = NULL, $add_directory_args = true, $view_id = 0 ) {
640 6
641
		if ( ! empty( $entry ) && ! is_array( $entry ) ) {
642 6
			$entry = GVCommon::get_entry( $entry );
643
		} else if( empty( $entry ) ) {
644
			// @deprecated path
645
			$entry = GravityView_frontend::getInstance()->getEntry();
646
		}
647
648 6
		// Second parameter used to be passed as $field; this makes sure it's not an array
649 1
		if ( ! is_numeric( $post_id ) ) {
650
			$post_id = NULL;
651
		}
652
653 6
		// Get the permalink to the View
654
		$directory_link = self::directory_link( $post_id, false );
655
656 6
		// No post ID? Get outta here.
657 1
		if ( empty( $directory_link ) ) {
658
			return '';
659
		}
660 5
661
		$query_arg_name = \GV\Entry::get_endpoint_name();
662 5
663 1
		if ( ! empty( $entry['_multi'] ) ) {
664
			$entry_slugs = array();
665 1
666
			foreach ( $entry['_multi'] as $_multi ) {
667 1
668 1
				if( $gv_multi = \GV\GF_Entry::from_entry( $_multi ) ) {
669
					$entry_slugs[] = $gv_multi->get_slug();
670
				} else {
671
					// TODO: This path isn't covered by unit tests
672
					$entry_slugs[] = \GravityView_API::get_entry_slug( $_multi['id'], $_multi );
673
				}
674 1
675
				unset( $gv_multi );
676 1
677
				$forms[] = $_multi['form_id'];
0 ignored issues
show
Coding Style Comprehensibility introduced by
$forms was never initialized. Although not strictly required by PHP, it is generally a good practice to add $forms = array(); before regardless.

Adding an explicit array definition is generally preferable to implicit array definition as it guarantees a stable state of the code.

Let’s take a look at an example:

foreach ($collection as $item) {
    $myArray['foo'] = $item->getFoo();

    if ($item->hasBar()) {
        $myArray['bar'] = $item->getBar();
    }

    // do something with $myArray
}

As you can see in this example, the array $myArray is initialized the first time when the foreach loop is entered. You can also see that the value of the bar key is only written conditionally; thus, its value might result from a previous iteration.

This might or might not be intended. To make your intention clear, your code more readible and to avoid accidental bugs, we recommend to add an explicit initialization $myArray = array() either outside or inside the foreach loop.

Loading history...
678
			}
679 1
680
			$entry_slug = implode( ',', $entry_slugs );
681
		} else {
682
683 5
			// Fallback when
684 5
			if( $gv_entry = \GV\GF_Entry::from_entry( $entry ) ) {
685
				$entry_slug = $gv_entry->get_slug();
686
			} else {
687
				// TODO: This path isn't covered by unit tests
688
				$entry_slug = \GravityView_API::get_entry_slug( $entry['id'], $entry );
689
			}
690 5
691
			unset( $gv_entry );
692
		}
693 5
694
		$args = array();
695
696
		/**
697
		 * @filter `gravityview/entry_link/add_query_args` Modify whether to include passed $_GET parameters to the end of the url
698
		 * @since 2.10
699
		 * @param bool $add_query_params Whether to include passed $_GET parameters to the end of the Entry Link URL. Default: true.
700
		 */
701
		$add_query_args = apply_filters( 'gravityview/entry_link/add_query_args', true );
702
703
		if ( $add_query_args ) {
704
			$args = gv_get_query_args();
705
		}
706
707
		if ( get_option('permalink_structure') && ! is_preview() ) {
708
709 5
			/**
710
			 * Make sure the $directory_link doesn't contain any query otherwise it will break when adding the entry slug.
711
			 * @since 1.16.5
712
			 */
713
			$link_parts = explode( '?', $directory_link );
714
715 5
			$query = !empty( $link_parts[1] ) ? '?'.$link_parts[1] : '';
716
717 5
			$directory_link = trailingslashit( $link_parts[0] ) . $query_arg_name . '/'. $entry_slug .'/' . $query;
718
719
		} else {
720
721
			$args[] = array( $query_arg_name => $entry_slug );
722
		}
723
724 5
		/**
725
		 * @since 1.7.3
726
		 */
727
		if ( $add_directory_args ) {
728
729
			if ( ! empty( $_GET['pagenum'] ) ) {
730
				$args['pagenum'] = intval( $_GET['pagenum'] );
731 5
			}
732 5
733 5
			/**
734 5
			 * @since 1.7
735
			 */
736
			if ( $sort = \GV\Utils::_GET( 'sort' ) ) {
737
				$args['sort'] = $sort;
738
				$args['dir'] = \GV\Utils::_GET( 'dir' );
739 5
			}
740 1
741
		}
742
743 5
		if( $post_id ) {
744
			$passed_post = get_post( $post_id );
745
			$views       = \GV\View_Collection::from_post( $passed_post );
746
			$has_multiple_views = $views->count() > 1;
747
		} else {
748
			$has_multiple_views = class_exists( 'GravityView_View_Data' ) && 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...
749
		}
750
751
		if ( $has_multiple_views ) {
752
			$args['gvid'] = $view_id ? $view_id : gravityview_get_view_id();
753
		}
754
755
		return add_query_arg( $args, $directory_link );
756
757 2
	}
758
759
760
}
761 37
762
/**
763
 * Returns query parameters from $_GET with reserved internal GravityView keys removed
764
 *
765
 * @uses stripslashes_deep() $_GET is passed through stripslashes_deep().
766
 * @uses urldecode_deep() $_GET is passed through urldecode_deep().
767
 *
768
 * Important: The return value of gv_get_query_args() is not escaped by default. Output should be
769
 * late-escaped with esc_url() or similar to help prevent vulnerability to cross-site scripting
770
 * (XSS) attacks.
771
 *
772
 * @since 2.10
773
 *
774
 * @return array
775
 */
776
function gv_get_query_args() {
777
778 38
	$passed_get = isset( $_GET ) ? $_GET : array();
779 36
780 36
	$passed_get = stripslashes_deep( $passed_get );
781 36
	$passed_get = urldecode_deep( $passed_get );
782 36
783 36
	if ( empty( $passed_get ) ) {
784 36
		return array();
785 4
	}
786
787
	$query_args = $passed_get;
788 36
789 23
	$reserved_args = array(
790 17
		'gvid',
791 36
		'status',
792
		'action',
793
		'view_id',
794
		'entry_id',
795 3
	);
796 3
797 3
	/**
798
	 * @filter `gravityview/api/reserved_query_args` Modify the URL arguments that should not be used because they are internal to GravityView
799
	 * @since 2.10
800 38
	 * @param array $reserved_args Array of URL query keys that should not be used except internally.
801
	 */
802 38
	$reserved_args = apply_filters( 'gravityview/api/reserved_query_args', $reserved_args );
803
804 38
	foreach ( $reserved_args as $reserved_arg ) {
805 4
		unset( $query_args[ $reserved_arg ] );
806
	}
807
808 38
	return $query_args;
809 8
}
810
811
812 38
// inside loop functions
813 36
814
/**
815
 * @deprecated Use \GV\Field::get_label()
816 38
 */
817
function gv_label( $field, $entry = NULL ) {
818
	return GravityView_API::field_label( $field, $entry );
0 ignored issues
show
Deprecated Code introduced by
The method GravityView_API::field_label() has been deprecated with message: Use \GV\Field::get_label()

This method has been deprecated. The supplier of the class has supplied an explanatory message.

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

Loading history...
819
}
820
821
function gv_class( $field, $form = NULL, $entry = array() ) {
822
	return GravityView_API::field_class( $field, $form, $entry  );
823
}
824
825 38
/**
826
 * Generate a CSS class to be added to the wrapper <div> of a View
827 38
 *
828
 * @since 1.5.4
829 38
 * @since 1.16 Added $echo parameter.
830 38
 * @since 2.0 Added $context parameter.
831
 *
832
 * @param string $passed_css_class Default: `gv-container gv-container-{view id}`. If View is hidden until search, adds ` hidden`
833 38
 * @param boolean $echo Whether to echo the output. Default: true
834
 * @param \GV\Template_Context $context The template context.
835
 *
836
 * @return string CSS class, sanitized by gravityview_sanitize_html_class()
837
 */
838
function gv_container_class( $passed_css_class = '', $echo = true, $context = null ) {
839
	if ( $context instanceof \GV\Template_Context ) {
840
		$hide_until_searched = false;
841 2
		$total_entries = 0;
842
		$view_id = 0;
843 2
		if ( $context->view ) {
844
			$view_id = $context->view->ID;
845
			if( $context->view->settings->get( 'hide_until_searched' ) ) {
846
				$hide_until_searched = ( empty( $context->entry ) && ! $context->request->is_search() );
847
			}
848 1
		}
849
		if ( $context->entries ) {
850
			$total_entries = $context->entries->total();
851 2
		} else if ( $context->entry ) {
852
			$total_entries = 1;
853
		}
854
	} else {
855 18
		/** @deprecated legacy execution path */
856
		$view_id = GravityView_View::getInstance()->getViewId();
857
		$hide_until_searched = GravityView_View::getInstance()->isHideUntilSearched();
858
		$total_entries = GravityView_View::getInstance()->getTotalEntries();
859 2
	}
860
861
	$passed_css_class = trim( $passed_css_class );
862
863 9
	$default_css_class = ! empty( $view_id ) ? sprintf( 'gv-container gv-container-%d', $view_id ) : 'gv-container';
864
865
	if ( $hide_until_searched ) {
866
		$default_css_class .= ' hidden';
867
	}
868
869
	if ( 0 === $total_entries ) {
870
		$default_css_class .= ' gv-container-no-results';
871
	}
872
873
	if ( $context instanceof \GV\Template_Context && $context->view ) {
874
		$default_css_class .= ' ' . $context->view->settings->get( 'class', '' );
875 17
	}
876
877
	$css_class = trim( $passed_css_class . ' '. $default_css_class );
878
879
	/**
880
	 * @filter `gravityview/render/container/class` Modify the CSS class to be added to the wrapper <div> of a View
881
	 * @since 1.5.4
882
	 * @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`
883
	 * @since 2.0
884 17
	 * @param \GV\Template_Context $context The context.
885
	 */
886
	$css_class = apply_filters( 'gravityview/render/container/class', $css_class, $context );
887
888
	$css_class = gravityview_sanitize_html_class( $css_class );
889
890
	if ( $echo ) {
891
		echo $css_class;
892
	}
893 17
894
	return $css_class;
895 17
}
896 4
897
/**
898
 * @deprecated Use \GV\Field_Template::render()
899 14
 */
900 14
function gv_value( $entry, $field ) {
901 14
902
	$value = GravityView_API::field_value( $entry, $field );
0 ignored issues
show
Deprecated Code introduced by
The method GravityView_API::field_value() has been deprecated with message: Use \GV\Field_Template::render() or the more low-level \GV\Field::get_value()

This method has been deprecated. The supplier of the class has supplied an explanatory message.

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

Loading history...
903
904
	if( $value === '' ) {
905
		/**
906
		 * @filter `gravityview_empty_value` What to display when a field is empty
907
		 * @param string $value (empty string)
908
		 */
909
		$value = apply_filters( 'gravityview_empty_value', '' );
910 14
	}
911
912
	return $value;
913
}
914
915
function gv_directory_link( $post = NULL, $add_pagination = true, $context = null ) {
916
	return GravityView_API::directory_link( $post, $add_pagination, $context );
917
}
918 14
919
function gv_entry_link( $entry, $post_id = NULL ) {
920
	return GravityView_API::entry_link( $entry, $post_id );
921
}
922
923
function gv_no_results( $wpautop = true, $context = null ) {
924
	return GravityView_API::no_results( $wpautop, $context );
925
}
926
927 14
/**
928
 * Generate HTML for the back link from single entry view
929
 * @since 1.0.1
930
 * @since 2.0
931
 * @param \GV\Template_Context $context The context this link is being displayed from.
932
 * @return string|null      If no GV post exists, null. Otherwise, HTML string of back link.
933
 */
934
function gravityview_back_link( $context = null ) {
935 14
936
	$href = gv_directory_link( null, true, $context );
937 14
938
	/**
939 14
	 * @filter `gravityview_go_back_url` Modify the back link URL
940
	 * @since 1.17.5
941
	 * @see gv_directory_link() Generated the original back link
942
	 * @param string $href Existing label URL
943
	 * @deprecated Use `gravityview/template/links/back/url`
944
	 */
945
	$href = apply_filters( 'gravityview_go_back_url', $href );
946
947
	/**
948
	 * @filter `gravityview/template/links/back/url` Modify the back link URL
949
	 * @since 2.0
950
	 * @see gv_directory_link() Generated the original back link
951
	 * @param string $href Existing label URL
952
	 * @param \GV\Template_Context The context.
953
	 */
954
	$href = apply_filters( 'gravityview/template/links/back/url', $href, $context );
955
956 15
	if ( empty( $href ) ) {
957
		return NULL;
958
	}
959 12
960
	if ( $context instanceof \GV\Template_Context ) {
961
		$view_id = $context->view->ID;
962
		$view_label = $context->template->get_back_label();
0 ignored issues
show
Bug introduced by
It seems like you code against a specific sub-type and not the parent class GV\Template as the method get_back_label() does only exist in the following sub-classes of GV\Template: GV\Entry_Legacy_Template, GV\Entry_List_Template, GV\Entry_Table_Template, GV\Entry_Template. Maybe you want to instanceof check for one of these explicitly?

Let’s take a look at an example:

abstract class User
{
    /** @return string */
    abstract public function getPassword();
}

class MyUser extends User
{
    public function getPassword()
    {
        // return something
    }

    public function getDisplayName()
    {
        // return some name.
    }
}

class AuthSystem
{
    public function authenticate(User $user)
    {
        $this->logger->info(sprintf('Authenticating %s.', $user->getDisplayName()));
        // do something.
    }
}

In the above example, the authenticate() method works fine as long as you just pass instances of MyUser. However, if you now also want to pass a different sub-classes of User which does not have a getDisplayName() method, the code will break.

Available Fixes

  1. Change the type-hint for the parameter:

    class AuthSystem
    {
        public function authenticate(MyUser $user) { /* ... */ }
    }
    
  2. Add an additional type-check:

    class AuthSystem
    {
        public function authenticate(User $user)
        {
            if ($user instanceof MyUser) {
                $this->logger->info(/** ... */);
            }
    
            // or alternatively
            if ( ! $user instanceof MyUser) {
                throw new \LogicException(
                    '$user must be an instance of MyUser, '
                   .'other instances are not supported.'
                );
            }
    
        }
    }
    
Note: PHP Analyzer uses reverse abstract interpretation to narrow down the types inside the if block in such a case.
  1. Add the method to the parent class:

    abstract class User
    {
        /** @return string */
        abstract public function getPassword();
    
        /** @return string */
        abstract public function getDisplayName();
    }
    
Loading history...
963
	} else {
964 7
		/** @deprecated legacy path */
965
		$gravityview_view = GravityView_View::getInstance();
966
		$view_id = $gravityview_view->getViewId();
967
		$view_label = $gravityview_view->getBackLinkLabel() ? $gravityview_view->getBackLinkLabel() : false;
0 ignored issues
show
Deprecated Code introduced by
The method GravityView_View::getBackLinkLabel() has been deprecated with message: Use $template->get_back_label();

This method has been deprecated. The supplier of the class has supplied an explanatory message.

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

Loading history...
968
	}
969
970
	/** Default */
971
	$label = $view_label ? $view_label : __( '&larr; Go back', 'gravityview' );
972
973
	/**
974
	 * @filter `gravityview_go_back_label` Modify the back link text
975
	 * @since 1.0.9
976
	 * @param string $label Existing label text
977
	 * @deprecated Use `gravityview/template/links/back/label`
978
	 */
979
	$label = apply_filters( 'gravityview_go_back_label', $label );
980
981
	/**
982 1
	 * @filter `gravityview/template/links/back/label` Modify the back link text
983
	 * @since 2.0
984 1
	 * @see gv_directory_link() Generated the original back link
985 1
	 * @param string $label Existing label text
986
	 * @param \GV\Template_Context The context.
987 1
	 */
988
	$label = apply_filters( 'gravityview/template/links/back/label', $label, $context );
989
990 1
	/**
991
	 * @filter `gravityview/template/links/back/atts` Modify the attributes used on the back link anchor tag
992
	 * @since 2.1
993 1
	 * @param array $atts Original attributes, default: [ data-viewid => $view_id ]
994
	 * @param \GV\Template_Context The context.
995
	 */
996 1
	$atts = apply_filters( 'gravityview/template/links/back/atts', array( 'data-viewid' => $view_id ), $context );
997
998
	$link = gravityview_get_link( $href, esc_html( $label ), $atts );
999 1
1000 1
	return $link;
1001
}
1002
1003 1
/**
1004
 * Handle getting values for complex Gravity Forms fields
1005
 *
1006
 * If the field is complex, like a product, the field ID, for example, 11, won't exist. Instead,
1007
 * it will be 11.1, 11.2, and 11.3. This handles being passed 11 and 11.2 with the same function.
1008 1
 *
1009
 * @since 1.0.4
1010
 * @param  array      $entry    GF entry array
1011
 * @param  string      $field_id [description]
1012 1
 * @param  string 	$display_value The value generated by Gravity Forms
1013
 * @return string                Value
1014 1
 */
1015
function gravityview_get_field_value( $entry, $field_id, $display_value ) {
1016
1017 1
	if( floatval( $field_id ) === floor( floatval( $field_id ) ) ) {
1018
1019
		// For the complete field value as generated by Gravity Forms
1020
		return $display_value;
1021 1
1022
	} else {
1023
1024
		// For one part of the address (City, ZIP, etc.)
1025 1
		return isset( $entry[ $field_id ] ) ? $entry[ $field_id ] : '';
1026
1027
	}
1028
1029
}
1030
1031
/**
1032
 * Take a passed CSV of terms and generate a linked list of terms
1033
 *
1034
 * Gravity Forms passes categories as "Name:ID" so we handle that using the ID, which
1035
 * is more accurate than checking the name, which is more likely to change.
1036
 *
1037 1
 * @param  string      $value    Existing value
1038
 * @param  string      $taxonomy Type of term (`post_tag` or `category`)
1039 1
 * @return string                CSV of linked terms
1040 1
 */
1041
function gravityview_convert_value_to_term_list( $value, $taxonomy = 'post_tag' ) {
1042
1043 1
	$output = array();
1044
1045
	if ( is_array( $value ) ) {
1046
		$terms = array_filter( array_values( $value ), 'strlen' );
1047
	} else {
1048
		$terms = explode( ', ', $value );
1049
	}
1050
1051
	foreach ($terms as $term_name ) {
1052
1053
		// If we're processing a category,
1054
		if( $taxonomy === 'category' ) {
1055
1056 1
			// Use rgexplode to prevent errors if : doesn't exist
1057
			list( $term_name, $term_id ) = rgexplode( ':', $term_name, 2 );
1058
1059 1
			// The explode was succesful; we have the category ID
1060
			if( !empty( $term_id )) {
1061 1
				$term = get_term_by( 'id', $term_id, $taxonomy );
1062
			} else {
1063 1
			// We have to fall back to the name
1064
				$term = get_term_by( 'name', $term_name, $taxonomy );
1065
			}
1066
1067 1
		} else {
1068
			// Use the name of the tag to get the full term information
1069
			$term = get_term_by( 'name', $term_name, $taxonomy );
1070
		}
1071
1072
		// There's still a tag/category here.
1073
		if( $term ) {
1074 1
1075
			$term_link = get_term_link( $term, $taxonomy );
1076
1077
			// If there was an error, continue to the next term.
1078
			if ( is_wp_error( $term_link ) ) {
1079
			    continue;
1080
			}
1081
1082
			$output[] = gravityview_get_link( $term_link, esc_html( $term->name ) );
1083
		}
1084
	}
1085
1086
	return implode(', ', $output );
1087
}
1088
1089
/**
1090
 * Get the links for post_tags and post_category output based on post ID
1091
 * @param  int      $post_id  The ID of the post
1092
 * @param  boolean     $link     Add links or no?
1093
 * @param  string      $taxonomy Taxonomy of term to fetch.
1094
 * @return string                String with terms
1095
 */
1096
function gravityview_get_the_term_list( $post_id, $link = true, $taxonomy = 'post_tag' ) {
1097
1098
	$output = get_the_term_list( $post_id, $taxonomy, NULL, ', ' );
1099
1100
	if( empty( $link ) ) {
1101
		return strip_tags( $output);
1102
	}
1103
1104
	return $output;
1105
1106
}
1107
1108
1109
/**
1110
 * Get all views processed so far for the current page load
1111
 *
1112 37
 * @see  GravityView_View_Data::add_view()
1113 35
 * @return array Array of View data, each View data with `id`, `view_id`, `form_id`, `template_id`, `atts`, `fields`, `widgets`, `form` keys.
1114 35
 */
1115
function gravityview_get_current_views() {
1116
1117
	$fe = GravityView_frontend::getInstance();
1118
1119 35
	// Solve problem when loading content via admin-ajax.php
1120
	if( ! $fe->getGvOutputData() ) {
1121
1122
		gravityview()->log->debug( 'gv_output_data not defined; parsing content.' );
1123
1124 35
		$fe->parse_content();
1125
	}
1126
1127
	// Make 100% sure that we're dealing with a properly called situation
1128
	if( !is_a( $fe->getGvOutputData(), 'GravityView_View_Data' ) ) {
1129
1130
		gravityview()->log->debug( 'gv_output_data not an object or get_view not callable.', array( 'data' => $fe->getGvOutputData() ) );
1131
1132
		return array();
1133 2
	}
1134 2
1135
	return $fe->getGvOutputData()->get_views();
0 ignored issues
show
Deprecated Code introduced by
The method GravityView_View_Data::get_views() has been deprecated.

This method has been deprecated.

Loading history...
1136
}
1137
1138
/**
1139
 * Get data for a specific view
1140
 *
1141 33
 * @deprecated use \GV\View API instead
1142 31
 * @since 2.5
1143 31
 *
1144
 * @see  GravityView_View_Data::get_view()
1145
 * @return array View data with `id`, `view_id`, `form_id`, `template_id`, `atts`, `fields`, `widgets`, `form` keys.
1146
 */
1147
function gravityview_get_current_view_data( $view_id = 0 ) {
1148 31
	if ( $view_id ) {
1149
		if ( $view = \GV\View::by_id( $view_id ) ) {
1150
			return $view; // implements ArrayAccess
1151
		}
1152
		return array();
1153 31
	}
1154
1155
	$fe = GravityView_frontend::getInstance();
1156
1157
	// If not set, grab the current view ID
1158
	if ( empty( $view_id ) ) {
1159
		$view_id = $fe->get_context_view_id();
1160
	}
1161
1162 2
	if ( ! $fe->getGvOutputData() ) { return array(); }
1163 2
1164
	return $fe->getGvOutputData()->get_view( $view_id );
0 ignored issues
show
Deprecated Code introduced by
The method GravityView_View_Data::get_view() has been deprecated.

This method has been deprecated.

Loading history...
1165
}
1166
1167
// Templates' hooks
1168
function gravityview_before() {
1169
	/**
1170 33
	 * @action `gravityview/template/before` Append content to the view.
1171 31
	 * @param object $gravityview The $gravityview object available in templates.
1172 31
	 */
1173
	if ( count( $args = func_get_args() ) ) {
1174
		$gravityview = reset( $args );
1175
		if ( $gravityview instanceof \GV\Template_Context ) {
1176
			/**
1177 31
			 * @action `gravityview/template/before` Prepend content to the view.
1178
			 * @param \GV\Template_Context $gravityview The $gravityview object available in templates.
1179
			 */
1180
			do_action( 'gravityview/template/before', $gravityview );
1181
1182 31
			/**
1183
			 * @deprecated Use `gravityview/template/before`
1184
			 */
1185
			return do_action( 'gravityview_before', $gravityview->view->ID );
1186
		}
1187
	}
1188
1189
	/**
1190
	 * @action `gravityview_before` Prepend content to the View container `<div>`
1191 2
	 * @deprecated Use `gravityview/template/before`.
1192 2
	 * @param int $view_id The ID of the View being displayed
1193
	 */
1194
	do_action( 'gravityview_before', gravityview_get_view_id() );
1195 37
}
1196 35
1197 35
function gravityview_header() {
1198
	/**
1199
	 * @action `gravityview/template/header` Append content to the view.
1200
	 * @param object $gravityview The $gravityview object available in templates.
1201
	 */
1202 35
	if ( count( $args = func_get_args() ) ) {
1203
		$gravityview = reset( $args );
1204
		if ( $gravityview instanceof \GV\Template_Context ) {
1205
			/**
1206
			 * @action `gravityview/template/header` Prepend content to the view container <div>.
1207 35
			 * @param \GV\Template_Context $gravityview The $gravityview object available in templates.
1208
			 */
1209 35
			do_action( 'gravityview/template/header', $gravityview );
1210
1211
			/**
1212
			 * @deprecated Use `gravityview/template/header`
1213
			 */
1214
			return do_action( 'gravityview_header', $gravityview->view->ID );
1215
		}
1216
	}
1217
1218 2
	/**
1219 2
	 * @action `gravityview_header` Prepend content to the View container `<div>`
1220
	 * @deprecated Use `gravityview/template/header`.
1221
	 * @param int $view_id The ID of the View being displayed
1222
	 */
1223
	do_action( 'gravityview_header', gravityview_get_view_id() );
1224
}
1225
1226
function gravityview_footer() {
1227
	/**
1228
	 * @action `gravityview/template/footer` Append content to the view.
1229
	 * @param object $gravityview The $gravityview object available in templates.
1230 2
	 */
1231
	if ( count( $args = func_get_args() ) ) {
1232
		$gravityview = reset( $args );
1233
		if ( $gravityview instanceof \GV\Template_Context ) {
1234 2
			/**
1235
			 * @action `gravityview/template/footer` Prepend outside of the view container <div>.
1236
			 * @param \GV\Template_Context $gravityview The $gravityview object available in templates.
1237
			 */
1238
			do_action( 'gravityview/template/footer', $gravityview );
1239
1240
			/**
1241
			 * @deprecated Use `gravityview/template/footer`
1242
			 */
1243
			return do_action( 'gravityview_footer', $gravityview->view->ID );
1244
		}
1245
	}
1246
1247
	/**
1248
	 * @action `gravityview_after` Display content after a View. Used to render footer widget areas. Rendered outside the View container `<div>`
1249
	 * @deprecated Use `gravityview/template/footer`.
1250
	 * @param int $view_id The ID of the View being displayed
1251 4
	 */
1252
	do_action( 'gravityview_footer', gravityview_get_view_id() );
1253 4
}
1254
1255
function gravityview_after() {
1256
	if ( count( $args = func_get_args() ) ) {
1257
		$gravityview = reset( $args );
1258
		if ( $gravityview instanceof \GV\Template_Context ) {
1259
			/**
1260
			 * @action `gravityview/template/after` Append content to the view.
1261
			 * @param \GV\Template_Context $gravityview The $gravityview object available in templates.
1262 4
			 */
1263
			do_action( 'gravityview/template/after', $gravityview );
1264 4
1265
			/**
1266 4
			 * @deprecated Use `gravityview/template/after`
1267 1
			 */
1268 4
			do_action( 'gravityview_after', $gravityview->view->ID );
1269 4
1270
			return;
1271
		}
1272
	}
1273
1274
	/**
1275
	 * @action `gravityview_after` Append content to the View container `<div>`
1276
	 * @deprecated Use `gravityview/template/after`
1277
	 * @param int $view_id The ID of the View being displayed
1278
	 */
1279
	do_action( 'gravityview_after', gravityview_get_view_id() );
1280
}
1281
1282
/**
1283
 * Get the current View ID being rendered
1284
 *
1285
 * @global GravityView_View $gravityview_view
1286
 *
1287
 * @return int View ID, if exists. `0` if `GravityView_View` doesn't exist, like in the admin, or no View is set.
1288
 */
1289
function gravityview_get_view_id() {
1290
1291
	if ( ! class_exists( 'GravityView_View' ) ) {
1292
		return 0;
1293
	}
1294
1295
	return GravityView_View::getInstance()->getViewId();
1296
}
1297
1298 5
/**
1299
 * Returns the current GravityView context, or empty string if not GravityView
1300
 *
1301
 * - Returns empty string on GravityView archive pages
1302 5
 * - Returns empty string on archive pages containing embedded Views
1303
 * - Returns empty string for embedded Views, not 'directory'
1304
 * - Returns empty string for embedded entries (oEmbed or [gventry]), not 'single'
1305
 * - Returns 'single' when viewing a [gravityview] shortcode-embedded single entry
1306 5
 *
1307
 * @global GravityView_View $gravityview_view
1308
 * @deprecated since 2.0.6.2 Use `gravityview()->request`
1309
 * @return string View context "directory", "single", "edit", or empty string if not GravityView
1310 5
 */
1311
function gravityview_get_context() {
1312
	global $wp_query;
1313
1314
	if ( isset( $wp_query ) && $wp_query->post_count > 1 ) {
1315
		return '';
1316
	}
1317
1318
	/**
1319
	 * @filter `gravityview_is_edit_entry` Whether we're currently on the Edit Entry screen \n
1320
	 * The Edit Entry functionality overrides this value.
1321
	 * @param boolean $is_edit_entry
1322
	 */
1323
	$is_edit_entry = apply_filters( 'gravityview_is_edit_entry', false );
1324
1325
	if ( $is_edit_entry ) {
1326 1
		return 'edit';
1327 1
	} else if ( gravityview()->request->is_entry() ) {
1328
		return 'single';
1329 1
	} else if ( gravityview()->request->is_view() ) {
1330
		return 'directory';
1331 1
	}
1332
1333 1
	return '';
1334
}
1335
1336
1337
/**
1338
 * Return an array of files prepared for output. Wrapper for GravityView_Field_FileUpload::get_files_array()
1339
 *
1340
 * Processes files by file type and generates unique output for each.
1341 1
 *
1342
 * Returns array for each file, with the following keys:
1343 1
 *
1344
 * `file_path` => The file path of the file, with a line break
1345
 * `html` => The file output HTML formatted
1346
 *
1347
 * @see GravityView_Field_FileUpload::get_files_array()
1348
 *
1349
 * @since  1.2
1350
 * @param  string $value    Field value passed by Gravity Forms. String of file URL, or serialized string of file URL array
1351
 * @param  string $gv_class Field class to add to the output HTML
1352
 * @since  2.0
1353
 * @param  \GV\Template_Context $context The context
1354
 * @return array           Array of file output, with `file_path` and `html` keys (see comments above)
1355
 */
1356
function gravityview_get_files_array( $value, $gv_class = '', $context = null ) {
1357
	/** @define "GRAVITYVIEW_DIR" "../" */
1358
1359
	if( !class_exists( 'GravityView_Field' ) ) {
1360
		include_once( GRAVITYVIEW_DIR .'includes/fields/class-gravityview-field.php' );
1361
	}
1362
1363
	if( !class_exists( 'GravityView_Field_FileUpload' ) ) {
1364
		include_once( GRAVITYVIEW_DIR .'includes/fields/class-gravityview-field-fileupload.php' );
1365
	}
1366 34
1367
	if ( is_null( $context ) ) {
1368
		_doing_it_wrong( __FUNCTION__, '2.0', 'Please pass an \GV\Template_Context object as the 3rd parameter' );
1369
	}
1370
1371
	return GravityView_Field_FileUpload::get_files_array( $value, $gv_class, $context );
1372
}
1373
1374
/**
1375
 * Generate a mapping link from an address
1376 34
 *
1377
 * The address should be plain text with new line (`\n`) or `<br />` line breaks separating sections
1378
 *
1379
 * @todo use GF's field get_export_value() instead
1380
 *
1381
 * @see https://gravityview.co/support/documentation/201608159 Read how to modify the link
1382
 * @param  string $address Address
1383
 * @return string          URL of link to map of address
1384
 */
1385
function gravityview_get_map_link( $address ) {
1386
1387 34
	$address_qs = str_replace( array( '<br />', "\n" ), ' ', $address ); // Replace \n with spaces
1388
	$address_qs = urlencode( $address_qs );
1389
1390
	$url = "https://maps.google.com/maps?q={$address_qs}";
1391
1392
	$link_text = esc_html__( 'Map It', 'gravityview' );
1393
1394
	$link = gravityview_get_link( $url, $link_text, 'class=map-it-link' );
1395
1396 34
	/**
1397
	 * @filter `gravityview_map_link` Modify the map link generated. You can use a different mapping service, for example.
1398 34
	 * @param[in,out]  string $link Map link
1399 32
	 * @param[in] string $address Address to generate link for
1400
	 * @param[in] string $url URL generated by the function
1401 32
	 */
1402
	$link = apply_filters( 'gravityview_map_link', $link, $address, $url );
1403
1404
	return $link;
1405
}
1406 2
1407
1408
/**
1409
 * Output field based on a certain html markup
1410
 *
1411
 *   markup - string to be used on a sprintf statement.
1412 34
 *      Use:
1413 32
 *         {{label}} - field label
1414 32
 *         {{value}} - entry field value
1415 32
 *         {{class}} - field class
1416
 *
1417
 *   wpautop - true will filter the value using wpautop function
1418 2
 *
1419 2
 * @since  1.1.5
1420 2
 * @param  array $passed_args Associative array with field data. `field` and `form` are required.
1421
 * @since  2.0
1422
 * @param  \GV\Template_Context The template context.
1423
 * @return string Field output. If empty value and hide empty is true, return empty.
1424
 */
1425
function gravityview_field_output( $passed_args, $context = null ) {
1426
	$defaults = array(
1427
		'entry' => null,
1428 34
		'field' => null,
1429
		'form' => null,
1430
		'hide_empty' => true,
1431
		'markup' => '<div id="{{ field_id }}" class="{{ class }}">{{ label }}{{ value }}</div>',
1432
		'label_markup' => '',
1433
		'wpautop' => false,
1434
		'zone_id' => null,
1435
	);
1436
1437
	$args = wp_parse_args( $passed_args, $defaults );
1438
1439 34
	/**
1440 32
	 * @filter `gravityview/field_output/args` Modify the args before generation begins
1441
	 * @since 1.7
1442
	 * @param array $args Associative array; `field` and `form` is required.
1443 2
	 * @param array $passed_args Original associative array with field data. `field` and `form` are required.
1444
	 * @since 2.0
1445
	 * @param \GV\Template_Context $context The context.
1446
	 * @deprecated
1447 34
	 */
1448 5
	$args = apply_filters( 'gravityview/field_output/args', $args, $passed_args, $context );
1449
1450
	/**
1451 34
	 * @filter `gravityview/template/field_output/context` Modify the context before generation begins.
1452 5
	 * @since 2.0
1453
	 * @param[in,out] \GV\Template_Context $context The context.
1454
	 * @param array $args The sanitized arguments, these should not be trusted any longer.
1455
	 * @param array $passed_args The passed arguments, these should not be trusted any longer.
1456 34
	 */
1457
	$context = apply_filters( 'gravityview/template/field_output/context', $context, $args, $passed_args );
1458
1459 34
	if ( $context instanceof \GV\Template_Context ) {
1460
		if ( ! $context->field || ! $context->view || ! $context->view->form ) {
1461
			gravityview()->log->error( 'Field or form are empty.', array( 'data' => array( $context->field, $context->view->form ) ) );
1462 34
			return '';
1463 34
		}
1464
	} else {
1465 34
		// @deprecated path
1466 32
		// Required fields.
1467
		if ( empty( $args['field'] ) || empty( $args['form'] ) ) {
1468
			gravityview()->log->error( 'Field or form are empty.', array( 'data' => $args ) );
1469 2
			return '';
1470
		}
1471
	}
1472 34
1473 34
	if ( $context instanceof \GV\Template_Context ) {
1474
		$entry = $args['entry'] ? : ( $context->entry ? $context->entry->as_entry() : array() );
1475 34
		$field = $args['field'] ? : ( $context->field ? $context->field->as_configuration() : array() );
1476 34
		$form = $args['form'] ? : ( $context->view->form ? $context->view->form->form : array() );
0 ignored issues
show
Documentation introduced by
The property $form is declared private in GV\Form. Since you implemented __get(), maybe consider adding a @property or @property-read annotation. This makes it easier for IDEs to provide auto-completion.

Since your code implements the magic setter _set, this function will be called for any write 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.");
        }
    }

}

Since the property has write access only, you can use the @property-write 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...
1477
	} else {
1478
		// @deprecated path
1479
		$entry = empty( $args['entry'] ) ? array() : $args['entry'];
1480
		$field = $args['field'];
1481
		$form = $args['form'];
1482
	}
1483
1484
	/**
1485
	 * Create the content variables for replacing.
1486
	 * @since 1.11
1487 34
	 */
1488
	$placeholders = array(
1489
		'value' => '',
1490
		'width' => '',
1491
		'width:style' => '',
1492
		'label' => '',
1493
		'label_value' => '',
1494
		'label_value:esc_attr' => '',
1495
		'label_value:data-label' => '',
1496 34
		'class' => '',
1497
		'field_id' => '',
1498
	);
1499
1500
	if ( $context instanceof \GV\Template_Context ) {
1501
		$placeholders['value'] = \GV\Utils::get( $args, 'value', '' );
1502
	} else {
1503
		// @deprecated path
1504
		$placeholders['value'] = gv_value( $entry, $field );
0 ignored issues
show
Deprecated Code introduced by
The function gv_value() has been deprecated with message: Use \GV\Field_Template::render()

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...
1505 34
	}
1506
1507
	// If the value is empty and we're hiding empty, return empty.
1508
	if ( $placeholders['value'] === '' && ! empty( $args['hide_empty'] ) ) {
1509
		return '';
1510
	}
1511 34
1512
	if ( $placeholders['value'] !== '' && ! empty( $args['wpautop'] ) ) {
1513
		$placeholders['value'] = wpautop( $placeholders['value'] );
1514 34
	}
1515 34
1516
	// Get width setting, if exists
1517
	$placeholders['width'] = GravityView_API::field_width( $field );
1518
1519
	// If replacing with CSS inline formatting, let's do it.
1520 34
	$placeholders['width:style'] = GravityView_API::field_width( $field, 'width:' . $placeholders['width'] . '%;' );
1521 34
1522
	// Grab the Class using `gv_class`
1523
	$placeholders['class'] = gv_class( $field, $form, $entry );
1524
	$placeholders['field_id'] = GravityView_API::field_html_attr_id( $field, $form, $entry );
1525
1526
	if ( $context instanceof \GV\Template_Context ) {
1527
		$placeholders['label_value'] = \GV\Utils::get( $args, 'label' );
1528
	} else {
1529
		// Default Label value
1530
		$placeholders['label_value'] = gv_label( $field, $entry );
0 ignored issues
show
Deprecated Code introduced by
The function gv_label() has been deprecated with message: Use \GV\Field::get_label()

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...
1531
	}
1532 34
1533
	$placeholders['label_value:data-label'] = trim( esc_attr( strip_tags( str_replace( '>&nbsp;', '>', $placeholders['label_value'] ) ) ) );
1534
	$placeholders['label_value:esc_attr'] = esc_attr( $placeholders['label_value'] );
1535 34
1536
	if ( empty( $placeholders['label'] ) && ! empty( $placeholders['label_value'] ) ){
1537
		$placeholders['label'] = '<span class="gv-field-label">{{ label_value }}</span>';
1538
	}
1539
1540
	/**
1541
	 * @filter `gravityview/field_output/pre_html` Allow Pre filtering of the HTML
1542
	 * @since 1.11
1543
	 * @param string $markup The HTML for the markup
1544
	 * @param array $args All args for the field output
1545 34
	 * @since 2.0
1546
	 * @param \GV\Template_Context $context The context.
1547
	 */
1548
	$html = apply_filters( 'gravityview/field_output/pre_html', $args['markup'], $args, $context );
1549
1550
	/**
1551
	 * @filter `gravityview/field_output/open_tag` Modify the opening tags for the template content placeholders
1552
	 * @since 1.11
1553
	 * @param string $open_tag Open tag for template content placeholders. Default: `{{`
1554 34
	 * @since 2.0
1555
	 * @param \GV\Template_Context $context The context.
1556
	 */
1557 34
	$open_tag = apply_filters( 'gravityview/field_output/open_tag', '{{', $args, $context );
1558
1559 34
	/**
1560
	 * @filter `gravityview/field_output/close_tag` Modify the closing tags for the template content placeholders
1561
	 * @since 1.11
1562
	 * @param string $close_tag Close tag for template content placeholders. Default: `}}`
1563
	 * @since 2.0
1564
	 * @param \GV\Template_Context $context The context.
1565
	 */
1566
	$close_tag = apply_filters( 'gravityview/field_output/close_tag', '}}', $args, $context );
1567
1568
	/**
1569
	 * Loop through each of the tags to replace and replace both `{{tag}}` and `{{ tag }}` with the values
1570
	 * @since 1.11
1571
	 */
1572
	foreach ( $placeholders as $tag => $value ) {
1573
1574
		// If the tag doesn't exist just skip it
1575
		if ( false === strpos( $html, $open_tag . $tag . $close_tag ) && false === strpos( $html, $open_tag . ' ' . $tag . ' ' . $close_tag ) ){
1576
			continue;
1577
		}
1578
1579
		// Array to search
1580
		$search = array(
1581
			$open_tag . $tag . $close_tag,
1582
			$open_tag . ' ' . $tag . ' ' . $close_tag,
1583
		);
1584
1585
		/**
1586
		 * `gravityview/field_output/context/{$tag}` Allow users to filter content on context
1587
		 * @since 1.11
1588
		 * @param string $value The content to be shown instead of the {{tag}} placeholder
1589
		 * @param array $args Arguments passed to the function
1590
		 * @since 2.0
1591
		 * @param \GV\Template_Context $context The context.
1592
		 */
1593
		$value = apply_filters( 'gravityview/field_output/context/' . $tag, $value, $args, $context );
1594
1595
		// Finally do the replace
1596
		$html = str_replace( $search, $value, $html );
1597
	}
1598
1599
	/**
1600
	 * @filter `gravityview_field_output` Modify field HTML output
1601
	 * @param string $html Existing HTML output
1602
	 * @param array $args Arguments passed to the function
1603
	 * @since 2.0
1604
	 * @param \GV\Template_Context $context The context.
1605
	 */
1606
	$html = apply_filters( 'gravityview_field_output', $html, $args, $context );
1607
1608
	/**
1609
	 * @filter `gravityview/field_output/html` Modify field HTML output
1610
	 * @param string $html Existing HTML output
1611
	 * @param array $args Arguments passed to the function
1612
	 * @since 2.0
1613
	 * @param \GV\Template_Context $context The context.
1614
	 */
1615
	$html = apply_filters( 'gravityview/field_output/html', $html, $args, $context );
1616
1617
	/** @since 2.0.8 Remove unused atts */
1618
	$html = str_replace( array( ' style=""', ' class=""', ' id=""' ), '', $html );
1619
1620
	return $html;
1621
}
1622