Completed
Push — develop ( f28044...9183da )
by
unknown
18:42
created

GravityView_frontend::parse_content()   C

Complexity

Conditions 12
Paths 33

Size

Total Lines 46

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 14
CRAP Score 15.888

Importance

Changes 0
Metric Value
cc 12
nc 33
nop 1
dl 0
loc 46
ccs 14
cts 20
cp 0.7
crap 15.888
rs 6.9666
c 0
b 0
f 0

How to fix   Complexity   

Long Method

Small methods make your code easier to understand, in particular if combined with a good name. Besides, if your method is small, finding a good name is usually much easier.

For example, if you find yourself adding comments to a method's body, this is usually a good sign to extract the commented part to a new method, and use the comment as a starting point when coming up with a good name for this new method.

Commonly applied refactorings include:

1
<?php
2
/**
3
 * GravityView Frontend functions
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
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;
30
31
	/**
32
	 * Does the current post have a `[gravityview]` shortcode?
33
	 * @var boolean
34
	 */
35
	var $post_has_shortcode = false;
36
37
	/**
38
	 * The Post ID of the currently viewed post. Not necessarily GV
39
	 * @var int
40
	 */
41
	var $post_id = null;
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;
49
50
	/**
51
	 * If we are viewing a single entry, the entry data
52
	 * @var array|false
53
	 */
54
	var $entry = false;
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;
61
62
	/**
63
	 * The View is showing search results
64
	 * @since 1.5.4
65
	 * @var boolean
66
	 */
67
	var $is_search = false;
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;
76
77
	/**
78
	 * @var GravityView_frontend
79
	 */
80
	static $instance;
81
82
	/**
83
	 * Class constructor, enforce Singleton pattern
84
	 */
85
	private function __construct() {}
86
87 39
	private function initialize() {
88 39
		add_action( 'wp', array( $this, 'parse_content'), 11 );
89 39
		add_filter( 'parse_query', array( $this, 'parse_query_fix_frontpage' ), 10 );
90 39
		add_action( 'template_redirect', array( $this, 'set_entry_data'), 1 );
91
92
		// Enqueue scripts and styles after GravityView_Template::register_styles()
93 39
		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 39
		add_action( 'wp_print_footer_scripts', array( $this, 'add_scripts_and_styles' ), 1 );
97
98 39
		add_filter( 'the_title', array( $this, 'single_entry_title' ), 1, 2 );
99 39
		add_filter( 'comments_open', array( $this, 'comments_open' ), 10, 2 );
100
101 39
		add_action( 'gravityview_after', array( $this, 'context_not_configured_warning' ) );
102 39
	}
103
104
	/**
105
	 * Get the one true instantiated self
106
	 * @return GravityView_frontend
107
	 */
108 42
	public static function getInstance() {
109
110 42
		if ( empty( self::$instance ) ) {
111 39
			self::$instance = new self;
112 39
			self::$instance->initialize();
113
		}
114
115 42
		return self::$instance;
116
	}
117
118
	/**
119
	 * @return GravityView_View_Data
120
	 */
121 40
	public function getGvOutputData() {
122 40
		return $this->gv_output_data;
123
	}
124
125
	/**
126
	 * @param \GravityView_View_Data $gv_output_data
127
	 */
128 40
	public function setGvOutputData( $gv_output_data ) {
129 40
		$this->gv_output_data = $gv_output_data;
130 40
	}
131
132
	/**
133
	 * @return boolean
134
	 */
135 39
	public function isSearch() {
136 39
		return $this->is_search;
137
	}
138
139
	/**
140
	 * @param boolean $is_search
141
	 */
142 40
	public function setIsSearch( $is_search ) {
143 40
		$this->is_search = $is_search;
144 40
	}
145
146
	/**
147
	 * @return bool|int
148
	 */
149 41
	public function getSingleEntry() {
150 41
		return $this->single_entry;
151
	}
152
153
	/**
154
	 * Sets the single entry ID and also the entry
155
	 * @param bool|int|string $single_entry
156
	 */
157 39
	public function setSingleEntry( $single_entry ) {
158
159 39
		$this->single_entry = $single_entry;
160
161 39
	}
162
163
	/**
164
	 * @return array
165
	 */
166 39
	public function getEntry() {
167 39
		return $this->entry;
168
	}
169
170
	/**
171
	 * Set the current entry
172
	 * @param array|int $entry Entry array or entry slug or ID
173
	 */
174 39
	public function setEntry( $entry ) {
175
176 39
		if ( ! is_array( $entry ) ) {
177 30
			$entry = GVCommon::get_entry( $entry );
178
		}
179
180 39
		$this->entry = $entry;
181 39
	}
182
183
	/**
184
	 * @return int
185
	 */
186 40
	public function getPostId() {
187 40
		return $this->post_id;
188
	}
189
190
	/**
191
	 * @param int $post_id
192
	 */
193 40
	public function setPostId( $post_id ) {
194 40
		$this->post_id = $post_id;
195 40
	}
196
197
	/**
198
	 * @return boolean
199
	 */
200 41
	public function isPostHasShortcode() {
201 41
		return $this->post_has_shortcode;
202
	}
203
204
	/**
205
	 * @param boolean $post_has_shortcode
206
	 */
207 40
	public function setPostHasShortcode( $post_has_shortcode ) {
208 40
		$this->post_has_shortcode = $post_has_shortcode;
209 40
	}
210
211
	/**
212
	 * @return boolean
213
	 */
214 42
	public function isGravityviewPostType() {
215 42
		return $this->is_gravityview_post_type;
216
	}
217
218
	/**
219
	 * @param boolean $is_gravityview_post_type
220
	 */
221 40
	public function setIsGravityviewPostType( $is_gravityview_post_type ) {
222 40
		$this->is_gravityview_post_type = $is_gravityview_post_type;
223 40
	}
224
225
	/**
226
	 * Set the context view ID used when page contains multiple embedded views or displaying the single entry view
227
	 *
228
	 *
229
	 *
230
	 * @param null $view_id
231
	 */
