Completed
Push — develop ( 365b4b...6c202f )
by Zack
04:37
created

GravityView_frontend::get_search_criteria_paging()   B

Complexity

Conditions 5
Paths 12

Size

Total Lines 32
Code Lines 15

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 5
eloc 15
nc 12
nop 1
dl 0
loc 32
rs 8.439
c 0
b 0
f 0
1
<?php
0 ignored issues
show
Coding Style Compatibility introduced by
For compatibility and reusability of your code, PSR1 recommends that a file should introduce either new symbols (like classes, functions, etc.) or have side-effects (like outputting something, or including other files), but not both at the same time. The first symbol is defined on line 15 and the first side effect is on line 1631.

The PSR-1: Basic Coding Standard recommends that a file should either introduce new symbols, that is classes, functions, constants or similar, or have side effects. Side effects are anything that executes logic, like for example printing output, changing ini settings or writing to a file.

The idea behind this recommendation is that merely auto-loading a class should not change the state of an application. It also promotes a cleaner style of programming and makes your code less prone to errors, because the logic is not spread out all over the place.

To learn more about the PSR-1, please see the PHP-FIG site on the PSR-1.

Loading history...
2
/**
3
 * GravityView Frontend functions
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
15
class GravityView_frontend {
0 ignored issues
show
Coding Style introduced by
Since you have declared the constructor as private, maybe you should also declare the class as final.
Loading history...
16
17
	/**
18
	 * Regex strings that are used to determine whether the current request is a GravityView search or not.
19
	 * @see GravityView_frontend::is_searching()
20
	 * @since 1.7.4.1
21
	 * @var array
22
	 */
23
	private static $search_parameters = array( 'gv_search', 'gv_start', 'gv_end', 'gv_id', 'gv_by', 'filter_*' );
24
25
	/**
26
	 * Is the currently viewed post a `gravityview` post type?
27
	 * @var boolean
28
	 */
29
	var $is_gravityview_post_type = false;
0 ignored issues
show
Coding Style introduced by
The visibility should be declared for property $is_gravityview_post_type.

The PSR-2 coding standard requires that all properties in a class have their visibility explicitly declared. If you declare a property using

class A {
    var $property;
}

the property is implicitly global.

To learn more about the PSR-2, please see the PHP-FIG site on the PSR-2.

Loading history...
30
31
	/**
32
	 * Does the current post have a `[gravityview]` shortcode?
33
	 * @var boolean
34
	 */
35
	var $post_has_shortcode = false;
0 ignored issues
show
Coding Style introduced by
The visibility should be declared for property $post_has_shortcode.

The PSR-2 coding standard requires that all properties in a class have their visibility explicitly declared. If you declare a property using

class A {
    var $property;
}

the property is implicitly global.

To learn more about the PSR-2, please see the PHP-FIG site on the PSR-2.

Loading history...
36
37
	/**
38
	 * The Post ID of the currently viewed post. Not necessarily GV
39
	 * @var int
40
	 */
41
	var $post_id = null;
0 ignored issues
show
Coding Style introduced by
The visibility should be declared for property $post_id.

The PSR-2 coding standard requires that all properties in a class have their visibility explicitly declared. If you declare a property using

class A {
    var $property;
}

the property is implicitly global.

To learn more about the PSR-2, please see the PHP-FIG site on the PSR-2.

Loading history...
42
43
	/**
44
	 * Are we currently viewing a single entry?
45
	 * If so, the int value of the entry ID. Otherwise, false.
46
	 * @var int|boolean
47
	 */
48
	var $single_entry = false;
0 ignored issues
show
Coding Style introduced by
The visibility should be declared for property $single_entry.

The PSR-2 coding standard requires that all properties in a class have their visibility explicitly declared. If you declare a property using

class A {
    var $property;
}

the property is implicitly global.

To learn more about the PSR-2, please see the PHP-FIG site on the PSR-2.

Loading history...
49
50
	/**
51
	 * If we are viewing a single entry, the entry data
52
	 * @var array|false
53
	 */
54
	var $entry = false;
0 ignored issues
show
Coding Style introduced by
The visibility should be declared for property $entry.

The PSR-2 coding standard requires that all properties in a class have their visibility explicitly declared. If you declare a property using

class A {
    var $property;
}

the property is implicitly global.

To learn more about the PSR-2, please see the PHP-FIG site on the PSR-2.

Loading history...
55
56
	/**
57
	 * When displaying the single entry we should always know to which View it belongs (the context is everything!)
58
	 * @var null
59
	 */
60
	var $context_view_id = null;
0 ignored issues
show
Coding Style introduced by
The visibility should be declared for property $context_view_id.

The PSR-2 coding standard requires that all properties in a class have their visibility explicitly declared. If you declare a property using

class A {
    var $property;
}

the property is implicitly global.

To learn more about the PSR-2, please see the PHP-FIG site on the PSR-2.

Loading history...
61
62
	/**
63
	 * The View is showing search results
64
	 * @since 1.5.4
65
	 * @var boolean
66
	 */
67
	var $is_search = false;
0 ignored issues
show
Coding Style introduced by
The visibility should be declared for property $is_search.

The PSR-2 coding standard requires that all properties in a class have their visibility explicitly declared. If you declare a property using

class A {
    var $property;
}

the property is implicitly global.

To learn more about the PSR-2, please see the PHP-FIG site on the PSR-2.

Loading history...
68
69
	/**
70
	 * The view data parsed from the $post
71
	 *
72
	 * @see  GravityView_View_Data::__construct()
73
	 * @var GravityView_View_Data
74
	 */
75
	var $gv_output_data = null;
0 ignored issues
show
Coding Style introduced by
The visibility should be declared for property $gv_output_data.

The PSR-2 coding standard requires that all properties in a class have their visibility explicitly declared. If you declare a property using

class A {
    var $property;
}

the property is implicitly global.

To learn more about the PSR-2, please see the PHP-FIG site on the PSR-2.

Loading history...
76
77
	/**
78
	 * @var GravityView_frontend
79
	 */
80
	static $instance;
0 ignored issues
show
Coding Style introduced by
The visibility should be declared for property $instance.

The PSR-2 coding standard requires that all properties in a class have their visibility explicitly declared. If you declare a property using

class A {
    var $property;
}

the property is implicitly global.

To learn more about the PSR-2, please see the PHP-FIG site on the PSR-2.

Loading history...
81
82
	/**
83
	 * Class constructor, enforce Singleton pattern
84
	 */
85
	private function __construct() {}
86
87
	private function initialize() {
88
		add_action( 'wp', array( $this, 'parse_content'), 11 );
0 ignored issues
show
introduced by
No space before closing parenthesis of array is bad style
Loading history...
89
		add_filter( 'parse_query', array( $this, 'parse_query_fix_frontpage' ), 10 );
90
		add_action( 'template_redirect', array( $this, 'set_entry_data'), 1 );
0 ignored issues
show
introduced by
No space before closing parenthesis of array is bad style
Loading history...
91
92
		// Enqueue scripts and styles after GravityView_Template::register_styles()
93
		add_action( 'wp_enqueue_scripts', array( $this, 'add_scripts_and_styles' ), 20 );
94
95
		// Enqueue and print styles in the footer. Added 1 priorty so stuff gets printed at 10 priority.
96
		add_action( 'wp_print_footer_scripts', array( $this, 'add_scripts_and_styles' ), 1 );
97
98
		add_filter( 'the_title', array( $this, 'single_entry_title' ), 1, 2 );
99
		add_filter( 'the_content', array( $this, 'insert_view_in_content' ) );
100
		add_filter( 'comments_open', array( $this, 'comments_open' ), 10, 2 );
101
102
		add_action( 'gravityview_after', array( $this, 'context_not_configured_warning' ) );
103
	}
104
105
	/**
106
	 * Get the one true instantiated self
107
	 * @return GravityView_frontend
108
	 */
109
	public static function getInstance() {
0 ignored issues
show
Coding Style introduced by
The function name getInstance is in camel caps, but expected get_instance instead as per the coding standard.
Loading history...
110
111
		if ( empty( self::$instance ) ) {
112
			self::$instance = new self;
113
			self::$instance->initialize();
114
		}
115
116
		return self::$instance;
117
	}
118
119
	/**
120
	 * @return GravityView_View_Data
121
	 */
122
	public function getGvOutputData() {
0 ignored issues
show
Coding Style introduced by
The function name getGvOutputData is in camel caps, but expected get_gv_output_data instead as per the coding standard.
Loading history...
123
		return $this->gv_output_data;
124
	}
125
126
	/**
127
	 * @param GravityView_View_Data $gv_output_data
128
	 */
129
	public function setGvOutputData( $gv_output_data ) {
0 ignored issues
show
Coding Style introduced by
The function name setGvOutputData is in camel caps, but expected set_gv_output_data instead as per the coding standard.
Loading history...
130
		$this->gv_output_data = $gv_output_data;
131
	}
132
133
	/**
134
	 * @return boolean
135
	 */
136
	public function isSearch() {
0 ignored issues
show
Coding Style introduced by
The function name isSearch is in camel caps, but expected is_search instead as per the coding standard.
Loading history...
137
		return $this->is_search;
138
	}
139
140
	/**
141
	 * @param boolean $is_search
142
	 */
143
	public function setIsSearch( $is_search ) {
0 ignored issues
show
Coding Style introduced by
The function name setIsSearch is in camel caps, but expected set_is_search instead as per the coding standard.
Loading history...
144
		$this->is_search = $is_search;
145
	}
146
147
	/**
148
	 * @return bool|int
149
	 */
150
	public function getSingleEntry() {
0 ignored issues
show
Coding Style introduced by
The function name getSingleEntry is in camel caps, but expected get_single_entry instead as per the coding standard.
Loading history...
151
		return $this->single_entry;
152
	}
