Completed
Pull Request — master (#1442)
by Zack
08:53 queued 06:21
created

GravityView_frontend::_get_single_entry_title()   A

Complexity

Conditions 4
Paths 4

Size

Total Lines 36

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 0
CRAP Score 20

Importance

Changes 0
Metric Value
cc 4
nc 4
nop 3
dl 0
loc 36
ccs 0
cts 13
cp 0
crap 20
rs 9.344
c 0
b 0
f 0
1
<?php
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;
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 185
	public function parse_query_fix_frontpage( &$query ) {
278 185
		global $wp_rewrite;
279
280 185
		$is_front_page = ( $query->is_home || $query->is_page );
281 185
		$show_on_front = ( 'page' === get_option('show_on_front') );
282 185
		$front_page_id = get_option('page_on_front');
283
284 185
		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 185
	}
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
		// Calculate requested Views
346 2
		$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 2
		$this->set_context_view_id();
350
351 2
		$this->setIsGravityviewPostType( get_post_type( $post ) === 'gravityview' );
352
353 2
		$post_id = $this->getPostId() ? $this->getPostId() : (isset( $post ) ? $post->ID : null );
354 2
		$this->setPostId( $post_id );
355 2
		$post_has_shortcode = ! empty( $post->post_content ) ? gravityview_has_shortcode_r( $post->post_content, 'gravityview' ) : false;
356 2
		$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 2
		$this->setIsSearch( $this->is_searching() );
360
361 2
		unset( $entry, $post_id, $post_has_shortcode );
362 2
	}
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 2
	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 2
		if ( $this->getSingleEntry() ) {
384 2
			return false;
385
		}
386
387 2
		$search_method = GravityView_Widget_Search::getInstance()->get_search_method();
388
389 2
		if( 'post' === $search_method ) {
390
			$get = $_POST;
391
		} else {
392 2
			$get = $_GET;
393
		}
394
395
		// No $_GET parameters
396 2
		if ( empty( $get ) || ! is_array( $get ) ) {
397 2
			return false;
398
		}
399
400
		// Remove empty values
401 1
		$get = array_filter( $get );
402
403
		// If the $_GET parameters are empty, it's no search.
404 1
		if ( empty( $get ) ) {
405
			return false;
406
		}
407
408 1
		$search_keys = array_keys( $get );
409
410 1
		$search_match = implode( '|', self::$search_parameters );
411
412 1
		foreach ( $search_keys as $search_key ) {
413
414
			// Analyze the search key $_GET parameter and see if it matches known GV args
415 1
			if ( preg_match( '/(' . $search_match . ')/i', $search_key ) ) {
416
				return true;
417
			}
418
		}
419
420 1
		return false;
421
	}
422
423
	/**
424
	 * Filter the title for the single entry view
425
	 *
426
	 * @param  string $passed_title  Current title
427
	 * @param  int $passed_post_id Post ID
428
	 * @return string (modified) title
429
	 */
430 9
	public function single_entry_title( $passed_title, $passed_post_id = null ) {
431 9
		global $post;
432
433 9
		$gventry = gravityview()->request->is_entry();
434
435
		// If this is the directory view, return.
436 9
		if( ! $gventry ) {
437 8
			return $passed_title;
438
		}
439
440 1
		$entry = $gventry->as_entry();
441
442
		/**
443
		 * @filter `gravityview/single/title/out_loop` Apply the Single Entry Title filter outside the WordPress loop?
444
		 * @param boolean $in_the_loop Whether to apply the filter to the menu title and the meta tag <title> - outside the loop
445
		 * @param array $entry Current entry
446
		 */
447 1
		$apply_outside_loop = apply_filters( 'gravityview/single/title/out_loop', in_the_loop(), $entry );
448
449 1
		if ( ! $apply_outside_loop ) {
450 1
			return $passed_title;
451
		}
452
453
		// WooCommerce doesn't $post_id
454 1
		if ( empty( $passed_post_id ) )  {
455 1
			return $passed_title;
456
		}
457
458
		// Don't modify the title for anything other than the current view/post.
459
		// This is true for embedded shortcodes and Views.
460 1
		if ( is_object( $post ) && (int) $post->ID !== (int) $passed_post_id ) {
461 1
			return $passed_title;
462
		}
463
464 1
		$view = gravityview()->request->is_view();
465
466 1
		if( $view ) {
467 1
			return $this->_get_single_entry_title( $view, $entry, $passed_title );
468
		}
469
470 1
		$_gvid = \GV\Utils::_GET( 'gvid', null );
471
472
		// $_GET['gvid'] is set; we know what View to render
473 1
		if ( $_gvid ) {
474
475 1
			$view = \GV\View::by_id( $_gvid );
476
477 1
			return $this->_get_single_entry_title( $view, $entry, $passed_title );
478
		}
479
480 1
		global $post;
481
482 1
		if ( ! $post ) {
483
			return $passed_title;
484
		}
485
486 1
		$view_collection = \GV\View_Collection::from_post( $post );
487
488
		// We have multiple Views, but no gvid...this isn't valid security
489 1
		if( 1 < $view_collection->count() ) {
490 1
			return $passed_title;
491
		}
492
493
		return $this->_get_single_entry_title( $view_collection->first(), $entry, $passed_title );
494
	}
495
496
	/**
497
	 * Returns the single entry title for a View with variables replaced and shortcodes parsed
498
	 *
499
	 * @since 2.7.2
500
	 *
501
	 * @param \GV\View|null $view
502
	 * @param array $entry
503
	 * @param string $passed_title
504
	 *
505
	 * @return string
506
	 */
507
	private function _get_single_entry_title( $view, $entry = array(), $passed_title = '' ) {
508
509
		if ( ! $view ) {
510
			return $passed_title;
511
		}
512
513
		/**
514
		 * @filter `gravityview/single/title/check_entry_display` Override whether to check entry display rules against filters
515
		 * @internal This might change in the future! Don't rely on it.
516
		 * @since 2.7.2
517
		 * @param bool $check_entry_display Check whether the entry is visible for the current View configuration. Default: true.
518
		 * @param array $entry Gravity Forms entry array
519
		 * @param \GV\View $view The View
520
		 */
521
		$check_entry_display = apply_filters( 'gravityview/single/title/check_entry_display', true, $entry, $view );
522
523
		if( $check_entry_display ) {
524
525
			$check_display = GVCommon::check_entry_display( $entry, $view );
526
527
			if( is_wp_error( $check_display ) ) {
528
				return $passed_title;
529
			}
530
		}
531
532
		$title = $view->settings->get( 'single_title', $passed_title );
533
534
		$form = GVCommon::get_form( $entry['form_id'] );
535
536
		// We are allowing HTML in the fields, so no escaping the output
537
		$title = GravityView_API::replace_variables( $title, $form, $entry );
538
539
		$title = do_shortcode( $title );
540
541
		return $title;
542
	}