232 3
	public function set_context_view_id( $view_id = null ) {
233 3
		$multiple_views = $this->getGvOutputData() && $this->getGvOutputData()->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...
234
235 3
		if ( ! empty( $view_id ) ) {
236
237 1
			$this->context_view_id = (int) $view_id;
238
239 3
		} elseif ( isset( $_GET['gvid'] ) && $multiple_views ) {
240
			/**
241
			 * used on a has_multiple_views context
242
			 * @see GravityView_API::entry_link
243
			 */
244
			$this->context_view_id = (int) $_GET['gvid'];
245
246 3
		} elseif ( ! $multiple_views ) {
247 3
			$array_keys = array_keys( $this->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...
248 3
			$this->context_view_id = (int) array_pop( $array_keys );
249 3
			unset( $array_keys );
250
		}
251
252 3
	}
253
254
	/**
255
	 * Returns the the view_id context when page contains multiple embedded views or displaying single entry view
256
	 *
257
	 * @since 1.5.4
258
	 *
259
	 * @return int|null
260
	 */
261 39
	public function get_context_view_id() {
262 39
		return $this->context_view_id;
263
	}
264
265
	/**
266
	 * Allow GravityView entry endpoints on the front page of a site
267
	 *
268
	 * @link  https://core.trac.wordpress.org/ticket/23867 Fixes this core issue
269
	 * @link https://wordpress.org/plugins/cpt-on-front-page/ Code is based on this
270
	 *
271
	 * @since 1.17.3
272
	 *
273
	 * @param WP_Query &$query (passed by reference)
274
	 *
275
	 * @return void
276
	 */
277 186
	public function parse_query_fix_frontpage( &$query ) {
278 186
		global $wp_rewrite;
279
280 186
		$is_front_page = ( $query->is_home || $query->is_page );
281 186
		$show_on_front = ( 'page' === get_option('show_on_front') );
282 186
		$front_page_id = get_option('page_on_front');
283
284 186
		if (  $is_front_page && $show_on_front && $front_page_id ) {
285
286
			// Force to be an array, potentially a query string ( entry=16 )
287
			$_query = wp_parse_args( $query->query );
288
289
			// pagename can be set and empty depending on matched rewrite rules. Ignore an empty pagename.
290
			if ( isset( $_query['pagename'] ) && '' === $_query['pagename'] ) {
291
				unset( $_query['pagename'] );
292
			}
293
294
			// this is where will break from core wordpress
295
			/** @internal Don't use this filter; it will be unnecessary soon - it's just a patch for specific use case */
296
			$ignore = apply_filters( 'gravityview/internal/ignored_endpoints', array( 'preview', 'page', 'paged', 'cpage' ), $query );
297
			$endpoints = \GV\Utils::get( $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 186
	}
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 2
	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 2
		global $post;
339
340
		// If in admin and NOT AJAX request, get outta here.
341 2
		if ( gravityview()->request->is_admin() ) {
342
			return;
343
		}
344
345
		$is_GV_post_type = 'gravityview' === get_post_type( $post );
346 2
347
		// Calculate requested Views
348
		$post_content = ! empty( $post->post_content ) ? $post->post_content : null;
349 2
350
		if ( ! $is_GV_post_type && function_exists( 'parse_blocks' ) && preg_match_all( '/"ref":\d+/', $post_content ) ) {
351 2
			$blocks = parse_blocks( $post_content );
352
353 2
			foreach ( $blocks as $block ) {
354 2
				if ( empty( $block['attrs']['ref'] ) ) {
355 2
					continue;
356 2
				}
357
358
				$block_post = get_post( $block['attrs']['ref'] );
359 2
360
				$post_content .= $block_post->post_content;
361 2
			}
362 2
363
			$this->setGvOutputData( GravityView_View_Data::getInstance( $post_content ) );
364
		} else {
365
			$this->setGvOutputData( GravityView_View_Data::getInstance( $post ) );
366
		}
367
368
		// !important: we need to run this before getting single entry (to kick the advanced filter)
369
		$this->set_context_view_id();
370
371
		$this->setIsGravityviewPostType( $is_GV_post_type );
372
373
		$post_id = $this->getPostId() ? $this->getPostId() : ( isset( $post ) ? $post->ID : null );
374
		$this->setPostId( $post_id );
375
		$post_has_shortcode = $post_content ? gravityview_has_shortcode_r( $post_content, 'gravityview' ) : false;
376
		$this->setPostHasShortcode( $this->isGravityviewPostType() ? null : ! empty( $post_has_shortcode ) );
377
378
		// check if the View is showing search results (only for multiple entries View)
379
		$this->setIsSearch( $this->is_searching() );
380 2
381
		unset( $entry, $post_id, $post_has_shortcode );
382
	}
383 2
384 2
	/**
385
	 * Set the entry
386
	 */
387 2
	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...
388
		$entry_id = self::is_single_entry();
389 2
		$this->setSingleEntry( $entry_id );
390
		$this->setEntry( $entry_id );
391
	}
392 2
393
	/**
394
	 * Checks if the current View is presenting search results
395
	 *
396 2
	 * @since 1.5.4
397 2
	 *
398
	 * @return boolean True: Yes, it's a search; False: No, not a search.
399
	 */
400
	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...
401 1
402
		// It's a single entry, not search
403
		if ( $this->getSingleEntry() ) {
404 1
			return false;
405
		}
406
407
		$search_method = GravityView_Widget_Search::getInstance()->get_search_method();
408 1
409
		if( 'post' === $search_method ) {
410 1
			$get = $_POST;
411
		} else {
412 1
			$get = $_GET;
413
		}
414
415 1
		// No $_GET parameters
416
		if ( empty( $get ) || ! is_array( $get ) ) {
417
			return false;
418
		}
419
420 1
		// Remove empty values
421
		$get = array_filter( $get );
422
423
		// If the $_GET parameters are empty, it's no search.
424
		if ( empty( $get ) ) {
425
			return false;
426
		}
427
428
		$search_keys = array_keys( $get );
429
430 9
		$search_match = implode( '|', self::$search_parameters );
431 9
432
		foreach ( $search_keys as $search_key ) {
433
434 9
			// Analyze the search key $_GET parameter and see if it matches known GV args
435
			if ( preg_match( '/(' . $search_match . ')/i', $search_key ) ) {
436
				return true;
437
			}
438 9
		}
439
440
		return false;
441 9
	}
442 8
443
	/**
444
	 * Filter the title for the single entry view
445 1
	 *
446
	 * @param  string $passed_title  Current title
447
	 * @param  int $passed_post_id Post ID
448
	 * @return string (modified) title
449
	 */
450
	public function single_entry_title( $passed_title, $passed_post_id = null ) {
451
		global $post;
452 1
453
		// Since this is a public method, it can be called outside of the plugin. Don't assume things have been loaded properly.
454 1
		if ( ! class_exists( '\GV\Entry' ) ) {
455 1
			return $passed_title;
456
		}
457
458
		$gventry = gravityview()->request->is_entry();
459 1
460 1
		// If this is the directory view, return.
461
		if( ! $gventry ) {
462
			return $passed_title;
463
		}
464
465 1
		$entry = $gventry->as_entry();
466 1
467
		/**
468
		 * @filter `gravityview/single/title/out_loop` Apply the Single Entry Title filter outside the WordPress loop?
469 1
		 * @param boolean $in_the_loop Whether to apply the filter to the menu title and the meta tag <title> - outside the loop
470
		 * @param array $entry Current entry
471 1
		 */
472 1
		$apply_outside_loop = apply_filters( 'gravityview/single/title/out_loop', in_the_loop(), $entry );
473
474
		if ( ! $apply_outside_loop ) {
475 1
			return $passed_title;
476
		}
477
478 1
		// WooCommerce doesn't $post_id
479
		if ( empty( $passed_post_id ) )  {
480 1
			return $passed_title;
481
		}
482 1
483
		// Don't modify the title for anything other than the current view/post.
484
		// This is true for embedded shortcodes and Views.
485 1
		if ( is_object( $post ) && (int) $post->ID !== (int) $passed_post_id ) {
486
			return $passed_title;
487 1
		}
488
489
		$view = gravityview()->request->is_view();
490
491 1
		if( $view ) {
492
			return $this->_get_single_entry_title( $view, $entry, $passed_title );
493
		}
494 1
495 1
		$_gvid = \GV\Utils::_GET( 'gvid', null );
496
497
		// $_GET['gvid'] is set; we know what View to render
498
		if ( $_gvid ) {
499
500
			$view = \GV\View::by_id( $_gvid );
501
502
			return $this->_get_single_entry_title( $view, $entry, $passed_title );
503
		}
504
505
		global $post;
506
507
		if ( ! $post ) {
508
			return $passed_title;
509
		}
510
511
		$view_collection = \GV\View_Collection::from_post( $post );
512
513
		// We have multiple Views, but no gvid...this isn't valid security
514
		if( 1 < $view_collection->count() ) {
515
			return $passed_title;
516
		}
517
518
		return $this->_get_single_entry_title( $view_collection->first(), $entry, $passed_title );
519
	}
520
521
	/**
522
	 * Returns the single entry title for a View with variables replaced and shortcodes parsed
523
	 *
524
	 * @since 2.7.2
525
	 *
526
	 * @param \GV\View|null $view
527
	 * @param array $entry
528
	 * @param string $passed_title
529
	 *
530
	 * @return string
531
	 */