153
154
	/**
155
	 * Sets the single entry ID and also the entry
156
	 * @param bool|int|string $single_entry
157
	 */
158
	public function setSingleEntry( $single_entry ) {
0 ignored issues
show
Coding Style introduced by
The function name setSingleEntry is in camel caps, but expected set_single_entry instead as per the coding standard.
Loading history...
159
160
		$this->single_entry = $single_entry;
161
162
	}
163
164
	/**
165
	 * @return array
166
	 */
167
	public function getEntry() {
0 ignored issues
show
Coding Style introduced by
The function name getEntry is in camel caps, but expected get_entry instead as per the coding standard.
Loading history...
168
		return $this->entry;
169
	}
170
171
	/**
172
	 * Set the current entry
173
	 * @param array|int $entry Entry array or entry slug or ID
174
	 */
175
	public function setEntry( $entry ) {
0 ignored issues
show
Coding Style introduced by
The function name setEntry is in camel caps, but expected set_entry instead as per the coding standard.
Loading history...
176
177
		if ( ! is_array( $entry ) ) {
178
			$entry = GVCommon::get_entry( $entry );
179
		}
180
181
		$this->entry = $entry;
182
	}
183
184
	/**
185
	 * @return int
186
	 */
187
	public function getPostId() {
0 ignored issues
show
Coding Style introduced by
The function name getPostId is in camel caps, but expected get_post_id instead as per the coding standard.
Loading history...
188
		return $this->post_id;
189
	}
190
191
	/**
192
	 * @param int $post_id
193
	 */
194
	public function setPostId( $post_id ) {
0 ignored issues
show
Coding Style introduced by
The function name setPostId is in camel caps, but expected set_post_id instead as per the coding standard.
Loading history...
195
		$this->post_id = $post_id;
196
	}
197
198
	/**
199
	 * @return boolean
200
	 */
201
	public function isPostHasShortcode() {
0 ignored issues
show
Coding Style introduced by
The function name isPostHasShortcode is in camel caps, but expected is_post_has_shortcode instead as per the coding standard.
Loading history...
202
		return $this->post_has_shortcode;
203
	}
204
205
	/**
206
	 * @param boolean $post_has_shortcode
207
	 */
208
	public function setPostHasShortcode( $post_has_shortcode ) {
0 ignored issues
show
Coding Style introduced by
The function name setPostHasShortcode is in camel caps, but expected set_post_has_shortcode instead as per the coding standard.
Loading history...
209
		$this->post_has_shortcode = $post_has_shortcode;
210
	}
211
212
	/**
213
	 * @return boolean
214
	 */
215
	public function isGravityviewPostType() {
0 ignored issues
show
Coding Style introduced by
The function name isGravityviewPostType is in camel caps, but expected is_gravityview_post_type instead as per the coding standard.
Loading history...
216
		return $this->is_gravityview_post_type;
217
	}
218
219
	/**
220
	 * @param boolean $is_gravityview_post_type
221
	 */
222
	public function setIsGravityviewPostType( $is_gravityview_post_type ) {
0 ignored issues
show
Coding Style introduced by
The function name setIsGravityviewPostType is in camel caps, but expected set_is_gravityview_post_type instead as per the coding standard.
Loading history...
223
		$this->is_gravityview_post_type = $is_gravityview_post_type;
224
	}
225
226
	/**
227
	 * Set the context view ID used when page contains multiple embedded views or displaying the single entry view
228
	 *
229
	 *
230
	 *
231
	 * @param null $view_id
232
	 */
233
	public function set_context_view_id( $view_id = null ) {
234
235
		if ( ! empty( $view_id ) ) {
236
237
			$this->context_view_id = $view_id;
238
239
		} elseif ( isset( $_GET['gvid'] ) && $this->getGvOutputData()->has_multiple_views() ) {
240
			/**
241
			 * used on a has_multiple_views context
242
			 * @see GravityView_API::entry_link
243
			 * @see GravityView_View_Data::getInstance()->has_multiple_views()
244
			 */
245
			$this->context_view_id = $_GET['gvid'];
0 ignored issues
show
introduced by
Detected access of super global var $_GET, probably need manual inspection.
Loading history...
introduced by
Detected usage of a non-sanitized input variable: $_GET
Loading history...
246
247
		} elseif ( ! $this->getGvOutputData()->has_multiple_views() )  {
248
			$array_keys = array_keys( $this->getGvOutputData()->get_views() );
249
			$this->context_view_id = array_pop( $array_keys );
250
			unset( $array_keys );
251
		}
252
253
	}
254
255
	/**
256
	 * Returns the the view_id context when page contains multiple embedded views or displaying single entry view
257
	 *
258
	 * @since 1.5.4
259
	 *
260
	 * @return string
261
	 */
262
	public function get_context_view_id() {
263
		return $this->context_view_id;
264
	}
265
266
	/**
267
	 * Allow GravityView entry endpoints on the front page of a site
268
	 *
269
	 * @link  https://core.trac.wordpress.org/ticket/23867 Fixes this core issue
270
	 * @link https://wordpress.org/plugins/cpt-on-front-page/ Code is based on this
271
	 *
272
	 * @since 1.17.3
273
	 *
274
	 * @param WP_Query &$query (passed by reference)
275
	 *
276
	 * @return void
277
	 */
278
	public function parse_query_fix_frontpage( &$query ) {
279
		global $wp_rewrite;
0 ignored issues
show
Compatibility Best Practice introduced by
Use of global functionality is not recommended; it makes your code harder to test, and less reusable.

Instead of relying on global state, we recommend one of these alternatives:

1. Pass all data via parameters

function myFunction($a, $b) {
    // Do something
}

2. Create a class that maintains your state

class MyClass {
    private $a;
    private $b;

    public function __construct($a, $b) {
        $this->a = $a;
        $this->b = $b;
    }

    public function myFunction() {
        // Do something
    }
}
Loading history...
280
281
		$is_front_page = ( $query->is_home || $query->is_page );
282
		$show_on_front = ( 'page' === get_option('show_on_front') );
0 ignored issues
show
Coding Style introduced by
Expected 1 spaces after opening bracket; 0 found
Loading history...
Coding Style introduced by
Expected 1 spaces before closing bracket; 0 found
Loading history...
283
		$front_page_id = get_option('page_on_front');
0 ignored issues
show
Coding Style introduced by
Expected 1 spaces after opening bracket; 0 found
Loading history...
Coding Style introduced by
Expected 1 spaces before closing bracket; 0 found
Loading history...
284
285
		if (  $is_front_page && $show_on_front && $front_page_id ) {
286
287
			// Force to be an array, potentially a query string ( entry=16 )
288
			$_query = wp_parse_args( $query->query );
289
290
			// pagename can be set and empty depending on matched rewrite rules. Ignore an empty pagename.
291
			if ( isset( $_query['pagename'] ) && '' === $_query['pagename'] ) {
292
				unset( $_query['pagename'] );
293
			}
294
295
			// this is where will break from core wordpress
296
			$ignore = array( 'preview', 'page', 'paged', 'cpage' );
297
			$endpoints = rgobj( $wp_rewrite, 'endpoints' );
298
			foreach ( (array) $endpoints as $endpoint ) {
299
				$ignore[] = $endpoint[1];
300
			}
301
			unset( $endpoints );
302
303
			// Modify the query if:
304
			// - We're on the "Page on front" page (which we are), and:
305
			// - The query is empty OR
306
			// - The query includes keys that are associated with registered endpoints. `entry`, for example.
307
			if ( empty( $_query ) || ! array_diff( array_keys( $_query ), $ignore ) ) {
308
309
				$qv =& $query->query_vars;
310
311
				// Prevent redirect when on the single entry endpoint
312
				if( self::is_single_entry() ) {
313
					add_filter( 'redirect_canonical', '__return_false' );
314
				}
315
316
				$query->is_page = true;
317
				$query->is_home = false;
318
				$qv['page_id']  = $front_page_id;
319
320
				// Correct <!--nextpage--> for page_on_front
321
				if ( ! empty( $qv['paged'] ) ) {
322
					$qv['page'] = $qv['paged'];
323
					unset( $qv['paged'] );
324
				}
325
			}
326
327
			// reset the is_singular flag after our updated code above
328
			$query->is_singular = $query->is_single || $query->is_page || $query->is_attachment;
329
		}
330
	}
331
332
	/**
333
	 * Read the $post and process the View data inside
334
	 * @param  array  $wp Passed in the `wp` hook. Not used.
335
	 * @return void
336
	 */
337
	public function parse_content( $wp = array() ) {
0 ignored issues
show
Unused Code introduced by
The parameter $wp 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...
338
		global $post;
0 ignored issues
show
Compatibility Best Practice introduced by
Use of global functionality is not recommended; it makes your code harder to test, and less reusable.

Instead of relying on global state, we recommend one of these alternatives:

1. Pass all data via parameters

function myFunction($a, $b) {
    // Do something
}

2. Create a class that maintains your state

class MyClass {
    private $a;
    private $b;

    public function __construct($a, $b) {
        $this->a = $a;
        $this->b = $b;
    }

    public function myFunction() {
        // Do something
    }
}
Loading history...
339
340
		// If in admin and NOT AJAX request, get outta here.
341
		if ( GravityView_Plugin::is_admin() )  {
342
			return;
343
		}
344
345
		// Calculate requested Views
346
		$this->setGvOutputData( GravityView_View_Data::getInstance( $post ) );
347
348
		// !important: we need to run this before getting single entry (to kick the advanced filter)
349
		$this->set_context_view_id();
350
351
		$this->setIsGravityviewPostType( get_post_type( $post ) === 'gravityview' );
352
353
		$post_id = $this->getPostId() ? $this->getPostId() : (isset( $post ) ? $post->ID : null );
354
		$this->setPostId( $post_id );
355
		$post_has_shortcode = ! empty( $post->post_content ) ? gravityview_has_shortcode_r( $post->post_content, 'gravityview' ) : false;
356
		$this->setPostHasShortcode( $this->isGravityviewPostType() ? null : ! empty( $post_has_shortcode ) );
357
358
		// check if the View is showing search results (only for multiple entries View)
359
		$this->setIsSearch( $this->is_searching() );
360
361
		unset( $entry, $post_id, $post_has_shortcode );
362
	}