543
544
545
	/**
546
	 * In case View post is called directly, insert the view in the post content
547
	 *
548
	 * @deprecated Use \GV\View::content() instead.
549
	 *
550
	 * @access public
551
	 * @static
552
	 * @param mixed $content
553
	 * @return string Add the View output into View CPT content
554
	 */
555 4
	public function insert_view_in_content( $content ) {
556 4
		gravityview()->log->notice( '\GravityView_frontend::insert_view_in_content is deprecated. Use \GV\View::content()' );
557 4
		return \GV\View::content( $content );
558
	}
559
560
	/**
561
	 * Disable comments on GravityView post types
562
	 * @param  boolean $open    existing status
563
	 * @param  int $post_id Post ID
564
	 * @return boolean
565
	 */
566
	public function comments_open( $open, $post_id ) {
567
568
		if ( $this->isGravityviewPostType() ) {
569
			$open = false;
570
		}
571
572
		/**
573
		 * @filter `gravityview/comments_open` Whether to set comments to open or closed.
574
		 * @since  1.5.4
575
		 * @param  boolean $open Open or closed status
576
		 * @param  int $post_id Post ID to set comment status for
577
		 */
578
		$open = apply_filters( 'gravityview/comments_open', $open, $post_id );
579
580
		return $open;
581
	}
582
583
	/**
584
	 * Display a warning when a View has not been configured
585
	 *
586
	 * @since 1.19.2
587
	 *
588
	 * @param int $view_id The ID of the View currently being displayed
589
	 *
590
	 * @return void
591
	 */
592 2
	public function context_not_configured_warning( $view_id = 0 ) {
593
594 2
		if ( ! class_exists( 'GravityView_View' ) ) {
595
			return;
596
		}
597
598 2
		$fields = GravityView_View::getInstance()->getContextFields();
599
600 2
		if ( ! empty( $fields ) ) {
601 2
			return;
602
		}
603
604
		$context = GravityView_View::getInstance()->getContext();
605
606
		switch( $context ) {
607
			case 'directory':
608
				$tab = __( 'Multiple Entries', 'gravityview' );
609
				break;
610
			case 'edit':
611
				$tab = __( 'Edit Entry', 'gravityview' );
612
				break;
613
			case 'single':
614
			default:
615
				$tab = __( 'Single Entry', 'gravityview' );
616
				break;
617
		}
618
619
620
		$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 );
621
		$edit_link = admin_url( sprintf( 'post.php?post=%d&action=edit#%s-view', $view_id, $context ) );
622
		$action_text = sprintf( esc_html__('Add fields to %s', 'gravityview' ), $tab );
623
		$message = esc_html__( 'You can only see this message because you are able to edit this View.', 'gravityview' );
624
625
		$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 ) ) );
626
		$output = sprintf( '<h3>%s <strong><a href="%s">%s</a></strong></h3><p>%s</p>', $title, esc_url( $edit_link ), $action_text, $message );
627
628
		echo GVCommon::generate_notice( $output . $image, 'gv-error error', 'edit_gravityview', $view_id );
629
	}
630
631
632
	/**
633
	 * Core function to render a View based on a set of arguments
634
	 *
635
	 * @access public
636
	 * @static
637
	 * @param array $passed_args {
638
	 *
639
	 *      Settings for rendering the View
640
	 *
641
	 *      @type int $id View id
642
	 *      @type int $page_size Number of entries to show per page
643
	 *      @type string $sort_field Form field id to sort
644
	 *      @type string $sort_direction Sorting direction ('ASC', 'DESC', or 'RAND')
645
	 *      @type string $start_date - Ymd
646
	 *      @type string $end_date - Ymd
647
	 *      @type string $class - assign a html class to the view
648
	 *      @type string $offset (optional) - This is the start point in the current data set (0 index based).
649
	 * }
650
	 *
651
	 * @deprecated Use \GV\View_Renderer
652
	 *
653
	 * @return string|null HTML output of a View, NULL if View isn't found
654
	 */
655 1
	public function render_view( $passed_args ) {
656 1
		gravityview()->log->notice( '\GravityView_frontend::render_view is deprecated. Use \GV\View_Renderer etc.' );
657
658
		/**
659
		 * We can use a shortcode here, since it's pretty much the same.
660
		 *
661
		 * But we do need to check embed permissions, since shortcodes don't do this.
662
		 */
663
664 1
		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...
665
			return null;
666
		}
667
668 1
		$view->settings->update( $passed_args );
669
670 1
		$direct_access = apply_filters( 'gravityview_direct_access', true, $view->ID );
671 1
		$embed_only = $view->settings->get( 'embed_only' );
672
673 1
		if( ! $direct_access || ( $embed_only && ! GVCommon::has_cap( 'read_private_gravityviews' ) ) ) {
674 1
			return __( 'You are not allowed to view this content.', 'gravityview' );
675
		}
676
677 1
		$shortcode = new \GV\Shortcodes\gravityview();
678 1
		return $shortcode->callback( $passed_args );
679
	}
680
681
	/**
682
	 * Process the start and end dates for a view - overrides values defined in shortcode (if needed)
683
	 *
684
	 * The `start_date` and `end_date` keys need to be in a format processable by GFFormsModel::get_date_range_where(),
685
	 * which uses \DateTime() format.
686
	 *
687
	 * 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()},
688
	 * including strings like "now" or "-1 year" or "-3 days".
689
	 *
690
	 * @see GFFormsModel::get_date_range_where
691
	 *
692
	 * @param  array      $args            View settings
693
	 * @param  array      $search_criteria Search being performed, if any
694
	 * @return array                       Modified `$search_criteria` array
695
	 */