532
	private function _get_single_entry_title( $view, $entry = array(), $passed_title = '' ) {
533
534
		if ( ! $view ) {
535
			return $passed_title;
536
		}
537
538
		/**
539
		 * @filter `gravityview/single/title/check_entry_display` Override whether to check entry display rules against filters
540
		 * @internal This might change in the future! Don't rely on it.
541
		 * @since 2.7.2
542
		 * @param bool $check_entry_display Check whether the entry is visible for the current View configuration. Default: true.
543
		 * @param array $entry Gravity Forms entry array
544
		 * @param \GV\View $view The View
545
		 */
546
		$check_entry_display = apply_filters( 'gravityview/single/title/check_entry_display', true, $entry, $view );
547
548
		if( $check_entry_display ) {
549
550
			$check_display = GVCommon::check_entry_display( $entry, $view );
551
552
			if( is_wp_error( $check_display ) ) {
553
				return $passed_title;
554
			}
555
		}
556
557
		$title = $view->settings->get( 'single_title', $passed_title );
558
559 4
		$form = GVCommon::get_form( $entry['form_id'] );
560 4
561 4
		// We are allowing HTML in the fields, so no escaping the output
562
		$title = GravityView_API::replace_variables( $title, $form, $entry );
563
564
		$title = do_shortcode( $title );
565
566
		return $title;
567
	}
568
569
570
	/**
571
	 * In case View post is called directly, insert the view in the post content
572
	 *
573
	 * @deprecated Use \GV\View::content() instead.
574
	 *
575
	 * @static
576
	 * @param mixed $content
577
	 * @return string Add the View output into View CPT content
578
	 */
579
	public function insert_view_in_content( $content ) {
580
		gravityview()->log->notice( '\GravityView_frontend::insert_view_in_content is deprecated. Use \GV\View::content()' );
581
		return \GV\View::content( $content );
582
	}
583
584
	/**
585
	 * Disable comments on GravityView post types
586
	 * @param  boolean $open    existing status
587
	 * @param  int $post_id Post ID
588
	 * @return boolean
589
	 */
590
	public function comments_open( $open, $post_id ) {
591
592
		if ( $this->isGravityviewPostType() ) {
593
			$open = false;
594
		}
595
596 2
		/**
597
		 * @filter `gravityview/comments_open` Whether to set comments to open or closed.
598 2
		 * @since  1.5.4
599
		 * @param  boolean $open Open or closed status
600
		 * @param  int $post_id Post ID to set comment status for
601
		 */
602 2
		$open = apply_filters( 'gravityview/comments_open', $open, $post_id );
603
604 2
		return $open;
605 2
	}
606
607
	/**
608
	 * Display a warning when a View has not been configured
609
	 *
610
	 * @since 1.19.2
611
	 *
612
	 * @param int $view_id The ID of the View currently being displayed
613
	 *
614
	 * @return void
615
	 */
616
	public function context_not_configured_warning( $view_id = 0 ) {
617
618
		if ( ! class_exists( 'GravityView_View' ) ) {
619
			return;
620
		}
621
622
		$fields = GravityView_View::getInstance()->getContextFields();
623
624
		if ( ! empty( $fields ) ) {
625
			return;
626
		}
627
628
		$context = GravityView_View::getInstance()->getContext();
629
630
		switch( $context ) {
631
			case 'directory':
632
				$tab = __( 'Multiple Entries', 'gravityview' );
633
				break;
634
			case 'edit':
635
				$tab = __( 'Edit Entry', 'gravityview' );
636
				break;
637
			case 'single':
638
			default:
639
				$tab = __( 'Single Entry', 'gravityview' );
640
				break;
641
		}
642
643
644
		$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 );
645
		$edit_link = admin_url( sprintf( 'post.php?post=%d&action=edit#%s-view', $view_id, $context ) );
646
		$action_text = sprintf( esc_html__('Add fields to %s', 'gravityview' ), $tab );
647
		$message = esc_html__( 'You can only see this message because you are able to edit this View.', 'gravityview' );
648
649
		$image =  sprintf( '<img alt="%s" src="%s" style="margin-top: 10px;" />', $tab, esc_url(plugins_url( sprintf( 'assets/images/tab-%s.png', $context ), GRAVITYVIEW_FILE ) ) );
650
		$output = sprintf( '<h3>%s <strong><a href="%s">%s</a></strong></h3><p>%s</p>', $title, esc_url( $edit_link ), $action_text, $message );
651
652
		echo GVCommon::generate_notice( $output . $image, 'gv-error error', 'edit_gravityview', $view_id );
653
	}
654
655
656
	/**
657
	 * Core function to render a View based on a set of arguments
658 1
	 *
659 1
	 * @static
660
	 * @param array $passed_args {
661
	 *
662
	 *      Settings for rendering the View
663
	 *
664
	 *      @type int $id View id
665
	 *      @type int $page_size Number of entries to show per page
666
	 *      @type string $sort_field Form field id to sort
667 1
	 *      @type string $sort_direction Sorting direction ('ASC', 'DESC', or 'RAND')
668
	 *      @type string $start_date - Ymd
669
	 *      @type string $end_date - Ymd
670
	 *      @type string $class - assign a html class to the view
671 1
	 *      @type string $offset (optional) - This is the start point in the current data set (0 index based).
672
	 * }
673 1
	 *
674 1
	 * @deprecated Use \GV\View_Renderer
675
	 *
676 1
	 * @return string|null HTML output of a View, NULL if View isn't found
677 1
	 */
678
	public function render_view( $passed_args ) {
679
		gravityview()->log->notice( '\GravityView_frontend::render_view is deprecated. Use \GV\View_Renderer etc.' );
680 1
681 1
		/**
682
		 * We can use a shortcode here, since it's pretty much the same.
683
		 *
684
		 * But we do need to check embed permissions, since shortcodes don't do this.
685
		 */
686
687
		if ( ! $view = gravityview()->views->get( $passed_args ) ) {
0 ignored issues
show
Documentation introduced by
The property views does not exist on object<GV\Core>. 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...
688
			return null;
689
		}
690
691
		$view->settings->update( $passed_args );
692
693
		$direct_access = apply_filters( 'gravityview_direct_access', true, $view->ID );
694
		$embed_only = $view->settings->get( 'embed_only' );
695
696
		if( ! $direct_access || ( $embed_only && ! GVCommon::has_cap( 'read_private_gravityviews' ) ) ) {
697
			return __( 'You are not allowed to view this content.', 'gravityview' );
698
		}
699 75
700
		$shortcode = new \GV\Shortcodes\gravityview();
701 75
		return $shortcode->callback( $passed_args );
702
	}
703 75
704
	/**
705
	 * Process the start and end dates for a view - overrides values defined in shortcode (if needed)
706
	 *
707
	 * The `start_date` and `end_date` keys need to be in a format processable by GFFormsModel::get_date_range_where(),
708 75
	 * which uses \DateTime() format.
709
	 *
710
	 * 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()},
711 2
	 * including strings like "now" or "-1 year" or "-3 days".
712
	 *
713
	 * @see GFFormsModel::get_date_range_where
714 2
	 *
715
	 * @param  array      $args            View settings
716
	 * @param  array      $search_criteria Search being performed, if any
717
	 * @return array                       Modified `$search_criteria` array
718
	 */