363
364
	/**
365
	 * Set the entry
366
	 */
367
	function set_entry_data() {
0 ignored issues
show
Best Practice introduced by
It is generally recommended to explicitly declare the visibility for methods.

Adding explicit visibility (private, protected, or public) is generally recommend to communicate to other developers how, and from where this method is intended to be used.

Loading history...
368
		$entry_id = self::is_single_entry();
369
		$this->setSingleEntry( $entry_id );
370
		$this->setEntry( $entry_id );
371
	}
372
373
	/**
374
	 * Checks if the current View is presenting search results
375
	 *
376
	 * @since 1.5.4
377
	 *
378
	 * @return boolean True: Yes, it's a search; False: No, not a search.
379
	 */
380
	function is_searching() {
0 ignored issues
show
Best Practice introduced by
It is generally recommended to explicitly declare the visibility for methods.

Adding explicit visibility (private, protected, or public) is generally recommend to communicate to other developers how, and from where this method is intended to be used.

Loading history...
381
382
		// It's a single entry, not search
383
		if ( $this->getSingleEntry() ) {
384
			return false;
385
		}
386
387
		$search_method = GravityView_Widget_Search::getInstance()->get_search_method();
388
389
		if( 'post' === $search_method ) {
390
			$get = $_POST;
0 ignored issues
show
introduced by
Detected access of super global var $_POST, probably need manual inspection.
Loading history...
introduced by
Detected usage of a non-sanitized input variable: $_POST
Loading history...
391
		} else {
392
			$get = $_GET;
0 ignored issues
show
introduced by
Detected access of super global var $_GET, probably need manual inspection.
Loading history...
introduced by
Detected usage of a non-sanitized input variable: $_GET
Loading history...
393
		}
394
395
		// No $_GET parameters
396
		if ( empty( $get ) || ! is_array( $get ) ) {
397
			return false;
398
		}
399
400
		// Remove empty values
401
		$get = array_filter( $get );
402
403
		// If the $_GET parameters are empty, it's no search.
404
		if ( empty( $get ) ) {
405
			return false;
406
		}
407
408
		$search_keys = array_keys( $get );
409
410
		$search_match = implode( '|', self::$search_parameters );
411
412
		foreach ( $search_keys as $search_key ) {
413
414
			// Analyze the search key $_GET parameter and see if it matches known GV args
415
			if ( preg_match( '/(' . $search_match . ')/i', $search_key ) ) {
416
				return true;
417
			}
418
		}
419
420
		return false;
421
	}
422
423
	/**
424
	 * Filter the title for the single entry view
425
	 *
426
	 * @param  string $title   current title
427
	 * @param  int $passed_post_id Post ID
428
	 * @return string          (modified) title
429
	 */
430
	public function single_entry_title( $title, $passed_post_id = null ) {
431
		global $post;
0 ignored issues
show
Compatibility Best Practice introduced by
Use of global functionality is not recommended; it makes your code harder to test, and less reusable.

Instead of relying on global state, we recommend one of these alternatives:

1. Pass all data via parameters

function myFunction($a, $b) {
    // Do something
}

2. Create a class that maintains your state

class MyClass {
    private $a;
    private $b;

    public function __construct($a, $b) {
        $this->a = $a;
        $this->b = $b;
    }

    public function myFunction() {
        // Do something
    }
}
Loading history...
432
433
		// If this is the directory view, return.
434
		if ( ! $this->getSingleEntry() ) {
435
			return $title;
436
		}
437
438
		$entry = $this->getEntry();
439
440
		/**
441
		 * @filter `gravityview/single/title/out_loop` Apply the Single Entry Title filter outside the WordPress loop?
442
		 * @param boolean $in_the_loop Whether to apply the filter to the menu title and the meta tag <title> - outside the loop
443
		 * @param array $entry Current entry
444
		 */
445
		$apply_outside_loop = apply_filters( 'gravityview/single/title/out_loop' , in_the_loop(), $entry );
446
447
		if ( ! $apply_outside_loop ) {
448
			return $title;
449
		}
450
451
		// User reported WooCommerce doesn't pass two args.
452
		if ( empty( $passed_post_id ) )  {
453
			return $title;
454
		}
455
456
		// Don't modify the title for anything other than the current view/post.
457
		// This is true for embedded shortcodes and Views.
458
		if ( is_object( $post ) && (int) $post->ID !== (int) $passed_post_id ) {
459
			return $title;
460
		}
461
462
		$context_view_id = $this->get_context_view_id();
463
464
		if ( $this->getGvOutputData()->has_multiple_views() && ! empty( $context_view_id ) ) {
465
			$view_meta = $this->getGvOutputData()->get_view( $context_view_id );
466
		} else {
467
			foreach ( $this->getGvOutputData()->get_views() as $view_id => $view_data ) {
468
				if ( intval( $view_data['form_id'] ) === intval( $entry['form_id'] ) ) {
469
					$view_meta = $view_data;
470
					break;
471
				}
472
			}
473
		}
474
475
		if ( ! empty( $view_meta['atts']['single_title'] ) ) {
476
477
			$title = $view_meta['atts']['single_title'];
478
479
			// We are allowing HTML in the fields, so no escaping the output
480
			$title = GravityView_API::replace_variables( $title, $view_meta['form'], $entry );
481
482
			$title = do_shortcode( $title );
483
		}
484
485
		return $title;
486
	}
487
488
489
	/**
490
	 * In case View post is called directly, insert the view in the post content
491
	 *
492
	 * @access public
493
	 * @static
494
	 * @param mixed $content
495
	 * @return string Add the View output into View CPT content
496
	 */
497
	public function insert_view_in_content( $content ) {
498
499
		// Plugins may run through the content in the header. WP SEO does this for its OpenGraph functionality.
500
		if ( ! did_action( 'loop_start' ) ) {
501
502
			do_action( 'gravityview_log_debug', '[insert_view_in_content] Not processing yet: loop_start hasn\'t run yet. Current action:', current_filter() );
503
504
			return $content;
505
		}
506
507
		//	We don't want this filter to run infinite loop on any post content fields
508
		remove_filter( 'the_content', array( $this, 'insert_view_in_content' ) );
509
510
		// Otherwise, this is called on the Views page when in Excerpt mode.
511
		if ( is_admin() ) {
512
			return $content;
513
		}
514
515
		// Only render in the loop. Fixes issues with the_content filter being applied in places like the sidebar
516
		if( ! in_the_loop() ) {
517
			return $content;
518
		}
519
520
		if ( $this->isGravityviewPostType() ) {
521
522
			/** @since 1.7.4 */
523
			if ( is_preview() && ! gravityview_get_form_id( $this->post_id ) ) {
524
				$content .= __( 'When using a Start Fresh template, you must save the View before a Preview is available.', 'gravityview' );
525
			} else {
526
				foreach ( $this->getGvOutputData()->get_views() as $view_id => $data ) {
527
					$content .= $this->render_view( array( 'id' => $view_id ) );
528
				}
529
			}
530
		}
531
532
		//	Add the filter back in
533
		add_filter( 'the_content', array( $this, 'insert_view_in_content' ) );
534
535
		return $content;
536
	}
537
538
	/**
539
	 * Disable comments on GravityView post types
540
	 * @param  boolean $open    existing status
541
	 * @param  int $post_id Post ID
542
	 * @return boolean
543
	 */
544
	public function comments_open( $open, $post_id ) {
545
546
		if ( $this->isGravityviewPostType() ) {
547
			$open = false;
548
		}
549
550
		/**
551
		 * @filter `gravityview/comments_open` Whether to set comments to open or closed.
552
		 * @since  1.5.4
553
		 * @param  boolean $open Open or closed status
554
		 * @param  int $post_id Post ID to set comment status for
555
		 */
556
		$open = apply_filters( 'gravityview/comments_open', $open, $post_id );
557
558
		return $open;
559
	}
560
561
	/**
562
	 * Display a warning when a View has not been configured
563
	 *
564
	 * @since 1.19.2
565
	 *
566
	 * @param int $view_id The ID of the View currently being displayed
567
	 *
568
	 * @return void
569
	 */