696 74
	public static function process_search_dates( $args, $search_criteria = array() ) {
697
698 74
		$return_search_criteria = $search_criteria;
699
700 74
		foreach ( array( 'start_date', 'end_date' ) as $key ) {
701
702
703
			// Is the start date or end date set in the view or shortcode?
704
			// If so, we want to make sure that the search doesn't go outside the bounds defined.
705 74
			if ( ! empty( $args[ $key ] ) ) {
706
707
				// Get a timestamp and see if it's a valid date format
708 2
				$date = strtotime( $args[ $key ] );
709
710
				// The date was invalid
711 2
				if ( empty( $date ) ) {
712
					gravityview()->log->error( ' Invalid {key} date format: {format}', array( 'key' => $key, 'format' => $args[ $key ] ) );
713
					continue;
714
				}
715
716
				// The format that Gravity Forms expects for start_date and day-specific (not hour/second-specific) end_date
717 2
				$datetime_format = 'Y-m-d H:i:s';
718 2
				$search_is_outside_view_bounds = false;
719
720 2
				if( ! empty( $search_criteria[ $key ] ) ) {
721
722 1
					$search_date = strtotime( $search_criteria[ $key ] );
723
724
					// The search is for entries before the start date defined by the settings
725 1
					switch ( $key ) {
726 1
						case 'end_date':
727
							/**
728
							 * If the end date is formatted as 'Y-m-d', it should be formatted without hours and seconds
729
							 * so that Gravity Forms can convert the day to 23:59:59 the previous day.
730
							 *
731
							 * If it's a relative date ("now" or "-1 day"), then it should use the precise date format
732
							 *
733
							 * @see GFFormsModel::get_date_range_where
734
							 */
735 1
							$datetime_format               = gravityview_is_valid_datetime( $args[ $key ] ) ? 'Y-m-d' : 'Y-m-d H:i:s';
736 1
							$search_is_outside_view_bounds = ( $search_date > $date );
737 1
							break;
738 1
						case 'start_date':
739 1
							$search_is_outside_view_bounds = ( $search_date < $date );
740 1
							break;
741
					}
742
				}
743
744
				// If there is no search being performed, or if there is a search being performed that's outside the bounds
745 2
				if ( empty( $search_criteria[ $key ] ) || $search_is_outside_view_bounds ) {
746
747
					// Then we override the search and re-set the start date
748 2
					$return_search_criteria[ $key ] = date_i18n( $datetime_format , $date, true );
749
				}
750
			}
751
		}
752
753 74
		if( isset( $return_search_criteria['start_date'] ) && isset( $return_search_criteria['end_date'] ) ) {
754
			// The start date is AFTER the end date. This will result in no results, but let's not force the issue.
755 2
			if ( strtotime( $return_search_criteria['start_date'] ) > strtotime( $return_search_criteria['end_date'] ) ) {
756 1
				gravityview()->log->error( 'Invalid search: the start date is after the end date.', array( 'data' => $return_search_criteria ) );
757
			}
758
		}
759
760 74
		return $return_search_criteria;
761
	}
762
763
764
	/**
765
	 * Process the approved only search criteria according to the View settings
766
	 *
767
	 * @param  array      $args            View settings
768
	 * @param  array      $search_criteria Search being performed, if any
769
	 * @return array                       Modified `$search_criteria` array
770
	 */
771 73
	public static function process_search_only_approved( $args, $search_criteria ) {
772
773
		/** @since 1.19 */
774 73
		if( ! empty( $args['admin_show_all_statuses'] ) && GVCommon::has_cap('gravityview_moderate_entries') ) {
775
			gravityview()->log->debug( 'User can moderate entries; showing all approval statuses' );
776
			return $search_criteria;
777
		}
778
779 73
		if ( ! empty( $args['show_only_approved'] ) ) {
780
781 6
			$search_criteria['field_filters'][] = array(
782
				'key' => GravityView_Entry_Approval::meta_key,
783
				'value' => GravityView_Entry_Approval_Status::APPROVED
784
			);
785
786 6
			$search_criteria['field_filters']['mode'] = 'all'; // force all the criterias to be met
787
788 6
			gravityview()->log->debug( '[process_search_only_approved] Search Criteria if show only approved: ', array( 'data' => $search_criteria ) );
789
		}
790
791 73
		return $search_criteria;
792
	}
793
794
795
	/**
796
	 * Check if a certain entry is approved.
797
	 *
798
	 * If we pass the View settings ($args) it will check the 'show_only_approved' setting before
799
	 *   checking the entry approved field, returning true if show_only_approved = false.
800
	 *
801
	 * @since 1.7
802
	 * @since 1.18 Converted check to use GravityView_Entry_Approval_Status::is_approved
803
	 *
804
	 * @uses GravityView_Entry_Approval_Status::is_approved
805
	 *
806
	 * @param array $entry  Entry object
807
	 * @param array $args   View settings (optional)
808
	 *
809
	 * @return bool
810
	 */
811
	public static function is_entry_approved( $entry, $args = array() ) {
812
813
		if ( empty( $entry['id'] ) || ( array_key_exists( 'show_only_approved', $args ) && ! $args['show_only_approved'] ) ) {
814
			// is implicitly approved if entry is null or View settings doesn't require to check for approval
815
			return true;
816
		}
817
818
		/** @since 1.19 */
819
		if( ! empty( $args['admin_show_all_statuses'] ) && GVCommon::has_cap('gravityview_moderate_entries') ) {
820
			gravityview()->log->debug( 'User can moderate entries, so entry is approved for viewing' );
821
			return true;
822
		}
823
824
		$is_approved = gform_get_meta( $entry['id'], GravityView_Entry_Approval::meta_key );
825
826
		return GravityView_Entry_Approval_Status::is_approved( $is_approved );
827
	}
828
829
	/**
830
	 * Parse search criteria for a entries search.
831
	 *
832
	 * array(
833
	 * 	'search_field' => 1, // ID of the field
834
	 *  'search_value' => '', // Value of the field to search
835
	 *  'search_operator' => 'contains', // 'is', 'isnot', '>', '<', 'contains'
836
	 *  'show_only_approved' => 0 or 1 // Boolean
837
	 * )
838
	 *
839
	 * @param  array $args    Array of args
840
	 * @param  int $form_id Gravity Forms form ID
841
	 * @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.
842
	 */