719
	public static function process_search_dates( $args, $search_criteria = array() ) {
720 2
721 2
		$return_search_criteria = $search_criteria;
722
723 2
		foreach ( array( 'start_date', 'end_date' ) as $key ) {
724
725 1
726
			// Is the start date or end date set in the view or shortcode?
727
			// If so, we want to make sure that the search doesn't go outside the bounds defined.
728 1
			if ( ! empty( $args[ $key ] ) ) {
729 1
730
				// Get a timestamp and see if it's a valid date format
731
				$date = strtotime( $args[ $key ], GFCommon::get_local_timestamp() );
732
733
				// The date was invalid
734
				if ( empty( $date ) ) {
735
					gravityview()->log->error( ' Invalid {key} date format: {format}', array( 'key' => $key, 'format' => $args[ $key ] ) );
736
					continue;
737
				}
738 1
739 1
				// The format that Gravity Forms expects for start_date and day-specific (not hour/second-specific) end_date
740 1
				$datetime_format = 'Y-m-d H:i:s';
741 1
				$search_is_outside_view_bounds = false;
742 1
743 1
				if( ! empty( $search_criteria[ $key ] ) ) {
744
745
					$search_date = strtotime( $search_criteria[ $key ], GFCommon::get_local_timestamp() );
746
747
					// The search is for entries before the start date defined by the settings
748 2
					switch ( $key ) {
749
						case 'end_date':
750
							/**
751 2
							 * If the end date is formatted as 'Y-m-d', it should be formatted without hours and seconds
752
							 * so that Gravity Forms can convert the day to 23:59:59 the previous day.
753
							 *
754
							 * If it's a relative date ("now" or "-1 day"), then it should use the precise date format
755
							 *
756 75
							 * @see GFFormsModel::get_date_range_where
757
							 */
758 2
							$datetime_format               = gravityview_is_valid_datetime( $args[ $key ] ) ? 'Y-m-d' : $datetime_format;
759 1
							$search_is_outside_view_bounds = ( $search_date > $date );
760
							break;
761
						case 'start_date':
762
							$search_is_outside_view_bounds = ( $search_date < $date );
763 75
							break;
764
					}
765
				}
766
767
				// If there is no search being performed, or if there is a search being performed that's outside the bounds
768
				if ( empty( $search_criteria[ $key ] ) || $search_is_outside_view_bounds ) {
769
770
					// Then we override the search and re-set the start date
771
					$return_search_criteria[ $key ] = date_i18n( $datetime_format , $date, true );
772
				}
773
			}
774 74
		}
775
776
		if( isset( $return_search_criteria['start_date'] ) && isset( $return_search_criteria['end_date'] ) ) {
777 74
			// The start date is AFTER the end date. This will result in no results, but let's not force the issue.
778
			if ( strtotime( $return_search_criteria['start_date'] ) > strtotime( $return_search_criteria['end_date'] ) ) {
779
				gravityview()->log->error( 'Invalid search: the start date is after the end date.', array( 'data' => $return_search_criteria ) );
780
			}
781
		}
782 74
783
		return $return_search_criteria;
784 18
	}
785
786
787
	/**
788
	 * Process the approved only search criteria according to the View settings
789 18
	 *
790
	 * @param  array      $args            View settings
791 18
	 * @param  array      $search_criteria Search being performed, if any
792
	 * @return array                       Modified `$search_criteria` array
793
	 */
794 74
	public static function process_search_only_approved( $args, $search_criteria ) {
795
796
		/** @since 1.19 */
797
		if( ! empty( $args['admin_show_all_statuses'] ) && GVCommon::has_cap('gravityview_moderate_entries') ) {
798
			gravityview()->log->debug( 'User can moderate entries; showing all approval statuses' );
799
			return $search_criteria;
800
		}
801
802
		if ( ! empty( $args['show_only_approved'] ) ) {
803
804
			$search_criteria['field_filters'][] = array(
805
				'key' => GravityView_Entry_Approval::meta_key,
806
				'value' => GravityView_Entry_Approval_Status::APPROVED
807
			);
808
809
			$search_criteria['field_filters']['mode'] = 'all'; // force all the criterias to be met
810
811
			gravityview()->log->debug( '[process_search_only_approved] Search Criteria if show only approved: ', array( 'data' => $search_criteria ) );
812
		}
813
814
		return $search_criteria;
815
	}
816
817
818
	/**
819
	 * Check if a certain entry is approved.
820
	 *
821
	 * If we pass the View settings ($args) it will check the 'show_only_approved' setting before
822
	 *   checking the entry approved field, returning true if show_only_approved = false.
823
	 *
824
	 * @since 1.7
825
	 * @since 1.18 Converted check to use GravityView_Entry_Approval_Status::is_approved
826
	 *
827
	 * @uses GravityView_Entry_Approval_Status::is_approved
828
	 *
829
	 * @param array $entry  Entry object
830
	 * @param array $args   View settings (optional)
831
	 *
832
	 * @return bool
833
	 */
834
	public static function is_entry_approved( $entry, $args = array() ) {
835
836
		if ( empty( $entry['id'] ) || ( array_key_exists( 'show_only_approved', $args ) && ! $args['show_only_approved'] ) ) {
837
			// is implicitly approved if entry is null or View settings doesn't require to check for approval
838
			return true;
839
		}
840
841
		/** @since 1.19 */
842
		if( ! empty( $args['admin_show_all_statuses'] ) && GVCommon::has_cap('gravityview_moderate_entries') ) {
843
			gravityview()->log->debug( 'User can moderate entries, so entry is approved for viewing' );
844
			return true;
845
		}
846 75
847
		$is_approved = gform_get_meta( $entry['id'], GravityView_Entry_Approval::meta_key );
848
849
		return GravityView_Entry_Approval_Status::is_approved( $is_approved );
850 75
	}
851 75
852
	/**
853
	 * Parse search criteria for a entries search.
854
	 *
855
	 * array(
856
	 * 	'search_field' => 1, // ID of the field
857
	 *  'search_value' => '', // Value of the field to search
858
	 *  'search_operator' => 'contains', // 'is', 'isnot', '>', '<', 'contains'
859
	 *  'show_only_approved' => 0 or 1 // Boolean
860 75
	 * )
861
	 *
862 75
	 * @param  array $args    Array of args
863
	 * @param  int $form_id Gravity Forms form ID
864
	 * @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.
865
	 */
866 75
	public static function get_search_criteria( $args, $form_id ) {
867
		/**
868 75
		 * Compatibility with filters hooking in `gravityview_search_criteria` instead of `gravityview_fe_search_criteria`.
869
		 */
870
		$criteria = apply_filters( 'gravityview_search_criteria', array(), array( $form_id ), \GV\Utils::get( $args, 'id' ) );
871 75
		$search_criteria = isset( $criteria['search_criteria'] ) ? $criteria['search_criteria'] : array( 'field_filters' => array() );
872
873
		/**
874 3
		 * @filter `gravityview_fe_search_criteria` Modify the search criteria
875
		 * @see GravityView_Widget_Search::filter_entries Adds the default search criteria
876 3
		 * @param array $search_criteria Empty `field_filters` key
877 3
		 * @param int $form_id ID of the Gravity Forms form that is being searched
878 3
		 * @param array $args The View settings.
879 3
		 */
880
		$search_criteria = apply_filters( 'gravityview_fe_search_criteria', $search_criteria, $form_id, $args );
881
882
		if ( ! is_array( $search_criteria ) ) {
883 3
			return array();
884
		}
885
886 75
		$original_search_criteria = $search_criteria;
887 3
888
		gravityview()->log->debug( '[get_search_criteria] Search Criteria after hook gravityview_fe_search_criteria: ', array( 'data' =>$search_criteria ) );
889
890
		// implicity search
891 75
		if ( ! empty( $args['search_value'] ) ) {
892
893 75
			// Search operator options. Options: `is` or `contains`
894 4
			$operator = ! empty( $args['search_operator'] ) && in_array( $args['search_operator'], array( 'is', 'isnot', '>', '<', 'contains' ) ) ? $args['search_operator'] : 'contains';
895
896
			$search_criteria['field_filters'][] = array(
897
				'key' => \GV\Utils::_GET( 'search_field', \GV\Utils::get( $args, 'search_field' ) ), // The field ID to search
898 75
				'value' => _wp_specialchars( $args['search_value'] ), // The value to search. Encode ampersands but not quotes.
899
				'operator' => $operator,
900
			);
901
902
			// Lock search mode to "all" with implicit presearch filter.
903
			$search_criteria['field_filters']['mode'] = 'all';
904 75
		}
905
906 75
		if( $search_criteria !== $original_search_criteria ) {
907
			gravityview()->log->debug( '[get_search_criteria] Search Criteria after implicity search: ', array( 'data' => $search_criteria ) );
908
		}
909
910
		// Handle setting date range
911
		$search_criteria = self::process_search_dates( $args, $search_criteria );
912
913
		if( $search_criteria !== $original_search_criteria ) {
914
			gravityview()->log->debug( '[get_search_criteria] Search Criteria after date params: ', array( 'data' => $search_criteria ) );
915
		}
916
917
		// remove not approved entries
918
		$search_criteria = self::process_search_only_approved( $args, $search_criteria );
919
920
		/**
921
		 * @filter `gravityview_status` Modify entry status requirements to be included in search results.
922
		 * @param string $status Default: `active`. Accepts all Gravity Forms entry statuses, including `spam` and `trash`
923
		 */
924
		$search_criteria['status'] = apply_filters( 'gravityview_status', 'active', $args );
925
926
		return $search_criteria;
927
	}