570
	public function context_not_configured_warning( $view_id = 0 ) {
571
572
		if ( ! class_exists( 'GravityView_View' ) ) {
573
			return;
574
		}
575
576
		$fields = GravityView_View::getInstance()->getContextFields();
577
578
		if ( ! empty( $fields ) ) {
579
			return;
580
		}
581
582
		$context = GravityView_View::getInstance()->getContext();
583
584
		switch( $context ) {
585
			case 'directory':
586
				$tab = __( 'Multiple Entries', 'gravityview' );
587
				break;
588
			case 'edit':
589
				$tab = __( 'Edit Entry', 'gravityview' );
590
				break;
591
			case 'single':
592
			default:
593
				$tab = __( 'Single Entry', 'gravityview' );
594
				break;
595
		}
596
0 ignored issues
show
Coding Style introduced by
Functions must not contain multiple empty lines in a row; found 2 empty lines
Loading history...
597
598
		$title = sprintf( esc_html_x('The %s layout has not been configured.', 'Displayed when a View is not configured. %s is replaced by the tab label', 'gravityview' ), $tab );
0 ignored issues
show
Coding Style introduced by
Expected 1 spaces after opening bracket; 0 found
Loading history...
599
		$edit_link = admin_url( sprintf( 'post.php?post=%d&action=edit#%s-view', $view_id, $context ) );
600
		$action_text = sprintf( esc_html__('Add fields to %s', 'gravityview' ), $tab );
0 ignored issues
show
Coding Style introduced by
Expected 1 spaces after opening bracket; 0 found
Loading history...
601
		$message = esc_html__( 'You can only see this message because you are able to edit this View.', 'gravityview' );
602
603
		$output = sprintf( '<h3>%s <strong><a href="%s">%s</a></strong></h3><p>%s</p>', $title, esc_url( $edit_link ), $action_text, $message );
604
605
		echo GVCommon::generate_notice( $output, 'gv-error error', 'edit_gravityview', $view_id );
0 ignored issues
show
introduced by
Expected a sanitizing function (see Codex for 'Data Validation'), but instead saw 'GVCommon'
Loading history...
606
	}
607
608
609
	/**
610
	 * Core function to render a View based on a set of arguments
611
	 *
612
	 * @access public
613
	 * @static
614
	 * @param array $passed_args {
615
	 *
616
	 *      Settings for rendering the View
617
	 *
618
	 *      @type int $id View id
619
	 *      @type int $page_size Number of entries to show per page
620
	 *      @type string $sort_field Form field id to sort
621
	 *      @type string $sort_direction Sorting direction ('ASC' or 'DESC')
622
	 *      @type string $start_date - Ymd
623
	 *      @type string $end_date - Ymd
624
	 *      @type string $class - assign a html class to the view
625
	 *      @type string $offset (optional) - This is the start point in the current data set (0 index based).
626
	 * }
627
	 *
628
	 * @return string|null HTML output of a View, NULL if View isn't found
629
	 */
630
	public function render_view( $passed_args ) {
631
632
		// validate attributes
633
		if ( empty( $passed_args['id'] ) ) {
634
			do_action( 'gravityview_log_error', '[render_view] Returning; no ID defined.', $passed_args );
635
			return null;
636
		}
637
638
		// Solve problem when loading content via admin-ajax.php
639
		// @hack
640
		if ( ! $this->getGvOutputData() ) {
641
642
			do_action( 'gravityview_log_error', '[render_view] gv_output_data not defined; parsing content.', $passed_args );
643
644
			$this->parse_content();
645
		}
646
647
		// Make 100% sure that we're dealing with a properly called situation
648
		if ( ! is_object( $this->getGvOutputData() ) || ! is_callable( array( $this->getGvOutputData(), 'get_view' ) ) ) {
649
650
			do_action( 'gravityview_log_error', '[render_view] gv_output_data not an object or get_view not callable.', $this->getGvOutputData() );
651
652
			return null;
653
		}
654
655
		$view_id = $passed_args['id'];
656
657
		$view_data = $this->getGvOutputData()->get_view( $view_id, $passed_args );
658
659
		do_action( 'gravityview_log_debug', '[render_view] View Data: ', $view_data );
660
661
		do_action( 'gravityview_log_debug', '[render_view] Init View. Arguments: ', $passed_args );
662
663
		// The passed args were always winning, even if they were NULL.
664
		// This prevents that. Filters NULL, FALSE, and empty strings.
665
		$passed_args = array_filter( $passed_args, 'strlen' );
666
667
		//Override shortcode args over View template settings
668
		$atts = wp_parse_args( $passed_args, $view_data['atts'] );
669
670
		do_action( 'gravityview_log_debug', '[render_view] Arguments after merging with View settings: ', $atts );
671
672
		// It's password protected and you need to log in.
673
		if ( post_password_required( $view_id ) ) {
674
675
			do_action( 'gravityview_log_error', sprintf( '[render_view] Returning: View %d is password protected.', $view_id ) );
676
677
			// If we're in an embed or on an archive page, show the password form
678
			if ( get_the_ID() !== $view_id ) {
679
				return get_the_password_form();
680
			}
681
682
			// Otherwise, just get outta here
683
			return null;
684
		}
685
686
		/**
687
		 * Don't render View if user isn't allowed to see it
688
		 * @since 1.15
689
		 * @since 1.17.2 Added check for if a user has no caps but is logged in (member of multisite, but not any site). Treat as if logged-out.
690
		 */
691
		if( is_user_logged_in() && ! ( empty( wp_get_current_user()->caps ) && empty( wp_get_current_user()->roles ) ) && false === GVCommon::has_cap( 'read_gravityview', $view_id ) ) {
692
693
			do_action( 'gravityview_log_debug', sprintf( '%s Returning: View %d is not visible by current user.', __METHOD__, $view_id ) );
694
695
			return null;
696
		}
697
698
		if( $this->isGravityviewPostType() ) {
699
700
			/**
701
			 * @filter `gravityview_direct_access` Should Views be directly accessible, or only visible using the shortcode?
702
			 * @see https://codex.wordpress.org/Function_Reference/register_post_type#public
703
			 * @see \GV\Entry::get_endpoint_name
704
			 * @since 1.15.2
705
			 * @param[in,out] boolean `true`: allow Views to be accessible directly. `false`: Only allow Views to be embedded via shortcode. Default: `true`
706
			 * @param int $view_id The ID of the View currently being requested. `0` for general setting
707
			 */
708
			$direct_access = apply_filters( 'gravityview_direct_access', true, $view_id );
709
710
			$embed_only = ! empty( $atts['embed_only'] );
711
712
			if( ! $direct_access || ( $embed_only && ! GVCommon::has_cap( 'read_private_gravityviews' ) ) ) {
713
				return __( 'You are not allowed to view this content.', 'gravityview' );
714
			}
715
		}
716
717
		ob_start();
718
719
		/**
720
		 * Set globals for templating
721
		 * @deprecated 1.6.2
722
		 */
723
		global $gravityview_view;
0 ignored issues
show
Compatibility Best Practice introduced by
Use of global functionality is not recommended; it makes your code harder to test, and less reusable.

Instead of relying on global state, we recommend one of these alternatives:

1. Pass all data via parameters

function myFunction($a, $b) {
    // Do something
}

2. Create a class that maintains your state

class MyClass {
    private $a;
    private $b;

    public function __construct($a, $b) {
        $this->a = $a;
        $this->b = $b;
    }

    public function myFunction() {
        // Do something
    }
}
Loading history...
724
725
		$gravityview_view = new GravityView_View( $view_data );
726
727
		$post_id = ! empty( $atts['post_id'] ) ? intval( $atts['post_id'] ) : $this->getPostId();
728
729
		$gravityview_view->setPostId( $post_id );
730
731
		if ( ! $this->getSingleEntry() ) {
732
733
			// user requested Directory View
734
			do_action( 'gravityview_log_debug', '[render_view] Executing Directory View' );
735
736
			//fetch template and slug
737
			$view_slug = apply_filters( 'gravityview_template_slug_'. $view_data['template_id'], 'table', 'directory' );
738
739
			do_action( 'gravityview_log_debug', '[render_view] View template slug: ', $view_slug );
740
741
			/**
742
			 * Disable fetching initial entries for views that don't need it (DataTables)
743
			 */
744
			$get_entries = apply_filters( 'gravityview_get_view_entries_'.$view_slug, true );
745
746
			/**
747
			 * Hide View data until search is performed
748
			 * @since 1.5.4
749
			 */
750
			if ( ! empty( $atts['hide_until_searched'] ) && ! $this->isSearch() ) {
751
				$gravityview_view->setHideUntilSearched( true );
752
				$get_entries = false;
753
			}
754
0 ignored issues
show
Coding Style introduced by
Functions must not contain multiple empty lines in a row; found 2 empty lines
Loading history...
755
756
			if ( $get_entries ) {
757
758
				if ( ! empty( $atts['sort_columns'] ) ) {
759
					// add filter to enable column sorting
760
					add_filter( 'gravityview/template/field_label', array( $this, 'add_columns_sort_links' ) , 100, 3 );
761
				}
762
763
				$view_entries = self::get_view_entries( $atts, $view_data['form_id'] );
764
765
				do_action( 'gravityview_log_debug', sprintf( '[render_view] Get Entries. Found %s entries total, showing %d entries', $view_entries['count'], sizeof( $view_entries['entries'] ) ) );
766
767
			} else {
768
769
				$view_entries = array( 'count' => null, 'entries' => null, 'paging' => null );
770
771
				do_action( 'gravityview_log_debug', '[render_view] Not fetching entries because `gravityview_get_view_entries_'.$view_slug.'` is false' );
772
			}
773
774
			$gravityview_view->setPaging( $view_entries['paging'] );
775
			$gravityview_view->setContext( 'directory' );
776
			$sections = array( 'header', 'body', 'footer' );
777
778
		} else {
779
780
			// user requested Single Entry View
781
			do_action( 'gravityview_log_debug', '[render_view] Executing Single View' );
782
0 ignored issues
show
Coding Style introduced by
Functions must not contain multiple empty lines in a row; found 2 empty lines
Loading history...
783
784
			/**
785
			 * @action `gravityview_render_entry_{View ID}` Before rendering a single entry for a specific View ID
786
			 * @since 1.17
787
			 */
788
			do_action( 'gravityview_render_entry_'.$view_data['id'] );
789
790
			$entry = $this->getEntry();
791
792
			// You are not permitted to view this entry.
793
			if ( empty( $entry ) || ! self::is_entry_approved( $entry, $atts ) ) {
794
795
				do_action( 'gravityview_log_debug', '[render_view] Entry does not exist. This may be because of View filters limiting access.' );
796
797
				// Only display warning once when multiple Views are embedded
798
				if( $view_id !== (int) GravityView_frontend::get_context_view_id() ) {
799
					return null;
800
				}
801
802
				/**
803
				 * @filter `gravityview/render/entry/not_visible` Modify the message shown to users when the entry doesn't exist or they aren't allowed to view it.
804
				 * @since 1.6
805
				 * @param string $message Default: "You have attempted to view an entry that is not visible or may not exist."
806
				 */
807
				$message = apply_filters( 'gravityview/render/entry/not_visible', __( 'You have attempted to view an entry that is not visible or may not exist.', 'gravityview' ) );
808
809
				/**
810
				 * @since 1.6
811
				 */
812
				echo esc_attr( $message );
813
814
				return null;
815
			}
816
817
			// We're in single view, but the view being processed is not the same view the single entry belongs to.
818
			// important: do not remove this as it prevents fake attempts of displaying entries from other views/forms
819
			if ( $this->getGvOutputData()->has_multiple_views() && $view_id != $this->get_context_view_id() ) {
820
				do_action( 'gravityview_log_debug', '[render_view] In single entry view, but the entry does not belong to this View. Perhaps there are multiple views on the page. View ID: '. $view_id );
821
				return null;
822
			}
823
824
			//fetch template and slug
825
			$view_slug = apply_filters( 'gravityview_template_slug_' . $view_data['template_id'], 'table', 'single' );
826
			do_action( 'gravityview_log_debug', '[render_view] View single template slug: ', $view_slug );
827
828
			//fetch entry detail
829
			$view_entries['count'] = 1;
0 ignored issues
show
Coding Style Comprehensibility introduced by
$view_entries was never initialized. Although not strictly required by PHP, it is generally a good practice to add $view_entries = 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...
830
			$view_entries['entries'][] = $entry;
831
			do_action( 'gravityview_log_debug', '[render_view] Get single entry: ', $view_entries['entries'] );
832
833
			$back_link_label = isset( $atts['back_link_label'] ) ? $atts['back_link_label'] : null;
834
835
			// set back link label
836
			$gravityview_view->setBackLinkLabel( $back_link_label );
837
			$gravityview_view->setContext( 'single' );
838
			$sections = array( 'single' );
839
840
		}
841
842
		// add template style
843
		self::add_style( $view_data['template_id'] );
844
845
		// Prepare to render view and set vars
846
		$gravityview_view->setEntries( $view_entries['entries'] );
847
		$gravityview_view->setTotalEntries( $view_entries['count'] );
848
849
		// If Edit
850
		if ( 'edit' === gravityview_get_context() ) {
851
852
			do_action( 'gravityview_log_debug', '[render_view] Edit Entry ' );
853
854
			do_action( 'gravityview_edit_entry', $this->getGvOutputData() );
855
856
			return ob_get_clean();
857
858
		} else {
859
			// finaly we'll render some html
860
			$sections = apply_filters( 'gravityview_render_view_sections', $sections, $view_data['template_id'] );
861
862
			do_action( 'gravityview_log_debug', '[render_view] Sections to render: ', $sections );
863
			foreach ( $sections as $section ) {
864
				do_action( 'gravityview_log_debug', '[render_view] Rendering '. $section . ' section.' );
865
				$gravityview_view->render( $view_slug, $section, false );
866
			}
867
		}
868
869
		//@todo: check why we need the IF statement vs. print the view id always.
870
		if ( $this->isGravityviewPostType() || $this->isPostHasShortcode() ) {
871
			// Print the View ID to enable proper cookie pagination
872
			echo '<input type="hidden" class="gravityview-view-id" value="' . esc_attr( $view_id ) . '">';
873
		}
874
		$output = ob_get_clean();
875
876
		return $output;
877
	}