843 74
	public static function get_search_criteria( $args, $form_id ) {
844
		/**
845
		 * Compatibility with filters hooking in `gravityview_search_criteria` instead of `gravityview_fe_search_criteria`.
846
		 */
847 74
		$criteria = apply_filters( 'gravityview_search_criteria', array(), array( $form_id ), \GV\Utils::get( $args, 'id' ) );
848 74
		$search_criteria = isset( $criteria['search_criteria'] ) ? $criteria['search_criteria'] : array( 'field_filters' => array() );
849
850
		/**
851
		 * @filter `gravityview_fe_search_criteria` Modify the search criteria
852
		 * @see GravityView_Widget_Search::filter_entries Adds the default search criteria
853
		 * @param array $search_criteria Empty `field_filters` key
854
		 * @param int $form_id ID of the Gravity Forms form that is being searched
855
		 * @param array $args The View settings.
856
		 */
857 74
		$search_criteria = apply_filters( 'gravityview_fe_search_criteria', $search_criteria, $form_id, $args );
858
859 74
		if ( ! is_array( $search_criteria ) ) {
860
			return array();
861
		}
862
863 74
		$original_search_criteria = $search_criteria;
864
865 74
		gravityview()->log->debug( '[get_search_criteria] Search Criteria after hook gravityview_fe_search_criteria: ', array( 'data' =>$search_criteria ) );
866
867
		// implicity search
868 74
		if ( ! empty( $args['search_value'] ) ) {
869
870
			// Search operator options. Options: `is` or `contains`
871 3
			$operator = ! empty( $args['search_operator'] ) && in_array( $args['search_operator'], array( 'is', 'isnot', '>', '<', 'contains' ) ) ? $args['search_operator'] : 'contains';
872
873 3
			$search_criteria['field_filters'][] = array(
874 3
				'key' => \GV\Utils::_GET( 'search_field', \GV\Utils::get( $args, 'search_field' ) ), // The field ID to search
875 3
				'value' => _wp_specialchars( $args['search_value'] ), // The value to search. Encode ampersands but not quotes.
876 3
				'operator' => $operator,
877
			);
878
879
			// Lock search mode to "all" with implicit presearch filter.
880 3
			$search_criteria['field_filters']['mode'] = 'all';
881
		}
882
883 74
		if( $search_criteria !== $original_search_criteria ) {
884 3
			gravityview()->log->debug( '[get_search_criteria] Search Criteria after implicity search: ', array( 'data' => $search_criteria ) );
885
		}
886
887
		// Handle setting date range
888 74
		$search_criteria = self::process_search_dates( $args, $search_criteria );
889
890 74
		if( $search_criteria !== $original_search_criteria ) {
891 4
			gravityview()->log->debug( '[get_search_criteria] Search Criteria after date params: ', array( 'data' => $search_criteria ) );
892
		}
893
894
		// remove not approved entries
895 74
		$search_criteria = self::process_search_only_approved( $args, $search_criteria );
896
897
		/**
898
		 * @filter `gravityview_status` Modify entry status requirements to be included in search results.
899
		 * @param string $status Default: `active`. Accepts all Gravity Forms entry statuses, including `spam` and `trash`
900
		 */
901 74
		$search_criteria['status'] = apply_filters( 'gravityview_status', 'active', $args );
902
903 74
		return $search_criteria;
904
	}
905
906
907
908
	/**
909
	 * Core function to calculate View multi entries (directory) based on a set of arguments ($args):
910
	 *   $id - View id
911
	 *   $page_size - Page
912
	 *   $sort_field - form field id to sort
913
	 *   $sort_direction - ASC / DESC
914
	 *   $start_date - Ymd
915
	 *   $end_date - Ymd
916
	 *   $class - assign a html class to the view
917
	 *   $offset (optional) - This is the start point in the current data set (0 index based).
918
	 *
919
	 *
920
	 *
921
	 * @uses  gravityview_get_entries()
922
	 * @access public
923
	 * @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...
924
	 *   - $id - View id
925
	 *   - $page_size - Page
926
	 *   - $sort_field - form field id to sort
927
	 *   - $sort_direction - ASC / DESC
928
	 *   - $start_date - Ymd
929
	 *   - $end_date - Ymd
930
	 *   - $class - assign a html class to the view
931
	 *   - $offset (optional) - This is the start point in the current data set (0 index based).
932
	 * @param int $form_id Gravity Forms Form ID
933
	 * @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
934
	 */
935 1
	public static function get_view_entries( $args, $form_id ) {
936
937 1
		gravityview()->log->debug( '[get_view_entries] init' );
938
		// start filters and sorting
939
940 1
		$parameters = self::get_view_entries_parameters( $args, $form_id );
941
942 1
		$count = 0; // Must be defined so that gravityview_get_entries can use by reference
943
944
		// fetch entries
945
		list( $entries, $paging, $count ) =
946 1
			\GV\Mocks\GravityView_frontend_get_view_entries( $args, $form_id, $parameters, $count );
947
948 1
		gravityview()->log->debug( 'Get Entries. Found: {count} entries', array( 'count' => $count, 'data' => $entries ) );
949
950
		/**
951
		 * @filter `gravityview_view_entries` Filter the entries output to the View
952
		 * @deprecated since 1.5.2
953
		 * @param array $args View settings associative array
954
		 * @var array
955
		 */
956 1
		$entries = apply_filters( 'gravityview_view_entries', $entries, $args );
957
958
		$return = array(
959 1
			'count' => $count,
960 1
			'entries' => $entries,
961 1
			'paging' => $paging,
962
		);
963
964
		/**
965
		 * @filter `gravityview/view/entries` Filter the entries output to the View
966
		 * @param array $criteria associative array containing count, entries & paging
967
		 * @param array $args View settings associative array
968
		 * @since 1.5.2
969
		 */
970 1
		return apply_filters( 'gravityview/view/entries', $return, $args );
971
	}
972
973
	/**
974
	 * Get an array of search parameters formatted as Gravity Forms requires
975
	 *
976
	 * Results are filtered by `gravityview_get_entries` and `gravityview_get_entries_{View ID}` filters
977
	 *
978
	 * @uses GravityView_frontend::get_search_criteria
979
	 * @uses GravityView_frontend::get_search_criteria_paging
980
	 *
981
	 * @since 1.20
982
	 *
983
	 * @see \GV\View_Settings::defaults For $args options
984
	 *
985
	 * @param array $args Array of View settings, as structured in \GV\View_Settings::defaults
986
	 * @param int $form_id Gravity Forms form ID to search
987
	 *
988
	 * @return array With `search_criteria`, `sorting`, `paging`, `cache` keys
989
	 */