928
929
930
931
	/**
932
	 * Core function to calculate View multi entries (directory) based on a set of arguments ($args):
933
	 *   $id - View id
934
	 *   $page_size - Page
935
	 *   $sort_field - form field id to sort
936
	 *   $sort_direction - ASC / DESC
937 1
	 *   $start_date - Ymd
938
	 *   $end_date - Ymd
939 1
	 *   $class - assign a html class to the view
940
	 *   $offset (optional) - This is the start point in the current data set (0 index based).
941
	 *
942 1
	 *
943
	 *
944 1
	 * @uses  gravityview_get_entries()
945
	 * @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...
946
	 *   - $id - View id
947
	 *   - $page_size - Page
948 1
	 *   - $sort_field - form field id to sort
949
	 *   - $sort_direction - ASC / DESC
950 1
	 *   - $start_date - Ymd
951
	 *   - $end_date - Ymd
952
	 *   - $class - assign a html class to the view
953
	 *   - $offset (optional) - This is the start point in the current data set (0 index based).
954
	 * @param int $form_id Gravity Forms Form ID
955
	 * @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
956
	 */
957
	public static function get_view_entries( $args, $form_id ) {
958 1
959
		gravityview()->log->debug( '[get_view_entries] init' );
960
		// start filters and sorting
961 1
962 1
		$parameters = self::get_view_entries_parameters( $args, $form_id );
963 1
964
		$count = 0; // Must be defined so that gravityview_get_entries can use by reference
965
966
		// fetch entries
967
		list( $entries, $paging, $count ) =
968
			\GV\Mocks\GravityView_frontend_get_view_entries( $args, $form_id, $parameters, $count );
969
970
		gravityview()->log->debug( 'Get Entries. Found: {count} entries', array( 'count' => $count, 'data' => $entries ) );
971
972 1
		/**
973
		 * @filter `gravityview_view_entries` Filter the entries output to the View
974
		 * @deprecated since 1.5.2
975
		 * @param array $args View settings associative array
976
		 * @var array
977
		 */
978
		$entries = apply_filters( 'gravityview_view_entries', $entries, $args );
979
980
		$return = array(
981
			'count' => $count,
982
			'entries' => $entries,
983
			'paging' => $paging,
984
		);
985
986
		/**
987
		 * @filter `gravityview/view/entries` Filter the entries output to the View
988
		 * @param array $criteria associative array containing count, entries & paging
989
		 * @param array $args View settings associative array
990
		 * @since 1.5.2
991
		 */
992 74
		return apply_filters( 'gravityview/view/entries', $return, $args );
993
	}
994
995 74
	/**
996
	 * Get an array of search parameters formatted as Gravity Forms requires
997
	 *
998
	 * Results are filtered by `gravityview_get_entries` and `gravityview_get_entries_{View ID}` filters
999
	 *
1000
	 * @uses GravityView_frontend::get_search_criteria
1001
	 * @uses GravityView_frontend::get_search_criteria_paging
1002 74
	 *
1003
	 * @since 1.20
1004
	 *
1005
	 * @see \GV\View_Settings::defaults For $args options
1006
	 *
1007
	 * @param array $args Array of View settings, as structured in \GV\View_Settings::defaults
1008 74
	 * @param int $form_id Gravity Forms form ID to search
1009
	 *
1010 74
	 * @return array With `search_criteria`, `sorting`, `paging`, `cache` keys
1011
	 */
1012
	public static function get_view_entries_parameters( $args = array(), $form_id = 0 ) {
1013 74
1014 74
1015 74
		if ( ! is_array( $args ) || ! is_numeric( $form_id ) ) {
1016 74
1017
			gravityview()->log->error( 'Passed args are not an array or the form ID is not numeric' );
1018
1019
			return array();
1020
		}
1021
1022
		$form_id = intval( $form_id );
1023
1024
		/**
1025
		 * Process search parameters
1026
		 * @var array
1027
		 */
1028
		$search_criteria = self::get_search_criteria( $args, $form_id );
1029
1030
		$paging = self::get_search_criteria_paging( $args );
1031
1032
		$parameters = array(
1033
			'search_criteria' => $search_criteria,
1034 74
			'sorting' => self::updateViewSorting( $args, $form_id ),
1035
			'paging' => $paging,
1036
			'cache' => isset( $args['cache'] ) ? $args['cache'] : true,
1037
		);
1038
1039
		/**
1040
		 * @filter `gravityview_get_entries` Filter get entries criteria
1041 74
		 * @param array $parameters Array with `search_criteria`, `sorting` and `paging` keys.
1042
		 * @param array $args View configuration args. {
1043 74
		 *      @type int $id View id
1044
		 *      @type int $page_size Number of entries to show per page
1045 74
		 *      @type string $sort_field Form field id to sort
1046
		 *      @type string $sort_direction Sorting direction ('ASC', 'DESC', or 'RAND')
1047
		 *      @type string $start_date - Ymd
1048
		 *      @type string $end_date - Ymd
1049
		 *      @type string $class - assign a html class to the view
1050
		 *      @type string $offset (optional) - This is the start point in the current data set (0 index based).
1051
		 * }
1052
		 * @param int $form_id ID of Gravity Forms form
1053
		 */
1054
		$parameters = apply_filters( 'gravityview_get_entries', $parameters, $args, $form_id );
1055
1056 74
		/**
1057
		 * @filter `gravityview_get_entries_{View ID}` Filter get entries criteria
1058
		 * @param array $parameters Array with `search_criteria`, `sorting` and `paging` keys.
1059
		 * @param array $args View configuration args.
1060
		 */
1061
		$parameters = apply_filters( 'gravityview_get_entries_'.\GV\Utils::get( $args, 'id' ), $parameters, $args, $form_id );
1062
1063 74
		gravityview()->log->debug( '$parameters passed to gravityview_get_entries(): ', array( 'data' => $parameters ) );
1064
1065
		return $parameters;
1066 74
	}
1067
1068 74
	/**
1069 1
	 * Get the paging array for the View
1070
	 *
1071
	 * @since 1.19.5
1072 74
	 *
1073 74
	 * @param $args
1074
	 * @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...
1075 74
	 */