878
879
	/**
880
	 * Process the start and end dates for a view - overrides values defined in shortcode (if needed)
881
	 *
882
	 * The `start_date` and `end_date` keys need to be in a format processable by GFFormsModel::get_date_range_where(),
883
	 * which uses \DateTime() format.
884
	 *
885
	 * You can set the `start_date` or `end_date` to any value allowed by {@link http://www.php.net//manual/en/function.strtotime.php strtotime()},
886
	 * including strings like "now" or "-1 year" or "-3 days".
887
	 *
888
	 * @see GFFormsModel::get_date_range_where
889
	 *
890
	 * @param  array      $args            View settings
891
	 * @param  array      $search_criteria Search being performed, if any
892
	 * @return array                       Modified `$search_criteria` array
893
	 */
894
	public static function process_search_dates( $args, $search_criteria = array() ) {
895
896
		$return_search_criteria = $search_criteria;
897
898
		foreach ( array( 'start_date', 'end_date' ) as $key ) {
899
0 ignored issues
show
Coding Style introduced by
Functions must not contain multiple empty lines in a row; found 2 empty lines
Loading history...
900
901
			// Is the start date or end date set in the view or shortcode?
902
			// If so, we want to make sure that the search doesn't go outside the bounds defined.
903
			if ( ! empty( $args[ $key ] ) ) {
904
905
				// Get a timestamp and see if it's a valid date format
906
				$date = strtotime( $args[ $key ] );
907
908
				// The date was invalid
909
				if ( empty( $date ) ) {
910
					do_action( 'gravityview_log_error', __METHOD__ . ' Invalid ' . $key . ' date format: ' . $args[ $key ] );
911
					continue;
912
				}
913
914
				// The format that Gravity Forms expects for start_date and day-specific (not hour/second-specific) end_date
915
				$datetime_format = 'Y-m-d H:i:s';
916
				$search_is_outside_view_bounds = false;
917
918
				if( ! empty( $search_criteria[ $key ] ) ) {
919
920
					$search_date = strtotime( $search_criteria[ $key ] );
921
922
					// The search is for entries before the start date defined by the settings
923
					switch ( $key ) {
924
						case 'end_date':
925
							/**
926
							 * If the end date is formatted as 'Y-m-d', it should be formatted without hours and seconds
927
							 * so that Gravity Forms can convert the day to 23:59:59 the previous day.
928
							 *
929
							 * If it's a relative date ("now" or "-1 day"), then it should use the precise date format
930
							 *
931
							 * @see GFFormsModel::get_date_range_where
932
							 */
933
							$datetime_format               = gravityview_is_valid_datetime( $args[ $key ] ) ? 'Y-m-d' : 'Y-m-d H:i:s';
934
							$search_is_outside_view_bounds = ( $search_date > $date );
935
							break;
936
						case 'start_date':
937
							$search_is_outside_view_bounds = ( $search_date < $date );
938
							break;
939
					}
940
				}
941
942
				// If there is no search being performed, or if there is a search being performed that's outside the bounds
943
				if ( empty( $search_criteria[ $key ] ) || $search_is_outside_view_bounds ) {
944
945
					// Then we override the search and re-set the start date
946
					$return_search_criteria[ $key ] = date_i18n( $datetime_format , $date, true );
947
				}
948
			}
949
		}
950
951
		if( isset( $return_search_criteria['start_date'] ) && isset( $return_search_criteria['end_date'] ) ) {
952
			// The start date is AFTER the end date. This will result in no results, but let's not force the issue.
953
			if ( strtotime( $return_search_criteria['start_date'] ) > strtotime( $return_search_criteria['end_date'] ) ) {
954
				do_action( 'gravityview_log_error', __METHOD__ . ' Invalid search: the start date is after the end date.', $return_search_criteria );
955
			}
956
		}
957
958
		return $return_search_criteria;
959
	}
960
961
962
	/**
963
	 * Process the approved only search criteria according to the View settings
964
	 *
965
	 * @param  array      $args            View settings
966
	 * @param  array      $search_criteria Search being performed, if any
967
	 * @return array                       Modified `$search_criteria` array
968
	 */
969
	public static function process_search_only_approved( $args, $search_criteria ) {
970
971
		/** @since 1.19 */
972
		if( ! empty( $args['admin_show_all_statuses'] ) && GVCommon::has_cap('gravityview_moderate_entries') ) {
0 ignored issues
show
Coding Style introduced by
Expected 1 spaces after opening bracket; 0 found
Loading history...
Coding Style introduced by
Expected 1 spaces before closing bracket; 0 found
Loading history...
973
			do_action( 'gravityview_log_debug', __METHOD__ . ': User can moderate entries; showing all approval statuses' );
974
			return $search_criteria;
975
		}
976
977
		if ( ! empty( $args['show_only_approved'] ) ) {
978
979
			$search_criteria['field_filters'][] = array(
980
				'key' => GravityView_Entry_Approval::meta_key,
981
				'value' => GravityView_Entry_Approval_Status::APPROVED
0 ignored issues
show
introduced by
Each line in an array declaration must end in a comma
Loading history...
982
			);
983
984
			$search_criteria['field_filters']['mode'] = 'all'; // force all the criterias to be met
985
986
			do_action( 'gravityview_log_debug', '[process_search_only_approved] Search Criteria if show only approved: ', $search_criteria );
987
		}
988
989
		return $search_criteria;
990
	}
991
992
993
	/**
994
	 * Check if a certain entry is approved.
995
	 *
996
	 * If we pass the View settings ($args) it will check the 'show_only_approved' setting before
997
	 *   checking the entry approved field, returning true if show_only_approved = false.
998
	 *
999
	 * @since 1.7
1000
	 * @since 1.18 Converted check to use GravityView_Entry_Approval_Status::is_approved
1001
	 *
1002
	 * @uses GravityView_Entry_Approval_Status::is_approved
1003
	 *
1004
	 * @param array $entry  Entry object
1005
	 * @param array $args   View settings (optional)
1006
	 *
1007
	 * @return bool
1008
	 */