990 73
	public static function get_view_entries_parameters( $args = array(), $form_id = 0 ) {
991
992
993 73
		if ( ! is_array( $args ) || ! is_numeric( $form_id ) ) {
994
995
			gravityview()->log->error( 'Passed args are not an array or the form ID is not numeric' );
996
997
			return array();
998
		}
999
1000 73
		$form_id = intval( $form_id );
1001
1002
		/**
1003
		 * Process search parameters
1004
		 * @var array
1005
		 */
1006 73
		$search_criteria = self::get_search_criteria( $args, $form_id );
1007
1008 73
		$paging = self::get_search_criteria_paging( $args );
1009
1010
		$parameters = array(
1011 73
			'search_criteria' => $search_criteria,
1012 73
			'sorting' => self::updateViewSorting( $args, $form_id ),
1013 73
			'paging' => $paging,
1014 73
			'cache' => isset( $args['cache'] ) ? $args['cache'] : true,
1015
		);
1016
1017
		/**
1018
		 * @filter `gravityview_get_entries` Filter get entries criteria
1019
		 * @param array $parameters Array with `search_criteria`, `sorting` and `paging` keys.
1020
		 * @param array $args View configuration args. {
1021
		 *      @type int $id View id
1022
		 *      @type int $page_size Number of entries to show per page
1023
		 *      @type string $sort_field Form field id to sort
1024
		 *      @type string $sort_direction Sorting direction ('ASC', 'DESC', or 'RAND')
1025
		 *      @type string $start_date - Ymd
1026
		 *      @type string $end_date - Ymd
1027
		 *      @type string $class - assign a html class to the view
1028
		 *      @type string $offset (optional) - This is the start point in the current data set (0 index based).
1029
		 * }
1030
		 * @param int $form_id ID of Gravity Forms form
1031
		 */
1032 73
		$parameters = apply_filters( 'gravityview_get_entries', $parameters, $args, $form_id );
1033
1034
		/**
1035
		 * @filter `gravityview_get_entries_{View ID}` Filter get entries criteria
1036
		 * @param array $parameters Array with `search_criteria`, `sorting` and `paging` keys.
1037
		 * @param array $args View configuration args.
1038
		 */
1039 73
		$parameters = apply_filters( 'gravityview_get_entries_'.\GV\Utils::get( $args, 'id' ), $parameters, $args, $form_id );
1040
1041 73
		gravityview()->log->debug( '$parameters passed to gravityview_get_entries(): ', array( 'data' => $parameters ) );
1042
1043 73
		return $parameters;
1044
	}
1045
1046
	/**
1047
	 * Get the paging array for the View
1048
	 *
1049
	 * @since 1.19.5
1050
	 *
1051
	 * @param $args
1052
	 * @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...
1053
	 */
1054 73
	public static function get_search_criteria_paging( $args ) {
1055
1056
		/**
1057
		 * @filter `gravityview_default_page_size` The default number of entries displayed in a View
1058
		 * @since 1.1.6
1059
		 * @param int $default_page_size Default: 25
1060
		 */
1061 73
		$default_page_size = apply_filters( 'gravityview_default_page_size', 25 );
1062
1063
		// Paging & offset
1064 73
		$page_size = ! empty( $args['page_size'] ) ? intval( $args['page_size'] ) : $default_page_size;
1065
1066 73
		if ( -1 === $page_size ) {
1067 1
			$page_size = PHP_INT_MAX;
1068
		}
1069
1070 73
		$curr_page = empty( $_GET['pagenum'] ) ? 1 : intval( $_GET['pagenum'] );
1071 73
		$offset = ( $curr_page - 1 ) * $page_size;
1072
1073 73
		if ( ! empty( $args['offset'] ) ) {
1074
			$offset += intval( $args['offset'] );
1075
		}
1076
1077
		$paging = array(
1078 73
			'offset' => $offset,
1079 73
			'page_size' => $page_size,
1080
		);
1081
1082 73
		gravityview()->log->debug( 'Paging: ', array( 'data' => $paging ) );
1083
1084 73
		return $paging;
1085
	}
1086
1087
	/**
1088
	 * Updates the View sorting criteria
1089
	 *
1090
	 * @since 1.7
1091
	 *
1092
	 * @param array $args View settings. Required to have `sort_field` and `sort_direction` keys
1093
	 * @param int $form_id The ID of the form used to sort
1094
	 * @return array $sorting Array with `key`, `direction` and `is_numeric` keys
1095
	 */
1096 73
	public static function updateViewSorting( $args, $form_id ) {
1097 73
		$sorting = array();
1098
1099 73
		$has_values = isset( $_GET['sort'] );
1100
1101 73
		if ( $has_values && is_array( $_GET['sort'] ) ) {
1102 2
			$sorts = array_keys( $_GET['sort'] );
1103 2
			$dirs  = array_values( $_GET['sort'] );
1104
1105 2
			if ( $has_values = array_filter( $dirs ) ) {
1106 2
				$sort_field_id = end( $sorts );
1107 2
				$sort_direction = end( $dirs );
1108
			}
1109
		}
1110
1111 73
		if ( ! isset( $sort_field_id ) ) {
1112 73
			$sort_field_id = isset( $_GET['sort'] ) ? $_GET['sort'] : \GV\Utils::get( $args, 'sort_field' );
1113
		}
1114
1115 73
		if ( ! isset( $sort_direction ) ) {
1116 73
			$sort_direction = isset( $_GET['dir'] ) ? $_GET['dir'] : \GV\Utils::get( $args, 'sort_direction' );
1117
		}
1118
1119 73
		if ( is_array( $sort_field_id ) ) {
1120 1
			$sort_field_id = array_pop( $sort_field_id );
1121
		}
1122
1123 73
		if ( is_array( $sort_direction ) ) {
1124
			$sort_direction = array_pop( $sort_direction );
1125
		}
1126
1127 73
		if ( ! empty( $sort_field_id ) ) {
1128 5
			if ( is_array( $sort_field_id ) ) {
1129
				$sort_direction = array_values( $sort_field_id );
1130
				$sort_field_id = array_keys( $sort_field_id );
1131
1132
				$sort_field_id = reset( $sort_field_id );
1133
				$sort_direction = reset( $sort_direction );
1134
			}
1135
1136 5
			$sort_field_id = self::_override_sorting_id_by_field_type( $sort_field_id, $form_id );
1137
			$sorting = array(
1138 5
				'key' => $sort_field_id,
1139 5
				'direction' => strtolower( $sort_direction ),
1140 5
				'is_numeric' => GVCommon::is_field_numeric( $form_id, $sort_field_id )
1141
			);
1142
1143 5
			if ( 'RAND' === $sort_direction ) {
1144
1145
				$form = GFAPI::get_form( $form_id );
1146
1147
				// Get the first GF_Field field ID, set as the key for entry randomization
1148
				if ( ! empty( $form['fields'] ) ) {
1149
1150
					/** @var GF_Field $field */
1151
					foreach ( $form['fields'] as $field ) {
1152
						if ( ! is_a( $field, 'GF_Field' ) ) {
1153
							continue;
1154
						}
1155
1156
						$sorting = array(
1157
							'key'        => $field->id,
1158
							'is_numeric' => false,
1159
							'direction'  => 'RAND',
1160
						);
1161
1162
						break;
1163
					}
1164
				}
1165
			}
1166
		}
1167
1168 73
		GravityView_View::getInstance()->setSorting( $sorting );
1169
1170 73
		gravityview()->log->debug( '[updateViewSorting] Sort Criteria : ', array( 'data' => $sorting ) );
1171
1172 73
		return $sorting;
1173
1174
	}