1076
	public static function get_search_criteria_paging( $args ) {
1077
1078
		/**
1079
		 * @filter `gravityview_default_page_size` The default number of entries displayed in a View
1080 74
		 * @since 1.1.6
1081 74
		 * @param int $default_page_size Default: 25
1082
		 */
1083
		$default_page_size = apply_filters( 'gravityview_default_page_size', 25 );
1084 74
1085
		// Paging & offset
1086 74
		$page_size = ! empty( $args['page_size'] ) ? intval( $args['page_size'] ) : $default_page_size;
1087
1088
		if ( -1 === $page_size ) {
1089
			$page_size = PHP_INT_MAX;
1090
		}
1091
1092
		$curr_page = empty( $_GET['pagenum'] ) ? 1 : intval( $_GET['pagenum'] );
1093
		$offset = ( $curr_page - 1 ) * $page_size;
1094
1095
		if ( ! empty( $args['offset'] ) ) {
1096
			$offset += intval( $args['offset'] );
1097
		}
1098 74
1099 74
		$paging = array(
1100
			'offset' => $offset,
1101 74
			'page_size' => $page_size,
1102
		);
1103 74
1104 2
		gravityview()->log->debug( 'Paging: ', array( 'data' => $paging ) );
1105 2
1106
		return $paging;
1107 2
	}
1108 2
1109 2
	/**
1110
	 * Updates the View sorting criteria
1111
	 *
1112
	 * @since 1.7
1113 74
	 *
1114 74
	 * @param array $args View settings. Required to have `sort_field` and `sort_direction` keys
1115
	 * @param int $form_id The ID of the form used to sort
1116
	 * @return array $sorting Array with `key`, `direction` and `is_numeric` keys
1117 74
	 */
1118 74
	public static function updateViewSorting( $args, $form_id ) {
1119
		$sorting = array();
1120
1121 74
		$has_values = isset( $_GET['sort'] );
1122 1
1123
		if ( $has_values && is_array( $_GET['sort'] ) ) {
1124
			$sorts = array_keys( $_GET['sort'] );
1125 74
			$dirs  = array_values( $_GET['sort'] );
1126
1127
			if ( $has_values = array_filter( $dirs ) ) {
1128
				$sort_field_id = end( $sorts );
1129 74
				$sort_direction = end( $dirs );
1130 5
			}
1131
		}
1132
1133
		if ( ! isset( $sort_field_id ) ) {
1134
			$sort_field_id = isset( $_GET['sort'] ) ? $_GET['sort'] : \GV\Utils::get( $args, 'sort_field' );
1135
		}
1136
1137
		if ( ! isset( $sort_direction ) ) {
1138 5
			$sort_direction = isset( $_GET['dir'] ) ? $_GET['dir'] : \GV\Utils::get( $args, 'sort_direction' );
1139
		}
1140 5
1141 5
		if ( is_array( $sort_field_id ) ) {
1142 5
			$sort_field_id = array_pop( $sort_field_id );
1143
		}
1144
1145 5
		if ( is_array( $sort_direction ) ) {
1146
			$sort_direction = array_pop( $sort_direction );
1147
		}
1148
1149
		if ( ! empty( $sort_field_id ) ) {
1150
			if ( is_array( $sort_field_id ) ) {
1151
				$sort_direction = array_values( $sort_field_id );
1152
				$sort_field_id = array_keys( $sort_field_id );
1153
1154
				$sort_field_id = reset( $sort_field_id );
1155
				$sort_direction = reset( $sort_direction );
1156
			}
1157
1158
			$sort_field_id = self::_override_sorting_id_by_field_type( $sort_field_id, $form_id );
1159
			$sorting = array(
1160
				'key' => $sort_field_id,
1161
				'direction' => strtolower( $sort_direction ),
1162
				'is_numeric' => GVCommon::is_field_numeric( $form_id, $sort_field_id )
1163
			);
1164
1165
			if ( 'RAND' === $sort_direction ) {
1166
1167
				$form = GFAPI::get_form( $form_id );
1168
1169
				// Get the first GF_Field field ID, set as the key for entry randomization
1170 74
				if ( ! empty( $form['fields'] ) ) {
1171
1172 74
					/** @var GF_Field $field */
1173
					foreach ( $form['fields'] as $field ) {
1174 74
						if ( ! is_a( $field, 'GF_Field' ) ) {
1175
							continue;
1176
						}
1177
1178
						$sorting = array(
1179
							'key'        => $field->id,
1180
							'is_numeric' => false,
1181
							'direction'  => 'RAND',
1182
						);
1183
1184
						break;
1185
					}
1186
				}
1187
			}
1188
		}
1189
1190
		GravityView_View::getInstance()->setSorting( $sorting );
1191
1192
		gravityview()->log->debug( '[updateViewSorting] Sort Criteria : ', array( 'data' => $sorting ) );
1193 5
1194
		return $sorting;
1195 5
1196
	}
1197
1198
	/**
1199
	 * Override sorting per field
1200
	 *
1201
	 * Currently only modifies sorting ID when sorting by the full name. Sorts by first name.
1202
	 * Use the `gravityview/sorting/full-name` filter to override.
1203 5
	 *
1204
	 * @todo Filter from GravityView_Field
1205 5
	 * @since 1.7.4
1206
	 * @internal Hi developer! Although this is public, don't call this method; we're going to replace it.
1207 5
	 *
1208
	 * @param int|string|array $sort_field_id Field used for sorting (`id` or `1.2`), or an array for multisorts
1209
	 * @param int $form_id GF Form ID
1210
	 *
1211 5
	 * @return string|array Possibly modified sorting ID. Array if $sort_field_id is passed as array.
1212
	 */
1213 5
	public static function _override_sorting_id_by_field_type( $sort_field_id, $form_id ) {
1214
1215
		if ( is_array( $sort_field_id ) ) {
1216
			$modified_ids = array();
1217
			foreach ( $sort_field_id as $_sort_field_id ) {
1218
				$modified_ids []= self::_override_sorting_id_by_field_type( $_sort_field_id, $form_id );
1219
			}
1220
			return $modified_ids;
1221
		}
1222
1223
		$form = gravityview_get_form( $form_id );
1224
1225
		$sort_field = GFFormsModel::get_field( $form, $sort_field_id );
1226
1227
		if( ! $sort_field ) {
1228
			return $sort_field_id;
1229
		}
1230
1231
		switch ( $sort_field['type'] ) {
1232
1233
			case 'address':
1234
				// Sorting by full address
1235
				if ( floatval( $sort_field_id ) === floor( $sort_field_id ) ) {
1236
1237
					/**
1238
					 * Override how to sort when sorting address
1239
					 *
1240
					 * @since 1.8
1241
					 *
1242
					 * @param string $address_part `street`, `street2`, `city`, `state`, `zip`, or `country` (default: `city`)
1243
					 * @param string $sort_field_id Field used for sorting
1244
					 * @param int $form_id GF Form ID
1245
					 */
1246
					$address_part = apply_filters( 'gravityview/sorting/address', 'city', $sort_field_id, $form_id );
1247
1248
					switch( strtolower( $address_part ) ){
1249
						case 'street':
1250
							$sort_field_id .= '.1';
1251
							break;
1252 5
						case 'street2':
1253
							$sort_field_id .= '.2';
1254
							break;
1255
						default:
1256
						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...
1257
							$sort_field_id .= '.3';
1258
							break;
1259
						case 'state':
1260
							$sort_field_id .= '.4';
1261
							break;
1262
						case 'zip':
1263
							$sort_field_id .= '.5';
1264
							break;
1265
						case 'country':
1266
							$sort_field_id .= '.6';
1267
							break;
1268
					}
1269
1270
				}
1271 5
				break;
1272
			case 'name':
1273
				// Sorting by full name, not first, last, etc.
1274 5
				if ( floatval( $sort_field_id ) === floor( $sort_field_id ) ) {
1275
					/**
1276
					 * @filter `gravityview/sorting/full-name` Override how to sort when sorting full name.
1277
					 * @since 1.7.4
1278
					 * @param[in,out] string $name_part Sort by `first` or `last` (default: `first`)
1279
					 * @param[in] string $sort_field_id Field used for sorting
1280
					 * @param[in] int $form_id GF Form ID
1281
					 */
1282
					$name_part = apply_filters( 'gravityview/sorting/full-name', 'first', $sort_field_id, $form_id );
1283 1
1284 1
					if ( 'last' === strtolower( $name_part ) ) {
1285
						$sort_field_id .= '.6';
1286
					} else {
1287 5
						$sort_field_id .= '.3';
1288
					}
1289
				}
1290
				break;
1291
			case 'list':
1292
				$sort_field_id = false;
1293
				break;
1294
			case 'time':
1295 26
1296
				/**
1297
				 * @filter `gravityview/sorting/time` Override how to sort when sorting time
1298 26
				 * @see GravityView_Field_Time
1299
				 * @since 1.14
1300
				 * @param[in,out] string $name_part Field used for sorting
1301
				 * @param[in] int $form_id GF Form ID
1302
				 */
1303
				$sort_field_id = apply_filters( 'gravityview/sorting/time', $sort_field_id, $form_id );
1304
				break;
1305
		}
1306 26
1307
		return $sort_field_id;
1308 26
	}