1009
	public static function is_entry_approved( $entry, $args = array() ) {
1010
1011
		if ( empty( $entry['id'] ) || ( array_key_exists( 'show_only_approved', $args ) && ! $args['show_only_approved'] ) ) {
1012
			// is implicitly approved if entry is null or View settings doesn't require to check for approval
1013
			return true;
1014
		}
1015
1016
		/** @since 1.19 */
1017
		if( ! empty( $args['admin_show_all_statuses'] ) && GVCommon::has_cap('gravityview_moderate_entries') ) {
0 ignored issues
show
Coding Style introduced by
Expected 1 spaces after opening bracket; 0 found
Loading history...
Coding Style introduced by
Expected 1 spaces before closing bracket; 0 found
Loading history...
1018
			do_action( 'gravityview_log_debug', __METHOD__ . ': User can moderate entries, so entry is approved for viewing' );
1019
			return true;
1020
		}
1021
1022
		$is_approved = gform_get_meta( $entry['id'], GravityView_Entry_Approval::meta_key );
1023
1024
		return GravityView_Entry_Approval_Status::is_approved( $is_approved );
1025
	}
1026
1027
	/**
1028
	 * Parse search criteria for a entries search.
1029
	 *
1030
	 * array(
1031
	 * 	'search_field' => 1, // ID of the field
1032
	 *  'search_value' => '', // Value of the field to search
1033
	 *  'search_operator' => 'contains', // 'is', 'isnot', '>', '<', 'contains'
1034
	 *  'show_only_approved' => 0 or 1 // Boolean
1035
	 * )
1036
	 *
1037
	 * @param  array $args    Array of args
1038
	 * @param  int $form_id Gravity Forms form ID
1039
	 * @return array          Array of search parameters, formatted in Gravity Forms mode, using `status` key set to "active" by default, `field_filters` array with `key`, `value` and `operator` keys.
1040
	 */
1041
	public static function get_search_criteria( $args, $form_id ) {
1042
1043
		/**
1044
		 * @filter `gravityview_fe_search_criteria` Modify the search criteria
1045
		 * @see GravityView_Widget_Search::filter_entries Adds the default search criteria
1046
		 * @param array $search_criteria Empty `field_filters` key
1047
		 * @param int $form_id ID of the Gravity Forms form that is being searched
1048
		 */
1049
		$search_criteria = apply_filters( 'gravityview_fe_search_criteria', array( 'field_filters' => array() ), $form_id );
1050
1051
		$original_search_criteria = $search_criteria;
1052
1053
		do_action( 'gravityview_log_debug', '[get_search_criteria] Search Criteria after hook gravityview_fe_search_criteria: ', $search_criteria );
1054
1055
		// implicity search
1056
		if ( ! empty( $args['search_value'] ) ) {
1057
1058
			// Search operator options. Options: `is` or `contains`
1059
			$operator = ! empty( $args['search_operator'] ) && in_array( $args['search_operator'], array( 'is', 'isnot', '>', '<', 'contains' ) ) ? $args['search_operator'] : 'contains';
1060
1061
			$search_criteria['field_filters'][] = array(
1062
				'key' => rgget( 'search_field', $args ), // The field ID to search
1063
				'value' => _wp_specialchars( $args['search_value'] ), // The value to search. Encode ampersands but not quotes.
1064
				'operator' => $operator,
1065
			);
1066
		}
1067
1068
		if( $search_criteria !== $original_search_criteria ) {
1069
			do_action( 'gravityview_log_debug', '[get_search_criteria] Search Criteria after implicity search: ', $search_criteria );
1070
		}
1071
1072
		// Handle setting date range
1073
		$search_criteria = self::process_search_dates( $args, $search_criteria );
1074
1075
		if( $search_criteria !== $original_search_criteria ) {
1076
			do_action( 'gravityview_log_debug', '[get_search_criteria] Search Criteria after date params: ', $search_criteria );
1077
		}
1078
1079
		// remove not approved entries
1080
		$search_criteria = self::process_search_only_approved( $args, $search_criteria );
1081
1082
		/**
1083
		 * @filter `gravityview_status` Modify entry status requirements to be included in search results.
1084
		 * @param string $status Default: `active`. Accepts all Gravity Forms entry statuses, including `spam` and `trash`
1085
		 */
1086
		$search_criteria['status'] = apply_filters( 'gravityview_status', 'active', $args );
1087
1088
		return $search_criteria;
1089
	}
1090
1091
1092
1093
	/**
1094
	 * Core function to calculate View multi entries (directory) based on a set of arguments ($args):
1095
	 *   $id - View id
1096
	 *   $page_size - Page
1097
	 *   $sort_field - form field id to sort
1098
	 *   $sort_direction - ASC / DESC
1099
	 *   $start_date - Ymd
1100
	 *   $end_date - Ymd
1101
	 *   $class - assign a html class to the view
1102
	 *   $offset (optional) - This is the start point in the current data set (0 index based).
1103
	 *
1104
	 *
1105
	 *
1106
	 * @uses  gravityview_get_entries()
1107
	 * @access public
1108
	 * @param array $args\n
0 ignored issues
show
Bug introduced by
There is no parameter named $args\n. 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...
1109
	 *   - $id - View id
1110
	 *   - $page_size - Page
1111
	 *   - $sort_field - form field id to sort
1112
	 *   - $sort_direction - ASC / DESC
1113
	 *   - $start_date - Ymd
1114
	 *   - $end_date - Ymd
1115
	 *   - $class - assign a html class to the view
1116
	 *   - $offset (optional) - This is the start point in the current data set (0 index based).
1117
	 * @param int $form_id Gravity Forms Form ID
1118
	 * @return array Associative array with `count`, `entries`, and `paging` keys. `count` has the total entries count, `entries` is an array with Gravity Forms full entry data, `paging` is an array with `offset` and `page_size` keys
1119
	 */
1120
	public static function get_view_entries( $args, $form_id ) {
1121
1122
		do_action( 'gravityview_log_debug', '[get_view_entries] init' );
1123
		// start filters and sorting
1124
1125
		/**
1126
		 * Process search parameters
1127
		 * @var array
1128
		 */
1129
		$search_criteria = self::get_search_criteria( $args, $form_id );
1130
1131
		$paging = self::get_search_criteria_paging( $args );
1132
1133
		$parameters = array(
1134
			'search_criteria' => $search_criteria,
1135
			'sorting' => self::updateViewSorting( $args, $form_id ),
1136
			'paging' => $paging,
1137
			'cache' => isset( $args['cache'] ) ? $args['cache'] : true,
1138
		);
1139
1140
		/**
1141
		 * @filter `gravityview_get_entries` Filter get entries criteria
1142
		 * @param array $parameters Array with `search_criteria`, `sorting` and `paging` keys.
1143
		 * @param array $args View configuration args. {
1144
		 *      @type int $id View id
1145
		 *      @type int $page_size Number of entries to show per page
1146
		 *      @type string $sort_field Form field id to sort
1147
		 *      @type string $sort_direction Sorting direction ('ASC' or 'DESC')
1148
		 *      @type string $start_date - Ymd
1149
		 *      @type string $end_date - Ymd
1150
		 *      @type string $class - assign a html class to the view
1151
		 *      @type string $offset (optional) - This is the start point in the current data set (0 index based).
1152
		 * }
1153
		 * @param int $form_id ID of Gravity Forms form
1154
		 */
1155
		$parameters = apply_filters( 'gravityview_get_entries', $parameters, $args, $form_id );
1156
1157
		/**
1158
		 * @filter `gravityview_get_entries_{View ID}` Filter get entries criteria
1159
		 * @param array $parameters Array with `search_criteria`, `sorting` and `paging` keys.
1160
		 * @param array $args View configuration args.
1161
		 */
1162
		$parameters = apply_filters( 'gravityview_get_entries_'.$args['id'], $parameters, $args, $form_id );
1163
1164
		do_action( 'gravityview_log_debug', __METHOD__ . ': $parameters passed to gravityview_get_entries(): ', $parameters );
1165
1166
		//fetch entries
1167
		$count = 0;
1168
		$entries = gravityview_get_entries( $form_id, $parameters, $count );
1169
1170
		do_action( 'gravityview_log_debug', sprintf( '%s: Get Entries. Found: %s entries', __METHOD__, $count ), $entries );
1171
1172
		/**
1173
		 * @filter `gravityview_view_entries` Filter the entries output to the View
1174
		 * @deprecated since 1.5.2
1175
		 * @param array $args View settings associative array
1176
		 * @var array
1177
		 */
1178
		$entries = apply_filters( 'gravityview_view_entries', $entries, $args );
1179
1180
		/**
1181
		 * @filter `gravityview/view/entries` Filter the entries output to the View
1182
		 * @param array $criteria associative array containing count, entries & paging
1183
		 * @param array $args View settings associative array
1184
		 * @since 1.5.2
1185
		 */
1186
		return apply_filters( 'gravityview/view/entries', compact( 'count', 'entries', 'paging' ), $args );
1187
1188
	}
1189
1190
	/**
1191
	 * Get the paging array for the View
1192
	 *
1193
	 * @since 1.19.5
1194
	 *
1195
	 * @param $args
1196
	 * @param int $form_id
0 ignored issues
show
Bug introduced by
There is no parameter named $form_id. Was it maybe removed?

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

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

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

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

Loading history...
1197
	 */