1175
1176
	/**
1177
	 * Override sorting per field
1178
	 *
1179
	 * Currently only modifies sorting ID when sorting by the full name. Sorts by first name.
1180
	 * Use the `gravityview/sorting/full-name` filter to override.
1181
	 *
1182
	 * @todo Filter from GravityView_Field
1183
	 * @since 1.7.4
1184
	 * @internal Hi developer! Although this is public, don't call this method; we're going to replace it.
1185
	 *
1186
	 * @param int|string|array $sort_field_id Field used for sorting (`id` or `1.2`), or an array for multisorts
1187
	 * @param int $form_id GF Form ID
1188
	 *
1189
	 * @return string Possibly modified sorting ID
1190
	 */
1191 5
	public static function _override_sorting_id_by_field_type( $sort_field_id, $form_id ) {
1192
1193 5
		if ( is_array( $sort_field_id ) ) {
1194
			$modified_ids = array();
1195
			foreach ( $sort_field_id as $_sort_field_id ) {
1196
				$modified_ids []= self::_override_sorting_id_by_field_type( $_sort_field_id, $form_id );
1197
			}
1198
			return $modified_ids;
1199
		}
1200
1201 5
		$form = gravityview_get_form( $form_id );
1202
1203 5
		$sort_field = GFFormsModel::get_field( $form, $sort_field_id );
1204
1205 5
		if( ! $sort_field ) {
1206
			return $sort_field_id;
1207
		}
1208
1209 5
		switch ( $sort_field['type'] ) {
1210
1211 5
			case 'address':
1212
				// Sorting by full address
1213
				if ( floatval( $sort_field_id ) === floor( $sort_field_id ) ) {
1214
1215
					/**
1216
					 * Override how to sort when sorting address
1217
					 *
1218
					 * @since 1.8
1219
					 *
1220
					 * @param string $address_part `street`, `street2`, `city`, `state`, `zip`, or `country` (default: `city`)
1221
					 * @param string $sort_field_id Field used for sorting
1222
					 * @param int $form_id GF Form ID
1223
					 */
1224
					$address_part = apply_filters( 'gravityview/sorting/address', 'city', $sort_field_id, $form_id );
1225
1226
					switch( strtolower( $address_part ) ){
1227
						case 'street':
1228
							$sort_field_id .= '.1';
1229
							break;
1230
						case 'street2':
1231
							$sort_field_id .= '.2';
1232
							break;
1233
						default:
1234
						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...
1235
							$sort_field_id .= '.3';
1236
							break;
1237
						case 'state':
1238
							$sort_field_id .= '.4';
1239
							break;
1240
						case 'zip':
1241
							$sort_field_id .= '.5';
1242
							break;
1243
						case 'country':
1244
							$sort_field_id .= '.6';
1245
							break;
1246
					}
1247
1248
				}
1249
				break;
1250 5
			case 'name':
1251
				// Sorting by full name, not first, last, etc.
1252
				if ( floatval( $sort_field_id ) === floor( $sort_field_id ) ) {
1253
					/**
1254
					 * @filter `gravityview/sorting/full-name` Override how to sort when sorting full name.
1255
					 * @since 1.7.4
1256
					 * @param[in,out] string $name_part Sort by `first` or `last` (default: `first`)
1257
					 * @param[in] string $sort_field_id Field used for sorting
1258
					 * @param[in] int $form_id GF Form ID
1259
					 */
1260
					$name_part = apply_filters( 'gravityview/sorting/full-name', 'first', $sort_field_id, $form_id );
1261
1262
					if ( 'last' === strtolower( $name_part ) ) {
1263
						$sort_field_id .= '.6';
1264
					} else {
1265
						$sort_field_id .= '.3';
1266
					}
1267
				}
1268
				break;
1269 5
			case 'list':
1270
				$sort_field_id = false;
1271
				break;
1272 5
			case 'time':
1273
1274
				/**
1275
				 * @filter `gravityview/sorting/time` Override how to sort when sorting time
1276
				 * @see GravityView_Field_Time
1277
				 * @since 1.14
1278
				 * @param[in,out] string $name_part Field used for sorting
1279
				 * @param[in] int $form_id GF Form ID
1280
				 */
1281 1
				$sort_field_id = apply_filters( 'gravityview/sorting/time', $sort_field_id, $form_id );
1282 1
				break;
1283
		}
1284
1285 5
		return $sort_field_id;
1286
	}
1287
1288
	/**
1289
	 * Verify if user requested a single entry view
1290
	 * @since 2.3.3 Added return null
1291
	 * @return boolean|string|null false if not, single entry slug if true, null if \GV\Entry doesn't exist yet
1292
	 */