1309
1310
	/**
1311
	 * Verify if user requested a single entry view
1312
	 * @since 2.3.3 Added return null
1313
	 * @return boolean|string|null false if not, single entry slug if true, null if \GV\Entry doesn't exist yet
1314
	 */
1315
	public static function is_single_entry() {
1316 26
1317
		// Since this is a public method, it can be called outside of the plugin. Don't assume things have been loaded properly.
1318 26
		if ( ! class_exists( '\GV\Entry' ) ) {
1319 4
1320
			// Not using gravityview()->log->error(), since that may not exist yet either!
1321 22
			do_action( 'gravityview_log_error', '\GV\Entry not defined yet. Backtrace: ' . wp_debug_backtrace_summary()  );
1322
1323
			return null;
1324
		}
1325
1326
		$var_name = \GV\Entry::get_endpoint_name();
1327
1328
		$single_entry = get_query_var( $var_name );
1329
1330
		/**
1331 1
		 * Modify the entry that is being displayed.
1332 1
		 *
1333
		 * @internal Should only be used by things like the oEmbed functionality.
1334 1
		 * @since 1.6
1335
		 */
1336 1
		$single_entry = apply_filters( 'gravityview/is_single_entry', $single_entry );
1337
1338 1
		if ( empty( $single_entry ) ){
1339 1
			return false;
1340 1
		} else {
1341 1
			return $single_entry;
1342 1
		}
1343
	}
1344
1345
1346
	/**
1347
	 * Register styles and scripts
1348 1
	 *
1349
	 * @return void
1350
	 */
1351
	public function add_scripts_and_styles() {
1352
		global $post, $posts;
1353 1
		// enqueue template specific styles
1354 1
		if ( $this->getGvOutputData() ) {
1355
1356 1
			$views = $this->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...
1357
1358
			foreach ( $views as $view_id => $data ) {
1359 1
				$view = \GV\View::by_id( $data['id'] );
1360
				$view_id = $view->ID;
1361 1
				$template_id = gravityview_get_template_id( $view->ID );
1362
				$data = $view->as_data();
0 ignored issues
show
Deprecated Code introduced by
The method GV\View::as_data() has been deprecated.

This method has been deprecated.

Loading history...
1363 1
1364
				/**
1365
				 * Don't enqueue the scripts or styles if it's not going to be displayed.
1366
				 * @since 1.15
1367
				 */
1368
				if( is_user_logged_in() && false === GVCommon::has_cap( 'read_gravityview', $view_id ) ) {
1369
					continue;
1370
				}
1371
1372 1
				// By default, no thickbox
1373
				$js_dependencies = array( 'jquery', 'gravityview-jquery-cookie' );
1374
				$css_dependencies = array();
1375
1376
				$lightbox = $view->settings->get( 'lightbox' );
1377
1378
				// If the thickbox is enqueued, add dependencies
1379
				if ( $lightbox ) {
1380 1
1381 1
					global $wp_filter;
1382
1383 1
					/**
1384
					 * @filter `gravity_view_lightbox_script` Override the lightbox script to enqueue. Default: `thickbox`
1385
					 * @param string $script_slug If you want to use a different lightbox script, return the name of it here.
1386
					 * @deprecated 2.5.1 Naming. See `gravityview_lightbox_script` instead.
1387
					 */
1388
					$js_dependency = apply_filters_deprecated( 'gravity_view_lightbox_script', array( 'thickbox' ), '2.5.1', 'gravityview_lightbox_script' );
1389
1390
					/**
1391
					 * @filter `gravityview_lightbox_script` Override the lightbox script to enqueue. Default: `thickbox`
1392 1
					 * @since 2.5.1
1393
					 * @param string $script_slug If you want to use a different lightbox script, return the name of it here.
1394
					 * @param \GV\View The View.
1395
					 */
1396
					$js_dependency = apply_filters( 'gravityview_lightbox_script', $js_dependency, $view );
1397
					$js_dependencies[] = $js_dependency;
1398
1399
					/**
1400 1
					 * @filter `gravity_view_lightbox_style` Modify the lightbox CSS slug. Default: `thickbox`
1401 1
					 * @param string $script_slug If you want to use a different lightbox script, return the name of its CSS file here.
1402
					 * @deprecated 2.5.1 Naming. See `gravityview_lightbox_style` instead.
1403
					 */
1404
					$css_dependency = apply_filters_deprecated( 'gravity_view_lightbox_style', array( 'thickbox' ), '2.5.1', 'gravityview_lightbox_style' );
1405
1406
					/**
1407
					 * @filter `gravityview_lightbox_script` Override the lightbox script to enqueue. Default: `thickbox`
1408
					 * @since 2.5.1
1409 1
					 * @param string $script_slug If you want to use a different lightbox script, return the name of it here.
1410
					 * @param \GV\View The View.
1411
					 */
1412
					$css_dependency = apply_filters( 'gravityview_lightbox_style', $css_dependency, $view );
1413 1
					$css_dependencies[] = $css_dependency;
1414
				}
1415 1
1416
				/**
1417 1
				 * If the form has checkbox fields, enqueue dashicons
1418
				 * @see https://github.com/katzwebservices/GravityView/issues/536
1419 1
				 * @since 1.15
1420
				 */
1421 1
				if( gravityview_view_has_single_checkbox_or_radio( $data['form'], $data['fields'] ) ) {
1422
					$css_dependencies[] = 'dashicons';
1423
				}
1424
1425 1
				wp_register_script( 'gravityview-jquery-cookie', plugins_url( 'assets/lib/jquery.cookie/jquery.cookie.min.js', GRAVITYVIEW_FILE ), array( 'jquery' ), GravityView_Plugin::version, true );
0 ignored issues
show
Deprecated Code introduced by
The constant GravityView_Plugin::version has been deprecated with message: Use \GV\Plugin::$version

This class constant 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 constant will be removed from the class and what other constant to use instead.

Loading history...
1426
1427 1
				$script_debug = ( defined( 'SCRIPT_DEBUG' ) && SCRIPT_DEBUG ) ? '' : '.min';
1428
1429
				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 );
0 ignored issues
show
Deprecated Code introduced by
The constant GravityView_Plugin::version has been deprecated with message: Use \GV\Plugin::$version

This class constant 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 constant will be removed from the class and what other constant to use instead.

Loading history...
1430 1
1431
				wp_enqueue_script( 'gravityview-fe-view' );
1432
1433
				if ( ! empty( $data['atts']['sort_columns'] ) ) {
1434
					wp_enqueue_style( 'gravityview_font', plugins_url( 'assets/css/font.css', GRAVITYVIEW_FILE ), $css_dependencies, GravityView_Plugin::version, 'all' );
0 ignored issues
show
Deprecated Code introduced by
The constant GravityView_Plugin::version has been deprecated with message: Use \GV\Plugin::$version

This class constant 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 constant will be removed from the class and what other constant to use instead.

Loading history...
1435
				}
1436
1437
				$this->enqueue_default_style( $css_dependencies );
1438
1439
				self::add_style( $template_id );
1440
			}
1441
1442
			if ( 'wp_print_footer_scripts' === current_filter() ) {
1443
1444
				$js_localization = array(
1445
					'cookiepath' => COOKIEPATH,
1446
					'clear' => _x( 'Clear', 'Clear all data from the form', 'gravityview' ),
1447
					'reset' => _x( 'Reset', 'Reset the search form to the state that existed on page load', 'gravityview' ),
1448 1
				);
1449
1450
				/**
1451
				 * @filter `gravityview_js_localization` Modify the array passed to wp_localize_script()
1452
				 * @param array $js_localization The data padded to the Javascript file
1453
				 * @param array $views Array of View data arrays with View settings
1454
				 */
1455
				$js_localization = apply_filters( 'gravityview_js_localization', $js_localization, $views );
1456
1457
				wp_localize_script( 'gravityview-fe-view', 'gvGlobals', $js_localization );
1458
			}
1459
		}