1198
	public static function get_search_criteria_paging( $args ) {
1199
1200
		/**
1201
		 * @filter `gravityview_default_page_size` The default number of entries displayed in a View
1202
		 * @since 1.1.6
1203
		 * @param int $default_page_size Default: 25
1204
		 */
1205
		$default_page_size = apply_filters( 'gravityview_default_page_size', 25 );
1206
1207
		// Paging & offset
1208
		$page_size = ! empty( $args['page_size'] ) ? intval( $args['page_size'] ) : $default_page_size;
1209
1210
		if ( -1 === $page_size ) {
1211
			$page_size = PHP_INT_MAX;
1212
		}
1213
1214
		if ( isset( $args['offset'] ) ) {
1215
			$offset = intval( $args['offset'] );
1216
		} else {
1217
			$curr_page = empty( $_GET['pagenum'] ) ? 1 : intval( $_GET['pagenum'] );
0 ignored issues
show
introduced by
Detected access of super global var $_GET, probably need manual inspection.
Loading history...
1218
			$offset = ( $curr_page - 1 ) * $page_size;
1219
		}
1220
1221
		$paging = array(
1222
			'offset' => $offset,
1223
			'page_size' => $page_size,
1224
		);
1225
1226
		do_action( 'gravityview_log_debug', __METHOD__ . ': Paging: ', $paging );
1227
1228
		return $paging;
1229
	}
1230
1231
	/**
1232
	 * Updates the View sorting criteria
1233
	 *
1234
	 * @since 1.7
1235
	 *
1236
	 * @param array $args View settings. Required to have `sort_field` and `sort_direction` keys
1237
	 * @param int $form_id The ID of the form used to sort
1238
	 * @return array $sorting Array with `key`, `direction` and `is_numeric` keys
1239
	 */
1240
	public static function updateViewSorting( $args, $form_id ) {
0 ignored issues
show
Coding Style introduced by
The function name updateViewSorting is in camel caps, but expected update_view_sorting instead as per the coding standard.
Loading history...
1241
		$sorting = array();
1242
		$sort_field_id = isset( $_GET['sort'] ) ? $_GET['sort'] : rgar( $args, 'sort_field' );
0 ignored issues
show
introduced by
Detected access of super global var $_GET, probably need manual inspection.
Loading history...
introduced by
Detected usage of a non-sanitized input variable: $_GET
Loading history...
1243
		$sort_direction = isset( $_GET['dir'] ) ? $_GET['dir'] : rgar( $args, 'sort_direction' );
0 ignored issues
show
introduced by
Detected access of super global var $_GET, probably need manual inspection.
Loading history...
introduced by
Detected usage of a non-sanitized input variable: $_GET
Loading history...
1244
1245
		$sort_field_id = self::_override_sorting_id_by_field_type( $sort_field_id, $form_id );
1246
1247
		if ( ! empty( $sort_field_id ) ) {
1248
			$sorting = array(
1249
				'key' => $sort_field_id,
1250
				'direction' => strtolower( $sort_direction ),
1251
				'is_numeric' => GVCommon::is_field_numeric( $form_id, $sort_field_id )
1252
			);
1253
		}
1254
1255
		GravityView_View::getInstance()->setSorting( $sorting );
1256
1257
		do_action( 'gravityview_log_debug', '[updateViewSorting] Sort Criteria : ', $sorting );
1258
1259
		return $sorting;
1260
1261
	}
1262
1263
	/**
1264
	 * Override sorting per field
1265
	 *
1266
	 * Currently only modifies sorting ID when sorting by the full name. Sorts by first name.
1267
	 * Use the `gravityview/sorting/full-name` filter to override.
1268
	 *
1269
	 * @todo Filter from GravityView_Field
1270
	 * @since 1.7.4
1271
	 *
1272
	 * @param int|string $sort_field_id Field used for sorting (`id` or `1.2`)
1273
	 * @param int $form_id GF Form ID
1274
	 *
1275
	 * @return string Possibly modified sorting ID
1276
	 */
1277
	private static function _override_sorting_id_by_field_type( $sort_field_id, $form_id ) {
1278
1279
		$form = gravityview_get_form( $form_id );
1280
1281
		$sort_field = GFFormsModel::get_field( $form, $sort_field_id );
1282
1283
		if( ! $sort_field ) {
1284
			return $sort_field_id;
1285
		}
1286
1287
		switch ( $sort_field['type'] ) {
1288
1289
			case 'address':
1290
				// Sorting by full address
1291
				if ( floatval( $sort_field_id ) === floor( $sort_field_id ) ) {
1292
1293
					/**
1294
					 * Override how to sort when sorting address
1295
					 *
1296
					 * @since 1.8
1297
					 *
1298
					 * @param string $address_part `street`, `street2`, `city`, `state`, `zip`, or `country` (default: `city`)
1299
					 * @param string $sort_field_id Field used for sorting
1300
					 * @param int $form_id GF Form ID
1301
					 */
1302
					$address_part = apply_filters( 'gravityview/sorting/address', 'city', $sort_field_id, $form_id );
1303
1304
					switch( strtolower( $address_part ) ){
1305
						case 'street':
1306
							$sort_field_id .= '.1';
1307
							break;
1308
						case 'street2':
1309
							$sort_field_id .= '.2';
1310
							break;
1311
						default:
1312
						case 'city':
0 ignored issues
show
Unused Code introduced by
case 'city': $sort_f..._id .= '.3'; break; does not seem to be reachable.

This check looks for unreachable code. It uses sophisticated control flow analysis techniques to find statements which will never be executed.

Unreachable code is most often the result of return, die or exit statements that have been added for debug purposes.

function fx() {
    try {
        doSomething();
        return true;
    }
    catch (\Exception $e) {
        return false;
    }

    return false;
}

In the above example, the last return false will never be executed, because a return statement has already been met in every possible execution path.

Loading history...
1313
							$sort_field_id .= '.3';
1314
							break;
1315
						case 'state':
1316
							$sort_field_id .= '.4';
1317
							break;
1318
						case 'zip':
1319
							$sort_field_id .= '.5';
1320
							break;
1321
						case 'country':
1322
							$sort_field_id .= '.6';
1323
							break;
1324
					}
1325
1326
				}
1327
				break;
1328
			case 'name':
1329
				// Sorting by full name, not first, last, etc.
1330
				if ( floatval( $sort_field_id ) === floor( $sort_field_id ) ) {
1331
					/**
1332
					 * @filter `gravityview/sorting/full-name` Override how to sort when sorting full name.
1333
					 * @since 1.7.4
1334
					 * @param[in,out] string $name_part Sort by `first` or `last` (default: `first`)
1335
					 * @param[in] string $sort_field_id Field used for sorting
1336
					 * @param[in] int $form_id GF Form ID
1337
					 */
1338
					$name_part = apply_filters( 'gravityview/sorting/full-name', 'first', $sort_field_id, $form_id );
1339
1340
					if ( 'last' === strtolower( $name_part ) ) {
1341
						$sort_field_id .= '.6';
1342
					} else {
1343
						$sort_field_id .= '.3';
1344
					}
1345
				}
1346
				break;
1347
			case 'list':
1348
				$sort_field_id = false;
1349
				break;
1350
			case 'time':
1351
1352
				/**
1353
				 * @filter `gravityview/sorting/time` Override how to sort when sorting time
1354
				 * @see GravityView_Field_Time
1355
				 * @since 1.14
1356
				 * @param[in,out] string $name_part Field used for sorting
1357
				 * @param[in] int $form_id GF Form ID
1358
				 */
1359
				$sort_field_id = apply_filters( 'gravityview/sorting/time', $sort_field_id, $form_id );
1360
				break;
1361
		}
1362
1363
		return $sort_field_id;
1364
	}
1365
1366
	/**
1367
	 * Verify if user requested a single entry view
1368
	 * @return boolean|string false if not, single entry slug if true
1369
	 */
1370
	public static function is_single_entry() {
1371
1372
		if ( function_exists( 'gravityview' ) ) {
1373
			$var_name = \GV\Entry::get_endpoint_name();
1374
		} else {
1375
			/** Deprecated. Use \GV\Entry::get_endpoint_name instead. */
1376
			$var_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...
1377
		}
1378
1379
		$single_entry = get_query_var( $var_name );
1380
1381
		/**
1382
		 * Modify the entry that is being displayed.
1383
		 *
1384
		 * @internal Should only be used by things like the oEmbed functionality.
1385
		 * @since 1.6
1386
		 */
1387
		$single_entry = apply_filters( 'gravityview/is_single_entry', $single_entry );
1388
1389
		if ( empty( $single_entry ) ){
1390
			return false;
1391
		} else {
1392
			return $single_entry;
1393
		}
1394
	}
1395
1396
1397
	/**
1398
	 * Register styles and scripts
1399
	 *
1400
	 * @access public
1401
	 * @return void
1402
	 */