1293 26
	public static function is_single_entry() {
1294
1295
		// Since this is a public method, it can be called outside of the plugin. Don't assume things have been loaded properly.
1296 26
		if ( ! class_exists( '\GV\Entry' ) ) {
1297
1298
			// Not using gravityview()->log->error(), since that may not exist yet either!
1299
			do_action( 'gravityview_log_error', '\GV\Entry not defined yet. Backtrace: ' . wp_debug_backtrace_summary()  );
1300
1301
			return null;
1302
		}
1303
1304 26
		$var_name = \GV\Entry::get_endpoint_name();
1305
1306 26
		$single_entry = get_query_var( $var_name );
1307
1308
		/**
1309
		 * Modify the entry that is being displayed.
1310
		 *
1311
		 * @internal Should only be used by things like the oEmbed functionality.
1312
		 * @since 1.6
1313
		 */
1314 26
		$single_entry = apply_filters( 'gravityview/is_single_entry', $single_entry );
1315
1316 26
		if ( empty( $single_entry ) ){
1317 4
			return false;
1318
		} else {
1319 22
			return $single_entry;
1320
		}
1321
	}
1322
1323
1324
	/**
1325
	 * Register styles and scripts
1326
	 *
1327
	 * @access public
1328
	 * @return void
1329
	 */
1330 1
	public function add_scripts_and_styles() {
1331 1
		global $post, $posts;
1332
		// enqueue template specific styles
1333 1
		if ( $this->getGvOutputData() ) {
1334
1335 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...
1336
1337 1
			foreach ( $views as $view_id => $data ) {
1338 1
				$view = \GV\View::by_id( $data['id'] );
1339 1
				$view_id = $view->ID;
1340 1
				$template_id = gravityview_get_template_id( $view->ID );
1341 1
				$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...
1342
1343
				/**
1344
				 * Don't enqueue the scripts or styles if it's not going to be displayed.
1345
				 * @since 1.15
1346
				 */
1347 1
				if( is_user_logged_in() && false === GVCommon::has_cap( 'read_gravityview', $view_id ) ) {
1348
					continue;
1349
				}
1350
1351
				// By default, no thickbox
1352 1
				$js_dependencies = array( 'jquery', 'gravityview-jquery-cookie' );
1353 1
				$css_dependencies = array();
1354
1355 1
				$lightbox = $view->settings->get( 'lightbox' );
1356
1357
				// If the thickbox is enqueued, add dependencies
1358 1
				if ( $lightbox ) {
1359
1360 1
					global $wp_filter;
1361
1362 1
					if ( ! empty( $wp_filter[ 'gravity_view_lightbox_script' ] ) ) {
1363
						gravityview()->log->warning( 'gravity_view_lightbox_script filter is deprecated use gravityview_lightbox_script instead' );
1364
					}
1365
1366
					/**
1367
					 * @filter `gravity_view_lightbox_script` Override the lightbox script to enqueue. Default: `thickbox`
1368
					 * @param string $script_slug If you want to use a different lightbox script, return the name of it here.
1369
					 * @deprecated 2.5.1 Naming. See `gravityview_lightbox_script` instead.
1370
					 */
1371 1
					$js_dependency = apply_filters( 'gravity_view_lightbox_script', 'thickbox' );
1372
1373
					/**
1374
					 * @filter `gravityview_lightbox_script` Override the lightbox script to enqueue. Default: `thickbox`
1375
					 * @since 2.5.1
1376
					 * @param string $script_slug If you want to use a different lightbox script, return the name of it here.
1377
					 * @param \GV\View The View.
1378
					 */
1379 1
					apply_filters( 'gravityview_lightbox_script', $js_dependency, $view );
1380 1
					$js_dependencies[] = $js_dependency;
1381
1382 1
					if ( ! empty( $wp_filter[ 'gravity_view_lightbox_style' ] ) ) {
1383
						gravityview()->log->warning( 'gravity_view_lightbox_style filter is deprecated use gravityview_lightbox_style instead' );
1384
					}
1385
1386
					/**
1387
					 * @filter `gravity_view_lightbox_style` Modify the lightbox CSS slug. Default: `thickbox`
1388
					 * @param string $script_slug If you want to use a different lightbox script, return the name of its CSS file here.
1389
					 * @deprecated 2.5.1 Naming. See `gravityview_lightbox_style` instead.
1390
					 */
1391 1
					$css_dependency = apply_filters( 'gravity_view_lightbox_style', 'thickbox' );
1392
1393
					/**
1394
					 * @filter `gravityview_lightbox_script` Override the lightbox script to enqueue. Default: `thickbox`
1395
					 * @since 2.5.1
1396
					 * @param string $script_slug If you want to use a different lightbox script, return the name of it here.
1397
					 * @param \GV\View The View.
1398
					 */
1399 1
					$css_dependency = apply_filters( 'gravityview_lightbox_style', $css_dependency, $view );
1400 1
					$css_dependencies[] = $css_dependency;
1401
				}
1402
1403
				/**
1404
				 * If the form has checkbox fields, enqueue dashicons
1405
				 * @see https://github.com/katzwebservices/GravityView/issues/536
1406
				 * @since 1.15
1407
				 */
1408 1
				if( gravityview_view_has_single_checkbox_or_radio( $data['form'], $data['fields'] ) ) {
1409
					$css_dependencies[] = 'dashicons';
1410
				}
1411
1412 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...
1413
1414 1
				$script_debug = ( defined( 'SCRIPT_DEBUG' ) && SCRIPT_DEBUG ) ? '' : '.min';
1415
1416 1
				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...
1417
1418 1
				wp_enqueue_script( 'gravityview-fe-view' );
1419
1420 1
				if ( ! empty( $data['atts']['sort_columns'] ) ) {
1421
					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...
1422
				}
1423
1424 1
				$this->enqueue_default_style( $css_dependencies );
1425
1426 1
				self::add_style( $template_id );
1427
			}
1428
1429 1
			if ( 'wp_print_footer_scripts' === current_filter() ) {
1430
1431
				$js_localization = array(
1432
					'cookiepath' => COOKIEPATH,
1433
					'clear' => _x( 'Clear', 'Clear all data from the form', 'gravityview' ),
1434
					'reset' => _x( 'Reset', 'Reset the search form to the state that existed on page load', 'gravityview' ),
1435
				);
1436
1437
				/**
1438
				 * @filter `gravityview_js_localization` Modify the array passed to wp_localize_script()
1439
				 * @param array $js_localization The data padded to the Javascript file
1440
				 * @param array $views Array of View data arrays with View settings
1441
				 */
1442
				$js_localization = apply_filters( 'gravityview_js_localization', $js_localization, $views );
1443
1444
				wp_localize_script( 'gravityview-fe-view', 'gvGlobals', $js_localization );
1445
			}
1446
		}
1447 1
	}