1460
	}
1461
1462
	/**
1463
	 * Handle enqueuing the `gravityview_default_style` stylesheet
1464
	 *
1465
	 * @since 1.17
1466
	 *
1467
	 * @param array $css_dependencies Dependencies for the `gravityview_default_style` stylesheet
1468
	 *
1469
	 * @return void
1470
	 */
1471
	private function enqueue_default_style( $css_dependencies = array() ) {
1472
1473
		/**
1474
		 * @filter `gravityview_use_legacy_search_css` Should GravityView use the legacy Search Bar stylesheet (from before Version 1.17)?
1475
		 * @since 1.17
1476
		 * @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`
1477
		 */
1478
		$use_legacy_search_style = apply_filters( 'gravityview_use_legacy_search_style', false );
1479
1480
		$rtl = is_rtl() ? '-rtl' : '';
1481
1482
		$css_file_base = $use_legacy_search_style ? 'gv-legacy-search' : 'gv-default-styles';
1483
1484
		$path = gravityview_css_url( $css_file_base . $rtl . '.css' );
1485
1486
		wp_enqueue_style( 'gravityview_default_style', $path, $css_dependencies, GravityView_Plugin::version, 'all' );
0 ignored issues
show
Deprecated Code introduced by
The constant GravityView_Plugin::version has been deprecated with message: Use \GV\Plugin::$version

This class constant 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 constant will be removed from the class and what other constant to use instead.

Loading history...
1487
	}
1488
1489
	/**
1490
	 * Add template extra style if exists
1491
	 * @param string $template_id
1492
	 */
1493
	public static function add_style( $template_id ) {
1494
1495
		if ( ! empty( $template_id ) && wp_style_is( 'gravityview_style_' . $template_id, 'registered' ) ) {
1496
			gravityview()->log->debug(  'Adding extra template style for {template_id}', array( 'template_id' => $template_id ) );
1497
			wp_enqueue_style( 'gravityview_style_' . $template_id );
1498
		} elseif ( empty( $template_id ) ) {
1499
			gravityview()->log->error( 'Cannot add template style; template_id is empty' );
1500
		} else {
1501
			gravityview()->log->error( 'Cannot add template style; {template_id} is not registered', array( 'template_id' => 'gravityview_style_' . $template_id ) );
1502
		}
1503
1504
	}
1505
1506
1507
	/**
1508
	 * Inject the sorting links on the table columns
1509
	 *
1510
	 * Callback function for hook 'gravityview/template/field_label'
1511
	 * @see GravityView_API::field_label() (in includes/class-api.php)
1512
	 *
1513
	 * @since 1.7
1514
	 *
1515
	 * @param string $label Field label
1516
	 * @param array $field Field settings
1517
	 * @param array $form Form object
1518
	 *
1519
	 * @return string Field Label
1520
	 */
1521
	public function add_columns_sort_links( $label = '', $field, $form ) {
1522
1523
		/**
1524
		 * Not a table-based template; don't add sort icons
1525
		 * @since 1.12
1526
		 */
1527
		if( ! preg_match( '/table/ism', GravityView_View::getInstance()->getTemplatePartSlug() ) ) {
1528
			return $label;
1529
		}
1530
1531
		if ( ! $this->is_field_sortable( $field['id'], $form ) ) {
1532
			return $label;
1533
		}
1534
1535
		$sorting = GravityView_View::getInstance()->getSorting();
1536
1537
		$class = 'gv-sort';
1538
1539
		$sort_field_id = self::_override_sorting_id_by_field_type( $field['id'], $form['id'] );
1540
1541
		$sort_args = array(
1542
			'sort' => $field['id'],
1543
			'dir' => 'asc',
1544
		);
1545
1546
		if ( ! empty( $sorting['key'] ) && (string) $sort_field_id === (string) $sorting['key'] ) {
1547
			//toggle sorting direction.
1548
			if ( 'asc' === $sorting['direction'] ) {
1549
				$sort_args['dir'] = 'desc';
1550
				$class .= ' gv-icon-sort-desc';
1551
			} else {
1552
				$sort_args['dir'] = 'asc';
1553
				$class .= ' gv-icon-sort-asc';
1554
			}
1555
		} else {
1556
			$class .= ' gv-icon-caret-up-down';
1557
		}
1558
1559
		$url = add_query_arg( $sort_args, remove_query_arg( array('pagenum') ) );
1560
1561
		return '<a href="'. esc_url_raw( $url ) .'" class="'. $class .'" ></a>&nbsp;'. $label;
1562
1563 1
	}
1564
1565 1
	/**
1566
	 * Checks if field (column) is sortable
1567 1
	 *
1568 1
	 * @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...
1569 1
	 * @param array $form Gravity Forms form array
1570
	 *
1571
	 * @since 1.7
1572
	 *
1573 1
	 * @return bool True: Yes, field is sortable; False: not sortable
1574
	 */
1575
	public function is_field_sortable( $field_id = '', $form = array() ) {
1576
1577
		$field_type = $field_id;
1578
1579
		if( is_numeric( $field_id ) ) {
1580
			$field = GFFormsModel::get_field( $form, $field_id );
1581
			$field_type = $field ? $field->type : $field_id;
1582
		}
1583
1584 1
		$not_sortable = array(
1585
			'edit_link',
1586 1
			'delete_link',
1587
		);
1588
1589
		/**
1590 1
		 * @filter `gravityview/sortable/field_blacklist` Modify what fields should never be sortable.
1591
		 * @since 1.7
1592
		 * @param[in,out] array $not_sortable Array of field types that aren't sortable
1593
		 * @param string $field_type Field type to check whether the field is sortable
1594
		 * @param array $form Gravity Forms form
1595
		 */
1596
		$not_sortable = apply_filters( 'gravityview/sortable/field_blacklist', $not_sortable, $field_type, $form );
1597
1598
		if ( in_array( $field_type, $not_sortable ) ) {
1599
			return false;
1600
		}
1601
1602
		return apply_filters( "gravityview/sortable/formfield_{$form['id']}_{$field_id}", apply_filters( "gravityview/sortable/field_{$field_id}", true, $form ) );
1603
1604
	}
1605
1606
}
1607
1608
GravityView_frontend::getInstance();
1609
1610
1611
1612