1403
	public function add_scripts_and_styles() {
1404
		global $post, $posts;
0 ignored issues
show
Compatibility Best Practice introduced by
Use of global functionality is not recommended; it makes your code harder to test, and less reusable.

Instead of relying on global state, we recommend one of these alternatives:

1. Pass all data via parameters

function myFunction($a, $b) {
    // Do something
}

2. Create a class that maintains your state

class MyClass {
    private $a;
    private $b;

    public function __construct($a, $b) {
        $this->a = $a;
        $this->b = $b;
    }

    public function myFunction() {
        // Do something
    }
}
Loading history...
1405
		// enqueue template specific styles
1406
		if ( $this->getGvOutputData() ) {
1407
1408
			$views = $this->getGvOutputData()->get_views();
1409
1410
			foreach ( $views as $view_id => $data ) {
1411
1412
				/**
1413
				 * Don't enqueue the scripts or styles if it's not going to be displayed.
1414
				 * @since 1.15
1415
				 */
1416
				if( is_user_logged_in() && false === GVCommon::has_cap( 'read_gravityview', $view_id ) ) {
1417
					continue;
1418
				}
1419
1420
				// By default, no thickbox
1421
				$js_dependencies = array( 'jquery', 'gravityview-jquery-cookie' );
1422
				$css_dependencies = array();
1423
1424
				// If the thickbox is enqueued, add dependencies
1425
				if ( ! empty( $data['atts']['lightbox'] ) ) {
1426
1427
					/**
1428
					 * @filter `gravity_view_lightbox_script` Override the lightbox script to enqueue. Default: `thickbox`
1429
					 * @param string $script_slug If you want to use a different lightbox script, return the name of it here.
1430
					 */
1431
					$js_dependencies[] = apply_filters( 'gravity_view_lightbox_script', 'thickbox' );
1432
1433
					/**
1434
					 * @filter `gravity_view_lightbox_style` Modify the lightbox CSS slug. Default: `thickbox`
1435
					 * @param string $script_slug If you want to use a different lightbox script, return the name of its CSS file here.
1436
					 */
1437
					$css_dependencies[] = apply_filters( 'gravity_view_lightbox_style', 'thickbox' );
1438
				}
1439
1440
				/**
1441
				 * If the form has checkbox fields, enqueue dashicons
1442
				 * @see https://github.com/katzwebservices/GravityView/issues/536
1443
				 * @since 1.15
1444
				 */
1445
				if( gravityview_view_has_single_checkbox_or_radio( $data['form'], $data['fields'] ) ) {
1446
					$css_dependencies[] = 'dashicons';
1447
				}
1448
1449
				wp_register_script( 'gravityview-jquery-cookie', plugins_url( 'assets/lib/jquery.cookie/jquery.cookie.min.js', GRAVITYVIEW_FILE ), array( 'jquery' ), GravityView_Plugin::version, true );
1450
1451
				$script_debug = ( defined( 'SCRIPT_DEBUG' ) && SCRIPT_DEBUG ) ? '' : '.min';
1452
1453
				wp_register_script( 'gravityview-fe-view', plugins_url( 'assets/js/fe-views' . $script_debug . '.js', GRAVITYVIEW_FILE ), apply_filters( 'gravityview_js_dependencies', $js_dependencies ) , GravityView_Plugin::version, true );
1454
1455
				wp_enqueue_script( 'gravityview-fe-view' );
1456
1457
				if ( ! empty( $data['atts']['sort_columns'] ) ) {
1458
					wp_enqueue_style( 'gravityview_font', plugins_url( 'assets/css/font.css', GRAVITYVIEW_FILE ), $css_dependencies, GravityView_Plugin::version, 'all' );
1459
				}
1460
1461
				$this->enqueue_default_style( $css_dependencies );
1462
1463
				self::add_style( $data['template_id'] );
1464
			}
1465
1466
			if ( 'wp_print_footer_scripts' === current_filter() ) {
1467
1468
				$js_localization = array(
1469
					'cookiepath' => COOKIEPATH,
1470
					'clear' => _x( 'Clear', 'Clear all data from the form', 'gravityview' ),
1471
					'reset' => _x( 'Reset', 'Reset the search form to the state that existed on page load', 'gravityview' ),
1472
				);
1473
1474
				/**
1475
				 * @filter `gravityview_js_localization` Modify the array passed to wp_localize_script()
1476
				 * @param array $js_localization The data padded to the Javascript file
1477
				 * @param array $views Array of View data arrays with View settings
1478
				 */
1479
				$js_localization = apply_filters( 'gravityview_js_localization', $js_localization, $views );
1480
1481
				wp_localize_script( 'gravityview-fe-view', 'gvGlobals', $js_localization );
1482
			}
1483
		}
1484
	}
1485
1486
	/**
1487
	 * Handle enqueuing the `gravityview_default_style` stylesheet
1488
	 *
1489
	 * @since 1.17
1490
	 *
1491
	 * @param array $css_dependencies Dependencies for the `gravityview_default_style` stylesheet
1492
	 *
1493
	 * @return void
1494
	 */
1495
	private function enqueue_default_style( $css_dependencies = array() ) {
1496
1497
		/**
1498
		 * @filter `gravityview_use_legacy_search_css` Should GravityView use the legacy Search Bar stylesheet (from before Version 1.17)?
1499
		 * @since 1.17
1500
		 * @param bool $use_legacy_search_style If true, loads `gv-legacy-search(-rtl).css`. If false, loads `gv-default-styles(-rtl).css`. `-rtl` is added on RTL websites. Default: `false`
1501
		 */
1502
		$use_legacy_search_style = apply_filters( 'gravityview_use_legacy_search_style', false );
1503
1504
		$rtl = is_rtl() ? '-rtl' : '';
1505
1506
		$css_file_base = $use_legacy_search_style ? 'gv-legacy-search' : 'gv-default-styles';
1507
1508
		$path = gravityview_css_url( $css_file_base . $rtl . '.css' );
1509
1510
		wp_enqueue_style( 'gravityview_default_style', $path, $css_dependencies, GravityView_Plugin::version, 'all' );
1511
	}
1512
1513
	/**
1514
	 * Add template extra style if exists
1515
	 * @param string $template_id
1516
	 */
1517
	public static function add_style( $template_id ) {
1518
1519
		if ( ! empty( $template_id ) && wp_style_is( 'gravityview_style_' . $template_id, 'registered' ) ) {
1520
			do_action( 'gravityview_log_debug', sprintf( '[add_style] Adding extra template style for %s', $template_id ) );
1521
			wp_enqueue_style( 'gravityview_style_' . $template_id );
1522
		} elseif ( empty( $template_id ) ) {
1523
			do_action( 'gravityview_log_error', '[add_style] Cannot add template style; template_id is empty' );
1524
		} else {
1525
			do_action( 'gravityview_log_error', sprintf( '[add_style] Cannot add template style; %s is not registered', 'gravityview_style_'.$template_id ) );
1526
		}
1527
1528
	}
1529
1530
1531
	/**
1532
	 * Inject the sorting links on the table columns
1533
	 *
1534
	 * Callback function for hook 'gravityview/template/field_label'
1535
	 * @see GravityView_API::field_label() (in includes/class-api.php)
1536
	 *
1537
	 * @since 1.7
1538
	 *
1539
	 * @param string $label Field label
1540
	 * @param array $field Field settings
1541
	 *
1542
	 * @return string Field Label
1543
	 */
1544
	public function add_columns_sort_links( $label = '', $field, $form ) {
1545
1546
		/**
1547
		 * Not a table-based template; don't add sort icons
1548
		 * @since 1.12
1549
		 */
1550
		if( ! preg_match( '/table/ism', GravityView_View::getInstance()->getTemplatePartSlug() ) ) {
1551
			return $label;
1552
		}
1553
1554
		if ( ! $this->is_field_sortable( $field['id'], $form ) ) {
1555
			return $label;
1556
		}
1557
1558
		$sorting = GravityView_View::getInstance()->getSorting();
1559
1560
		$class = 'gv-sort';
1561
1562
		$sort_field_id = self::_override_sorting_id_by_field_type( $field['id'], $form['id'] );
1563
1564
		$sort_args = array(
1565
			'sort' => $field['id'],
1566
			'dir' => 'asc',
1567
		);
1568
1569
		if ( ! empty( $sorting['key'] ) && (string) $sort_field_id === (string) $sorting['key'] ) {
1570
			//toggle sorting direction.
1571
			if ( 'asc' === $sorting['direction'] ) {
1572
				$sort_args['dir'] = 'desc';
1573
				$class .= ' gv-icon-sort-desc';
1574
			} else {
1575
				$sort_args['dir'] = 'asc';
1576
				$class .= ' gv-icon-sort-asc';
1577
			}
1578
		} else {
1579
			$class .= ' gv-icon-caret-up-down';
1580
		}
1581
1582
		$url = add_query_arg( $sort_args, remove_query_arg( array('pagenum') ) );
0 ignored issues
show
introduced by
No space after opening parenthesis of array is bad style
Loading history...
introduced by
No space before closing parenthesis of array is bad style
Loading history...
1583
1584
		return '<a href="'. esc_url_raw( $url ) .'" class="'. $class .'" ></a>&nbsp;'. $label;
1585
1586
	}
1587
1588
	/**
1589
	 * Checks if field (column) is sortable
1590
	 *
1591
	 * @param string $field Field settings
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...
1592
	 * @param array $form Gravity Forms form array
1593
	 *
1594
	 * @since 1.7
1595
	 *
1596
	 * @return bool True: Yes, field is sortable; False: not sortable
1597
	 */
1598
	public function is_field_sortable( $field_id = '', $form = array() ) {
1599
1600
		$field_type = $field_id;
1601
1602
		if( is_numeric( $field_id ) ) {
1603
			$field = GFFormsModel::get_field( $form, $field_id );
1604
			$field_type = $field->type;
1605
		}
1606
1607
		$not_sortable = array(
1608
			'edit_link',
1609
			'delete_link',
1610
		);
1611
1612
		/**
1613
		 * @filter `gravityview/sortable/field_blacklist` Modify what fields should never be sortable.
1614
		 * @since 1.7
1615
		 * @param[in,out] array $not_sortable Array of field types that aren't sortable
1616
		 * @param string $field_type Field type to check whether the field is sortable
1617
		 * @param array $form Gravity Forms form
1618
		 */
1619
		$not_sortable = apply_filters( 'gravityview/sortable/field_blacklist', $not_sortable, $field_type, $form );
1620
1621
		if ( in_array( $field_type, $not_sortable ) ) {
1622
			return false;
1623
		}
1624
1625
		return apply_filters( "gravityview/sortable/formfield_{$form['id']}_{$field_id}", apply_filters( "gravityview/sortable/field_{$field_id}", true, $form ) );
1626
1627
	}
1628
1629
}
1630
1631
GravityView_frontend::getInstance();
1632
1633
1634
1635