1448
1449
	/**
1450
	 * Handle enqueuing the `gravityview_default_style` stylesheet
1451
	 *
1452
	 * @since 1.17
1453
	 *
1454
	 * @param array $css_dependencies Dependencies for the `gravityview_default_style` stylesheet
1455
	 *
1456
	 * @return void
1457
	 */
1458
	private function enqueue_default_style( $css_dependencies = array() ) {
1459
1460
		/**
1461
		 * @filter `gravityview_use_legacy_search_css` Should GravityView use the legacy Search Bar stylesheet (from before Version 1.17)?
1462
		 * @since 1.17
1463
		 * @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`
1464
		 */
1465
		$use_legacy_search_style = apply_filters( 'gravityview_use_legacy_search_style', false );
1466
1467
		$rtl = is_rtl() ? '-rtl' : '';
1468
1469
		$css_file_base = $use_legacy_search_style ? 'gv-legacy-search' : 'gv-default-styles';
1470
1471
		$path = gravityview_css_url( $css_file_base . $rtl . '.css' );
1472
1473
		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...
1474
	}
1475
1476
	/**
1477
	 * Add template extra style if exists
1478
	 * @param string $template_id
1479
	 */
1480
	public static function add_style( $template_id ) {
1481
1482
		if ( ! empty( $template_id ) && wp_style_is( 'gravityview_style_' . $template_id, 'registered' ) ) {
1483
			gravityview()->log->debug(  'Adding extra template style for {template_id}', array( 'template_id' => $template_id ) );
1484
			wp_enqueue_style( 'gravityview_style_' . $template_id );
1485
		} elseif ( empty( $template_id ) ) {
1486
			gravityview()->log->error( 'Cannot add template style; template_id is empty' );
1487
		} else {
1488
			gravityview()->log->error( 'Cannot add template style; {template_id} is not registered', array( 'template_id' => 'gravityview_style_' . $template_id ) );
1489
		}
1490
1491
	}
1492
1493
1494
	/**
1495
	 * Inject the sorting links on the table columns
1496
	 *
1497
	 * Callback function for hook 'gravityview/template/field_label'
1498
	 * @see GravityView_API::field_label() (in includes/class-api.php)
1499
	 *
1500
	 * @since 1.7
1501
	 *
1502
	 * @param string $label Field label
1503
	 * @param array $field Field settings
1504
	 * @param array $form Form object
1505
	 *
1506
	 * @return string Field Label
1507
	 */
1508
	public function add_columns_sort_links( $label = '', $field, $form ) {
1509
1510
		/**
1511
		 * Not a table-based template; don't add sort icons
1512
		 * @since 1.12
1513
		 */
1514
		if( ! preg_match( '/table/ism', GravityView_View::getInstance()->getTemplatePartSlug() ) ) {
1515
			return $label;
1516
		}
1517
1518
		if ( ! $this->is_field_sortable( $field['id'], $form ) ) {
1519
			return $label;
1520
		}
1521
1522
		$sorting = GravityView_View::getInstance()->getSorting();
1523
1524
		$class = 'gv-sort';
1525
1526
		$sort_field_id = self::_override_sorting_id_by_field_type( $field['id'], $form['id'] );
1527
1528
		$sort_args = array(
1529
			'sort' => $field['id'],
1530
			'dir' => 'asc',
1531
		);
1532
1533
		if ( ! empty( $sorting['key'] ) && (string) $sort_field_id === (string) $sorting['key'] ) {
1534
			//toggle sorting direction.
1535
			if ( 'asc' === $sorting['direction'] ) {
1536
				$sort_args['dir'] = 'desc';
1537
				$class .= ' gv-icon-sort-desc';
1538
			} else {
1539
				$sort_args['dir'] = 'asc';
1540
				$class .= ' gv-icon-sort-asc';
1541
			}
1542
		} else {
1543
			$class .= ' gv-icon-caret-up-down';
1544
		}
1545
1546
		$url = add_query_arg( $sort_args, remove_query_arg( array('pagenum') ) );
1547
1548
		return '<a href="'. esc_url_raw( $url ) .'" class="'. $class .'" ></a>&nbsp;'. $label;
1549
1550
	}
1551
1552
	/**
1553
	 * Checks if field (column) is sortable
1554
	 *
1555
	 * @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...
1556
	 * @param array $form Gravity Forms form array
1557
	 *
1558
	 * @since 1.7
1559
	 *
1560
	 * @return bool True: Yes, field is sortable; False: not sortable
1561
	 */
1562 1
	public function is_field_sortable( $field_id = '', $form = array() ) {
1563
1564 1
		$field_type = $field_id;
1565
1566 1
		if( is_numeric( $field_id ) ) {
1567 1
			$field = GFFormsModel::get_field( $form, $field_id );
1568 1
			$field_type = $field ? $field->type : $field_id;
1569
		}
1570
1571
		$not_sortable = array(
1572 1
			'edit_link',
1573
			'delete_link',
1574
		);
1575
1576
		/**
1577
		 * @filter `gravityview/sortable/field_blacklist` Modify what fields should never be sortable.
1578
		 * @since 1.7
1579
		 * @param[in,out] array $not_sortable Array of field types that aren't sortable
1580
		 * @param string $field_type Field type to check whether the field is sortable
1581
		 * @param array $form Gravity Forms form
1582
		 */
1583 1
		$not_sortable = apply_filters( 'gravityview/sortable/field_blacklist', $not_sortable, $field_type, $form );
1584
1585 1
		if ( in_array( $field_type, $not_sortable ) ) {
1586
			return false;
1587
		}
1588
1589 1
		return apply_filters( "gravityview/sortable/formfield_{$form['id']}_{$field_id}", apply_filters( "gravityview/sortable/field_{$field_id}", true, $form ) );
1590
1591
	}
1592
1593
}
1594
1595
GravityView_frontend::getInstance();
1596
1597
1598
1599