Completed
Pull Request — master (#664)
by Zack
07:00 queued 03:02
created

add_datepicker_js_dependency()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 6
Code Lines 3

Duplication

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

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

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

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

Loading history...
2
/**
3
 * The GravityView New Search widget
4
 *
5
 * @package   GravityView-DataTables-Ext
6
 * @license   GPL2+
7
 * @author    Katz Web Services, Inc.
8
 * @link      http://gravityview.co
9
 * @copyright Copyright 2014, Katz Web Services, Inc.
10
 */
11
12
if ( ! defined( 'WPINC' ) ) {
13
	die;
14
}
15
16
class GravityView_Widget_Search extends GravityView_Widget {
17
18
	public static $file;
19
	public static $instance;
20
21
	private $search_filters = array();
0 ignored issues
show
Unused Code introduced by
The property $search_filters is not used and could be removed.

This check marks private properties in classes that are never used. Those properties can be removed.

Loading history...
22
23
	/**
24
	 * whether search method is GET or POST ( default: GET )
25
	 * @since 1.16.4
26
	 * @var string
27
	 */
28
	private $search_method = 'get';
29
30
	public function __construct() {
31
32
		$this->widget_description = esc_html__( 'Search form for searching entries.', 'gravityview' );
33
34
		self::$instance = &$this;
35
36
		self::$file = plugin_dir_path( __FILE__ );
37
38
		$default_values = array( 'header' => 0, 'footer' => 0 );
39
40
		$settings = array(
41
			'search_layout' => array(
42
				'type' => 'radio',
43
				'full_width' => true,
44
				'label' => esc_html__( 'Search Layout', 'gravityview' ),
45
				'value' => 'horizontal',
46
				'options' => array(
47
					'horizontal' => esc_html__( 'Horizontal', 'gravityview' ),
48
					'vertical' => esc_html__( 'Vertical', 'gravityview' ),
49
				),
50
			),
51
			'search_clear' => array(
52
				'type' => 'checkbox',
53
				'label' => __( 'Show Clear button', 'gravityview' ),
54
				'value' => false,
55
			),
56
			'search_fields' => array(
57
				'type' => 'hidden',
58
				'label' => '',
59
				'class' => 'gv-search-fields-value',
60
				'value' => '[{"field":"search_all","input":"input_text"}]', // Default: Search Everything text box
61
			),
62
			'search_mode' => array(
63
				'type' => 'radio',
64
				'full_width' => true,
65
				'label' => esc_html__( 'Search Mode', 'gravityview' ),
66
				'desc' => __('Should search results match all search fields, or any?', 'gravityview'),
0 ignored issues
show
Coding Style introduced by
Expected 1 spaces after opening bracket; 0 found
Loading history...
Coding Style introduced by
Expected 1 spaces before closing bracket; 0 found
Loading history...
67
				'value' => 'any',
68
				'class' => 'hide-if-js',
69
				'options' => array(
70
					'any' => esc_html__( 'Match Any Fields', 'gravityview' ),
71
					'all' => esc_html__( 'Match All Fields', 'gravityview' ),
72
				),
73
			),
74
		);
75
		parent::__construct( esc_html__( 'Search Bar', 'gravityview' ), 'search_bar', $default_values, $settings );
76
77
		// frontend - filter entries
78
		add_filter( 'gravityview_fe_search_criteria', array( $this, 'filter_entries' ), 10, 1 );
79
80
		// frontend - add template path
81
		add_filter( 'gravityview_template_paths', array( $this, 'add_template_path' ) );
82
83
		// Add hidden fields for "Default" permalink structure
84
		add_filter( 'gravityview_widget_search_filters', array( $this, 'add_no_permalink_fields' ), 10, 3 );
85
86
		// admin - add scripts - run at 1100 to make sure GravityView_Admin_Views::add_scripts_and_styles() runs first at 999
87
		add_action( 'admin_enqueue_scripts', array( $this, 'add_scripts_and_styles' ), 1100 );
88
		add_filter( 'gravityview_noconflict_scripts', array( $this, 'register_no_conflict' ) );
89
90
		// ajax - get the searchable fields
91
		add_action( 'wp_ajax_gv_searchable_fields', array( 'GravityView_Widget_Search', 'get_searchable_fields' ) );
92
93
		// calculate the search method (POST / GET)
94
		$this->set_search_method();
95
96
	}
97
98
	/**
99
	 * @return GravityView_Widget_Search
100
	 */
101
	public static function getInstance() {
0 ignored issues
show
Coding Style introduced by
The function name getInstance is in camel caps, but expected get_instance instead as per the coding standard.
Loading history...
102
		if ( empty( self::$instance ) ) {
103
			self::$instance = new GravityView_Widget_Search;
104
		}
105
		return self::$instance;
106
	}
107
108
	/**
109
	 * Sets the search method to GET (default) or POST
110
	 * @since 1.16.4
111
	 */
112
	private function set_search_method() {
113
		/**
114
		 * @filter `gravityview/search/method` Modify the search form method (GET / POST)
115
		 * @since 1.16.4
116
		 * @param string $search_method Assign an input type according to the form field type. Defaults: `boolean`, `multi`, `select`, `date`, `text`
117
		 * @param string $field_type Gravity Forms field type (also the `name` parameter of GravityView_Field classes)
118
		 */
119
		$method = apply_filters( 'gravityview/search/method', $this->search_method );
120
121
		$method = strtolower( $method );
122
123
		$this->search_method = in_array( $method, array( 'get', 'post' ) ) ? $method : 'get';
124
	}
125
126
	/**
127
	 * Returns the search method
128
	 * @since 1.16.4
129
	 * @return string
130
	 */
131
	public function get_search_method() {
132
		return $this->search_method;
133
	}
134
135
136
	/**
137
	 * Add script to Views edit screen (admin)
138
	 * @param  mixed $hook
139
	 */
140
	public function add_scripts_and_styles( $hook ) {
141
		global $pagenow;
0 ignored issues
show
Compatibility Best Practice introduced by
Use of global functionality is not recommended; it makes your code harder to test, and less reusable.

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

1. Pass all data via parameters

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

2. Create a class that maintains your state

class MyClass {
    private $a;
    private $b;

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

    public function myFunction() {
        // Do something
    }
}
Loading history...
142
143
		// Don't process any scripts below here if it's not a GravityView page or the widgets screen
144
		if ( ! gravityview_is_admin_page( $hook ) && ( 'widgets.php' !== $pagenow ) ) {
145
			return;
146
		}
147
148
		$script_min = ( defined( 'SCRIPT_DEBUG' ) && SCRIPT_DEBUG ) ? '' : '.min';
149
		$script_source = empty( $script_min ) ? '/source' : '';
150
151
		wp_enqueue_script( 'gravityview_searchwidget_admin', plugins_url( 'assets/js'.$script_source.'/admin-search-widget'.$script_min.'.js', __FILE__ ), array( 'jquery', 'gravityview_views_scripts' ), GravityView_Plugin::version );
152
0 ignored issues
show
Coding Style introduced by
Functions must not contain multiple empty lines in a row; found 2 empty lines
Loading history...
153
154
		/**
155
		 * Input Type labels l10n
156
		 * @see admin-search-widget.js (getSelectInput)
157
		 * @var array
158
		 */
159
		$input_labels = array(
160
			'input_text' => esc_html__( 'Text', 'gravityview' ),
161
			'date' => esc_html__( 'Date', 'gravityview' ),
162
			'select' => esc_html__( 'Select', 'gravityview' ),
163
			'multiselect' => esc_html__( 'Select (multiple values)', 'gravityview' ),
164
			'radio' => esc_html__( 'Radio', 'gravityview' ),
165
			'checkbox' => esc_html__( 'Checkbox', 'gravityview' ),
166
			'single_checkbox' => esc_html__( 'Checkbox', 'gravityview' ),
167
			'link' => esc_html__( 'Links', 'gravityview' ),
168
			'date_range' => esc_html__( 'Date range', 'gravityview' ),
169
		);
170
171
		/**
172
		 * Input Type groups
173
		 * @see admin-search-widget.js (getSelectInput)
174
		 * @var array
175
		 */
176
		$input_types = array(
177
			'text' => array( 'input_text' ),
178
			'address' => array( 'input_text' ),
179
			'date' => array( 'date', 'date_range' ),
180
			'boolean' => array( 'single_checkbox' ),
181
			'select' => array( 'select', 'radio', 'link' ),
182
			'multi' => array( 'select', 'multiselect', 'radio', 'checkbox', 'link' ),
183
		);
184
185
		wp_localize_script( 'gravityview_searchwidget_admin', 'gvSearchVar', array(
186
			'nonce' => wp_create_nonce( 'gravityview_ajaxsearchwidget' ),
187
			'label_nofields' => esc_html__( 'No search fields configured yet.', 'gravityview' ),
188
			'label_addfield' => esc_html__( 'Add Search Field', 'gravityview' ),
189
			'label_label' => esc_html__( 'Label', 'gravityview' ),
190
			'label_searchfield' => esc_html__( 'Search Field', 'gravityview' ),
191
			'label_inputtype' => esc_html__( 'Input Type', 'gravityview' ),
192
			'label_ajaxerror' => esc_html__( 'There was an error loading searchable fields. Save the View or refresh the page to fix this issue.', 'gravityview' ),
193
			'input_labels' => json_encode( $input_labels ),
194
			'input_types' => json_encode( $input_types ),
195
		) );
196
197
	}
198
199
	/**
200
	 * Add admin script to the whitelist
201
	 */
202
	public function register_no_conflict( $required ) {
203
		$required[] = 'gravityview_searchwidget_admin';
204
		return $required;
205
	}
206
207
	/**
208
	 * Ajax
209
	 * Returns the form fields ( only the searchable ones )
210
	 *
211
	 * @access public
212
	 * @return void
213
	 */
214
	public static function get_searchable_fields() {
215
216
		if ( ! isset( $_POST['nonce'] ) || ! wp_verify_nonce( $_POST['nonce'], 'gravityview_ajaxsearchwidget' ) ) {
0 ignored issues
show
introduced by
Detected access of super global var $_POST, probably need manual inspection.
Loading history...
introduced by
Detected usage of a non-sanitized input variable: $_POST
Loading history...
217
			exit( '0' );
0 ignored issues
show
Coding Style Compatibility introduced by
The method get_searchable_fields() contains an exit expression.

An exit expression should only be used in rare cases. For example, if you write a short command line script.

In most cases however, using an exit expression makes the code untestable and often causes incompatibilities with other libraries. Thus, unless you are absolutely sure it is required here, we recommend to refactor your code to avoid its usage.

Loading history...
218
		}
219
220
		$form = '';
221
222
		// Fetch the form for the current View
223
		if ( ! empty( $_POST['view_id'] ) ) {
224
225
			$form = gravityview_get_form_id( $_POST['view_id'] );
0 ignored issues
show
introduced by
Detected access of super global var $_POST, probably need manual inspection.
Loading history...
introduced by
Detected usage of a non-sanitized input variable: $_POST
Loading history...
226
227
		} elseif ( ! empty( $_POST['formid'] ) ) {
228
229
			$form = (int) $_POST['formid'];
0 ignored issues
show
introduced by
Detected access of super global var $_POST, probably need manual inspection.
Loading history...
230
231
		} elseif ( ! empty( $_POST['template_id'] ) && class_exists( 'GravityView_Ajax' ) ) {
232
233
			$form = GravityView_Ajax::pre_get_form_fields( $_POST['template_id'] );
0 ignored issues
show
introduced by
Detected access of super global var $_POST, probably need manual inspection.
Loading history...
introduced by
Detected usage of a non-sanitized input variable: $_POST
Loading history...
234
235
		}
236
237
		// fetch form id assigned to the view
238
		$response = self::render_searchable_fields( $form );
239
240
		exit( $response );
0 ignored issues
show
Coding Style Compatibility introduced by
The method get_searchable_fields() contains an exit expression.

An exit expression should only be used in rare cases. For example, if you write a short command line script.

In most cases however, using an exit expression makes the code untestable and often causes incompatibilities with other libraries. Thus, unless you are absolutely sure it is required here, we recommend to refactor your code to avoid its usage.

Loading history...
241
	}
242
243
	/**
244
	 * Generates html for the available Search Fields dropdown
245
	 * @param  string $form_id
246
	 * @param  string $current (for future use)
247
	 * @return string
248
	 */
249
	public static function render_searchable_fields( $form_id = null, $current = '' ) {
250
251
		if ( is_null( $form_id ) ) {
252
			return '';
253
		}
254
255
		// Get fields with sub-inputs and no parent
256
		$fields = gravityview_get_form_fields( $form_id, true, true );
257
258
		// start building output
259
260
		$output = '<select class="gv-search-fields">';
261
262
		$custom_fields = array(
263
			'search_all' => array(
264
				'text' => esc_html__( 'Search Everything', 'gravityview' ),
265
				'type' => 'text',
266
			),
267
			'entry_date' => array(
268
				'text' => esc_html__( 'Entry Date', 'gravityview' ),
269
				'type' => 'date',
270
			),
271
			'entry_id' => array(
272
				'text' => esc_html__( 'Entry ID', 'gravityview' ),
273
				'type' => 'text',
274
			),
275
			'created_by' => array(
276
				'text' => esc_html__( 'Entry Creator', 'gravityview' ),
277
				'type' => 'select',
278
			)
279
		);
280
281
		foreach( $custom_fields as $custom_field_key => $custom_field ) {
282
			$output .= sprintf( '<option value="%s" %s data-inputtypes="%s" data-placeholder="%s">%s</option>', $custom_field_key, selected( $custom_field_key, $current, false ), $custom_field['type'], self::get_field_label( array('field' => $custom_field_key ) ), $custom_field['text'] );
0 ignored issues
show
introduced by
No space after opening parenthesis of array is bad style
Loading history...
283
		}
284
285
		if ( ! empty( $fields ) ) {
286
287
			$blacklist_field_types = apply_filters( 'gravityview_blacklist_field_types', array( 'fileupload', 'post_image', 'post_id', 'section' ), null );
288
289
			foreach ( $fields as $id => $field ) {
290
291
				if ( in_array( $field['type'], $blacklist_field_types ) ) {
292
					continue;
293
				}
294
295
				$types = self::get_search_input_types( $id, $field['type'] );
296
297
				$output .= '<option value="'. $id .'" '. selected( $id, $current, false ).'data-inputtypes="'. esc_attr( $types ) .'">'. esc_html( $field['label'] ) .'</option>';
298
			}
299
		}
300
301
		$output .= '</select>';
302
303
		return $output;
304
305
	}
306
307
	/**
308
	 * Assign an input type according to the form field type
309
	 * @see admin-search-widget.js
310
	 *
311
	 * @param int $id Gravity Forms field ID
312
	 * @param string $field_type Gravity Forms field type (also the `name` parameter of GravityView_Field classes)
313
	 *
314
	 * @return string GV field search input type ('multi', 'boolean', 'select', 'date', 'text')
315
	 */
316
	public static function get_search_input_types( $id = '', $field_type = null ) {
317
318
		// @todo - This needs to be improved - many fields have . including products and addresses
319
		if ( false !== strpos( (string) $id, '.' ) && in_array( $field_type, array( 'checkbox' ) ) || in_array( $id, array( 'is_fulfilled' ) ) ) {
320
			$input_type = 'boolean'; // on/off checkbox
321
		} elseif ( in_array( $field_type, array( 'checkbox', 'post_category', 'multiselect' ) ) ) {
322
			$input_type = 'multi'; //multiselect
323
		} elseif ( in_array( $field_type, array( 'select', 'radio' ) ) ) {
324
			$input_type = 'select';
325
		} elseif ( in_array( $field_type, array( 'date' ) ) || in_array( $id, array( 'payment_date' ) ) ) {
326
			$input_type = 'date';
327
		} elseif ( in_array( $field_type, array( 'number' ) ) || in_array( $id, array( 'payment_amount' ) ) ) {
328
			$input_type = 'number';
329
		} else {
330
			$input_type = 'text';
331
		}
332
333
		/**
334
		 * @filter `gravityview/extension/search/input_type` Modify the search form input type based on field type
335
		 * @since 1.2
336
		 * @param string $input_type Assign an input type according to the form field type. Defaults: `boolean`, `multi`, `select`, `date`, `text`
337
		 * @param string $field_type Gravity Forms field type (also the `name` parameter of GravityView_Field classes)
338
		 */
339
		$input_type = apply_filters( 'gravityview/extension/search/input_type', $input_type, $field_type );
340
341
		return $input_type;
342
	}
343
344
	/**
345
	 * Display hidden fields to add support for sites using Default permalink structure
346
	 *
347
	 * @since 1.8
348
	 * @return array Search fields, modified if not using permalinks
349
	 */
350
	public function add_no_permalink_fields( $search_fields, $object, $widget_args = array() ) {
351
		/** @global WP_Rewrite $wp_rewrite */
352
		global $wp_rewrite;
0 ignored issues
show
Compatibility Best Practice introduced by
Use of global functionality is not recommended; it makes your code harder to test, and less reusable.

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

1. Pass all data via parameters

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

2. Create a class that maintains your state

class MyClass {
    private $a;
    private $b;

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

    public function myFunction() {
        // Do something
    }
}
Loading history...
353
354
		// Support default permalink structure
355
		if ( false === $wp_rewrite->using_permalinks() ) {
356
357
			// By default, use current post.
358
			$post_id = 0;
359
360
			// We're in the WordPress Widget context, and an overriding post ID has been set.
361
			if ( ! empty( $widget_args['post_id'] ) ) {
362
				$post_id = absint( $widget_args['post_id'] );
363
			}
364
			// We're in the WordPress Widget context, and the base View ID should be used
365
			else if ( ! empty( $widget_args['view_id'] ) ) {
366
				$post_id = absint( $widget_args['view_id'] );
367
			}
368
369
			$args = gravityview_get_permalink_query_args( $post_id );
370
371
			// Add hidden fields to the search form
372
			foreach ( $args as $key => $value ) {
0 ignored issues
show
Bug introduced by
The expression $args of type array|null is not guaranteed to be traversable. How about adding an additional type check?

There are different options of fixing this problem.

  1. If you want to be on the safe side, you can add an additional type-check:

    $collection = json_decode($data, true);
    if ( ! is_array($collection)) {
        throw new \RuntimeException('$collection must be an array.');
    }
    
    foreach ($collection as $item) { /** ... */ }
    
  2. If you are sure that the expression is traversable, you might want to add a doc comment cast to improve IDE auto-completion and static analysis:

    /** @var array $collection */
    $collection = json_decode($data, true);
    
    foreach ($collection as $item) { /** .. */ }
    
  3. Mark the issue as a false-positive: Just hover the remove button, in the top-right corner of this issue for more options.

Loading history...
373
				$search_fields[] = array(
374
					'name'  => $key,
375
					'input' => 'hidden',
376
					'value' => $value,
377
				);
378
			}
379
		}
380
381
		return $search_fields;
382
	}
383
384
385
	/** --- Frontend --- */
386
387
	/**
388
	 * Calculate the search criteria to filter entries
389
	 * @param  array $search_criteria
390
	 * @return array
391
	 */
392
	public function filter_entries( $search_criteria ) {
393
394
		if( 'post' === $this->search_method ) {
395
			$get = $_POST;
0 ignored issues
show
introduced by
Detected access of super global var $_POST, probably need manual inspection.
Loading history...
introduced by
Detected usage of a non-sanitized input variable: $_POST
Loading history...
396
		} else {
397
			$get = $_GET;
0 ignored issues
show
introduced by
Detected access of super global var $_GET, probably need manual inspection.
Loading history...
introduced by
Detected usage of a non-sanitized input variable: $_GET
Loading history...
398
		}
399
400
		do_action( 'gravityview_log_debug', sprintf( '%s[filter_entries] Requested $_%s: ', get_class( $this ), $this->search_method ), $get );
401
402
		if ( empty( $get ) || ! is_array( $get ) ) {
403
			return $search_criteria;
404
		}
405
406
		$get = stripslashes_deep( $get );
407
408
		$get = gv_map_deep( $get, 'urldecode' );
409
410
		// add free search
411
		if ( ! empty( $get['gv_search'] ) ) {
412
413
			// Search for a piece
414
			$words = explode( ' ', $get['gv_search'] );
415
416
			$words = array_filter( $words );
417
418
			foreach ( $words as $word ) {
419
				$search_criteria['field_filters'][] = array(
420
					'key' => null, // The field ID to search
421
					'value' => $word, // The value to search
422
					'operator' => 'contains', // What to search in. Options: `is` or `contains`
423
				);
424
			}
425
		}
426
427
		//start date & end date
428
		$curr_start = !empty( $get['gv_start'] ) ? $get['gv_start'] : '';
0 ignored issues
show
introduced by
Expected 1 space after "!"; 0 found
Loading history...
429
		$curr_end = !empty( $get['gv_start'] ) ? $get['gv_end'] : '';
0 ignored issues
show
introduced by
Expected 1 space after "!"; 0 found
Loading history...
430
431
        /**
432
         * @filter `gravityview_date_created_adjust_timezone` Whether to adjust the timezone for entries. \n
433
         * date_created is stored in UTC format. Convert search date into UTC (also used on templates/fields/date_created.php)
434
         * @since 1.12
435
         * @param[out,in] boolean $adjust_tz  Use timezone-adjusted datetime? If true, adjusts date based on blog's timezone setting. If false, uses UTC setting. Default: true
436
         * @param[in] string $context Where the filter is being called from. `search` in this case.
437
         */
438
        $adjust_tz = apply_filters( 'gravityview_date_created_adjust_timezone', true, 'search' );
439
0 ignored issues
show
Coding Style introduced by
Functions must not contain multiple empty lines in a row; found 2 empty lines
Loading history...
440
441
		/**
442
		 * Don't set $search_criteria['start_date'] if start_date is empty as it may lead to bad query results (GFAPI::get_entries)
443
		 */
444
		if( !empty( $curr_start ) ) {
0 ignored issues
show
introduced by
Expected 1 space after "!"; 0 found
Loading history...
445
			$search_criteria['start_date'] = $adjust_tz ? get_gmt_from_date( $curr_start ) : $curr_start;
446
		}
447
		if( !empty( $curr_end ) ) {
0 ignored issues
show
introduced by
Expected 1 space after "!"; 0 found
Loading history...
448
			$search_criteria['end_date'] = $adjust_tz ? get_gmt_from_date( $curr_end ) : $curr_end;
449
		}
450
451
		// search for a specific entry ID
452
		if ( ! empty( $get[ 'gv_id' ] ) ) {
0 ignored issues
show
introduced by
Array keys should NOT be surrounded by spaces if they only contain a string or an integer.
Loading history...
453
			$search_criteria['field_filters'][] = array(
454
				'key' => 'id',
455
				'value' => absint( $get[ 'gv_id' ] ),
0 ignored issues
show
introduced by
Array keys should NOT be surrounded by spaces if they only contain a string or an integer.
Loading history...
456
				'operator' => '=',
457
			);
458
		}
459
460
		// search for a specific Created_by ID
461
		if ( ! empty( $get[ 'gv_by' ] ) ) {
0 ignored issues
show
introduced by
Array keys should NOT be surrounded by spaces if they only contain a string or an integer.
Loading history...
462
			$search_criteria['field_filters'][] = array(
463
				'key' => 'created_by',
464
				'value' => absint( $get['gv_by'] ),
465
				'operator' => '=',
466
			);
467
		}
468
0 ignored issues
show
Coding Style introduced by
Functions must not contain multiple empty lines in a row; found 2 empty lines
Loading history...
469
470
		// Get search mode passed in URL
471
		$mode = isset( $get['mode'] ) && in_array( $get['mode'], array( 'any', 'all' ) ) ?  $get['mode'] : 'any';
472
473
		// get the other search filters
474
		foreach ( $get as $key => $value ) {
475
476
			if ( 0 !== strpos( $key, 'filter_' ) || empty( $value ) || ( is_array( $value ) && count( $value ) === 1 && empty( $value[0] ) ) ) {
0 ignored issues
show
introduced by
Found "=== 1". Use Yoda Condition checks, you must
Loading history...
477
				continue;
478
			}
479
480
			// could return simple filter or multiple filters
481
			$filter = $this->prepare_field_filter( $key, $value );
482
483
			if ( isset( $filter[0]['value'] ) ) {
484
				$search_criteria['field_filters'] = array_merge( $search_criteria['field_filters'], $filter );
485
486
				// if date range type, set search mode to ALL
487
				if ( ! empty( $filter[0]['operator'] ) && in_array( $filter[0]['operator'], array( '>=', '<=', '>', '<' ) ) ) {
488
					$mode = 'all';
489
				}
490
			} elseif( !empty( $filter ) ) {
0 ignored issues
show
introduced by
Expected 1 space after "!"; 0 found
Loading history...
491
				$search_criteria['field_filters'][] = $filter;
492
			}
493
		}
494
495
		/**
496
		 * @filter `gravityview/search/mode` Set the Search Mode (`all` or `any`)
497
		 * @since 1.5.1
498
		 * @param[out,in] string $mode Search mode (`any` vs `all`)
499
		 */
500
		$search_criteria['field_filters']['mode'] = apply_filters( 'gravityview/search/mode', $mode );
501
502
		do_action( 'gravityview_log_debug', sprintf( '%s[filter_entries] Returned Search Criteria: ', get_class( $this ) ), $search_criteria );
503
504
		unset( $get );
505
506
		return $search_criteria;
507
	}
508
509
	/**
510
	 * Prepare the field filters to GFAPI
511
	 *
512
	 * The type post_category, multiselect and checkbox support multi-select search - each value needs to be separated in an independent filter so we could apply the ANY search mode.
513
	 *
514
	 * Format searched values
515
	 * @param  string $key   $_GET/$_POST search key
516
	 * @param  string $value $_GET/$_POST search value
517
	 * @return array        1 or 2 deph levels
518
	 */
519
	public function prepare_field_filter( $key, $value ) {
520
521
		$gravityview_view = GravityView_View::getInstance();
522
523
		// calculates field_id, removing 'filter_' and for '_' for advanced fields ( like name or checkbox )
524
		$field_id = str_replace( '_', '.', str_replace( 'filter_', '', $key ) );
525
526
		// get form field array
527
		$form = $gravityview_view->getForm();
528
		$form_field = gravityview_get_field( $form, $field_id );
529
530
		$value = gv_map_deep( $value, '_wp_specialchars' ); // Gravity Forms encodes ampersands but not quotes
531
532
		// default filter array
533
		$filter = array(
534
			'key' => $field_id,
535
			'value' => $value,
536
		);
537
538
		switch ( $form_field['type'] ) {
539
540
			case 'select':
541
			case 'radio':
542
				$filter['operator'] = 'is';
543
				break;
544
545
			case 'post_category':
546
547
				if ( ! is_array( $value ) ) {
548
					$value = array( $value );
549
				}
550
551
				// Reset filter variable
552
				$filter = array();
553
554
				foreach ( $value as $val ) {
555
					$cat = get_term( $val, 'category' );
556
					$filter[] = array(
557
						'key' => $field_id,
558
						'value' => esc_attr( $cat->name ) . ':' . $val,
559
						'operator' => 'is',
560
					);
561
				}
562
563
				break;
564
565
			case 'multiselect':
566
567
				if ( ! is_array( $value ) ) {
568
					break;
569
				}
570
571
				// Reset filter variable
572
				$filter = array();
573
574
				foreach ( $value as $val ) {
575
					$filter[] = array( 'key' => $field_id, 'value' => $val );
576
				}
577
578
				break;
579
580
			case 'checkbox':
581
				// convert checkbox on/off into the correct search filter
582
				if ( false !== strpos( $field_id, '.' ) && ! empty( $form_field['inputs'] ) && ! empty( $form_field['choices'] ) ) {
583
					foreach ( $form_field['inputs'] as $k => $input ) {
584
						if ( $input['id'] == $field_id ) {
585
							$filter['value'] = $form_field['choices'][ $k ]['value'];
586
							$filter['operator'] = 'is';
587
							break;
588
						}
589
					}
590
				} elseif ( is_array( $value ) ) {
591
592
					// Reset filter variable
593
					$filter = array();
594
595
					foreach ( $value as $val ) {
596
						$filter[] = array(
597
								'key'   => $field_id,
598
								'value' => $val,
599
								'operator' => 'is',
600
						);
601
					}
602
				}
603
604
				break;
605
606
			case 'name':
607
			case 'address':
608
609
				if ( false === strpos( $field_id, '.' ) ) {
610
611
					$words = explode( ' ', $value );
612
613
					$filters = array();
614
					foreach ( $words as $word ) {
615
						if ( ! empty( $word ) && strlen( $word ) > 1 ) {
616
							// Keep the same key for each filter
617
							$filter['value'] = $word;
618
							// Add a search for the value
619
							$filters[] = $filter;
620
						}
621
					}
622
623
					$filter = $filters;
624
				}
625
626
				break;
627
628
			case 'date':
629
630
				if ( is_array( $value ) ) {
631
632
					// Reset filter variable
633
					$filter = array();
634
635
					foreach ( $value as $k => $date ) {
636
						if ( empty( $date ) ) {
637
							continue;
638
						}
639
						$operator = 'start' === $k ? '>=' : '<=';
640
641
						/**
642
						 * @hack
643
						 * @since 1.16.3
644
						 * Safeguard until GF implements '<=' operator
645
						 */
646
						if( !GFFormsModel::is_valid_operator( $operator ) && $operator === '<=' ) {
0 ignored issues
show
introduced by
Expected 1 space after "!"; 0 found
Loading history...
647
							$operator = '<';
648
							$date = date( 'Y-m-d', strtotime( $date . ' +1 day' ) );
649
						}
650
651
						$filter[] = array(
652
							'key' => $field_id,
653
							'value' => self::get_formatted_date( $date, 'Y-m-d' ),
654
							'operator' => $operator,
655
						);
656
					}
657
				} else {
658
					$filter['value'] = self::get_formatted_date( $value, 'Y-m-d' );
659
				}
660
661
				break;
662
0 ignored issues
show
Coding Style introduced by
Functions must not contain multiple empty lines in a row; found 2 empty lines
Loading history...
663
664
		} // switch field type
665
666
		return $filter;
667
	}
668
669
	/**
670
	 * Get the Field Format form GravityForms
671
	 *
672
	 * @param GF_Field_Date $field The field object
673
	 * @since 1.10
674
	 *
675
	 * @return string Format of the date in the database
676
	 */
677
	public static function get_date_field_format( GF_Field_Date $field ) {
678
		$format = 'm/d/Y';
679
		$datepicker = array(
680
			'mdy' => 'm/d/Y',
681
			'dmy' => 'd/m/Y',
682
			'dmy_dash' => 'd-m-Y',
683
			'dmy_dot' => 'm.d.Y',
684
			'ymd_slash' => 'Y/m/d',
685
			'ymd_dash' => 'Y-m-d',
686
			'ymd_dot' => 'Y.m.d',
687
		);
688
689
		if ( ! empty( $field->dateFormat ) && isset( $datepicker[ $field->dateFormat ] ) ){
690
			$format = $datepicker[ $field->dateFormat ];
691
		}
692
693
		return $format;
694
	}
695
696
	/**
697
	 * Format a date value
698
	 *
699
	 * @param string $value Date value input
700
	 * @param string $format Wanted formatted date
701
	 * @return string
702
	 */
703
	public static function get_formatted_date( $value = '', $format = 'Y-m-d' ) {
704
		$date = date_create( $value );
705
		if ( empty( $date ) ) {
706
			do_action( 'gravityview_log_debug', sprintf( '%s[get_formatted_date] Date format not valid: ', get_class( self::$instance ) ), $value );
707
			return '';
708
		}
709
		return $date->format( $format );
710
	}
711
712
713
	/**
714
	 * Include this extension templates path
715
	 * @param array $file_paths List of template paths ordered
716
	 */
717
	public function add_template_path( $file_paths ) {
718
719
		// Index 100 is the default GravityView template path.
720
		$file_paths[102] = self::$file . 'templates/';
721
722
		return $file_paths;
723
	}
724
725
	/**
726
	 * Renders the Search Widget
727
	 * @param type $widget_args
728
	 * @param type $content
729
	 * @param type $context
730
	 * @return type
731
	 */
732
	public function render_frontend( $widget_args, $content = '', $context = '' ) {
733
		/** @var GravityView_View $gravityview_view */
734
		$gravityview_view = GravityView_View::getInstance();
735
736
		if ( empty( $gravityview_view ) ) {
737
			do_action( 'gravityview_log_debug', sprintf( '%s[render_frontend]: $gravityview_view not instantiated yet.', get_class( $this ) ) );
738
			return;
739
		}
740
741
		// get configured search fields
742
		$search_fields = ! empty( $widget_args['search_fields'] ) ? json_decode( $widget_args['search_fields'], true ) : '';
743
744
		if ( empty( $search_fields ) || ! is_array( $search_fields ) ) {
745
			do_action( 'gravityview_log_debug', sprintf( '%s[render_frontend] No search fields configured for widget:', get_class( $this ) ), $widget_args );
746
			return;
747
		}
748
749
		$has_date = false;
750
751
		// prepare fields
752
		foreach ( $search_fields as $k => $field ) {
753
754
			$updated_field = $field;
755
756
			if ( in_array( $field['input'], array( 'date', 'date_range' ) ) ) {
757
				$has_date = true;
758
			}
759
760
			$updated_field = $this->get_search_filter_details( $updated_field );
761
762
			switch ( $field['field'] ) {
763
764
				case 'search_all':
765
					$updated_field['key'] = 'search_all';
766
					$updated_field['input'] = 'search_all';
767
					$updated_field['value'] = $this->rgget_or_rgpost( 'gv_search' );
768
					break;
769
770
				case 'entry_date':
771
					$updated_field['key'] = 'entry_date';
772
					$updated_field['input'] = 'entry_date';
773
					$updated_field['value'] = array(
774
						'start' => $this->rgget_or_rgpost( 'gv_start' ),
775
						'end' => $this->rgget_or_rgpost( 'gv_end' ),
776
					);
777
					$has_date = true;
778
					break;
779
780
				case 'entry_id':
781
					$updated_field['key'] = 'entry_id';
782
					$updated_field['input'] = 'entry_id';
783
					$updated_field['value'] = $this->rgget_or_rgpost( 'gv_id' );
784
					break;
785
786
				case 'created_by':
787
					$updated_field['key'] = 'created_by';
788
					$updated_field['name'] = 'gv_by';
789
					$updated_field['value'] = $this->rgget_or_rgpost( 'gv_by' );
790
					$updated_field['choices'] = self::get_created_by_choices();
791
					break;
792
			}
793
794
			$search_fields[ $k ] = $updated_field;
795
		}
796
797
		do_action( 'gravityview_log_debug', sprintf( '%s[render_frontend] Calculated Search Fields: ', get_class( $this ) ), $search_fields );
798
799
		/**
800
		 * @filter `gravityview_widget_search_filters` Modify what fields are shown. The order of the fields in the $search_filters array controls the order as displayed in the search bar widget.
801
		 * @param array $search_fields Array of search filters with `key`, `label`, `value`, `type` keys
802
		 * @param GravityView_Widget_Search $this Current widget object
803
		 * @param array $widget_args Args passed to this method. {@since 1.8}
804
		 * @var array
805
		 */
806
		$gravityview_view->search_fields = apply_filters( 'gravityview_widget_search_filters', $search_fields, $this, $widget_args );
807
808
		$gravityview_view->search_layout = ! empty( $widget_args['search_layout'] ) ? $widget_args['search_layout'] : 'horizontal';
809
810
		/** @since 1.14 */
811
		$gravityview_view->search_mode = ! empty( $widget_args['search_mode'] ) ? $widget_args['search_mode'] : 'any';
812
813
		$custom_class = ! empty( $widget_args['custom_class'] ) ? $widget_args['custom_class'] : '';
814
815
		$gravityview_view->search_class = self::get_search_class( $custom_class );
816
817
		$gravityview_view->search_clear = ! empty( $widget_args['search_clear'] ) ? $widget_args['search_clear'] : false;
818
819
		if ( $has_date ) {
820
			// enqueue datepicker stuff only if needed!
821
			$this->enqueue_datepicker();
822
		}
823
824
		$gravityview_view->render( 'widget', 'search', false );
825
	}
826
827
	/**
828
	 * Get the search class for a search form
829
	 *
830
	 * @since 1.5.4
831
	 *
832
	 * @return string Sanitized CSS class for the search form
833
	 */
834
	public static function get_search_class( $custom_class = '' ) {
835
		$gravityview_view = GravityView_View::getInstance();
836
837
		$search_class = 'gv-search-'.$gravityview_view->search_layout;
838
839
		if ( ! empty( $custom_class )  ) {
840
			$search_class .= ' '.$custom_class;
841
		}
842
843
		/**
844
		 * Modify the CSS class for the search form
845
		 *
846
		 * @param string $search_class The CSS class for the search form
847
		 */
848
		$search_class = apply_filters( 'gravityview_search_class', $search_class );
849
850
		// Is there an active search being performed? Used by fe-views.js
851
		$search_class .= GravityView_frontend::getInstance()->isSearch() ? ' gv-is-search' : '';
852
853
		return gravityview_sanitize_html_class( $search_class );
854
	}
855
856
857
	/**
858
	 * Calculate the search form action
859
	 * @since 1.6
860
	 *
861
	 * @return string
862
	 */
863
	public static function get_search_form_action() {
864
		$gravityview_view = GravityView_View::getInstance();
865
866
		$post_id = $gravityview_view->getPostId() ? $gravityview_view->getPostId() : $gravityview_view->getViewId();
867
868
		$url = add_query_arg( array(), get_permalink( $post_id ) );
869
870
		return esc_url( $url );
871
	}
872
873
	/**
874
	 * Get the label for a search form field
875
	 * @param  array $field      Field setting as sent by the GV configuration - has `field`, `input` (input type), and `label` keys
876
	 * @param  array $form_field Form field data, as fetched by `gravityview_get_field()`
877
	 * @return string             Label for the search form
878
	 */
879
	private static function get_field_label( $field, $form_field = array() ) {
880
881
		$label = rgget( 'label', $field );
882
883
		if( '' === $label ) {
884
885
			$label = isset( $form_field['label'] ) ? $form_field['label'] : '';
886
887
			switch( $field['field'] ) {
888
				case 'search_all':
889
					$label = __( 'Search Entries:', 'gravityview' );
890
					break;
891
				case 'entry_date':
892
					$label = __( 'Filter by date:', 'gravityview' );
893
					break;
894
				case 'entry_id':
895
					$label = __( 'Entry ID:', 'gravityview' );
896
					break;
897
				case 'created_by':
898
					$label = __( 'Submitted by:', 'gravityview' );
899
					break;
900
				case 'is_fulfilled':
901
					$label = __( 'Is Fulfilled', 'gravityview' );
902
					break;
903
				default:
904
					// If this is a field input, not a field
905
					if ( strpos( $field['field'], '.' ) > 0 && ! empty( $form_field['inputs'] ) ) {
906
907
						// Get the label for the field in question, which returns an array
908
						$items = wp_list_filter( $form_field['inputs'], array( 'id' => $field['field'] ) );
909
910
						// Get the item with the `label` key
911
						$values = wp_list_pluck( $items, 'label' );
912
913
						// There will only one item in the array, but this is easier
914
						foreach ( $values as $value ) {
915
							$label = $value;
916
							break;
917
						}
918
					}
919
			}
920
		}
921
922
		/**
923
		 * @filter `gravityview_search_field_label` Modify the label for a search field. Supports returning HTML
924
		 * @param[in,out] string $label Existing label text, sanitized.
925
		 * @param[in] array $form_field Gravity Forms field array, as returned by `GFFormsModel::get_field()`
926
		 */
927
		$label = apply_filters( 'gravityview_search_field_label', esc_attr( $label ), $form_field );
928
929
		return $label;
930
	}
931
932
	/**
933
	 * Prepare search fields to frontend render with other details (label, field type, searched values)
934
	 *
935
	 * @param array $field
936
	 * @return array
937
	 */
938
	private function get_search_filter_details( $field ) {
939
940
		$gravityview_view = GravityView_View::getInstance();
941
942
		$form = $gravityview_view->getForm();
943
944
		// for advanced field ids (eg, first name / last name )
945
		$name = 'filter_' . str_replace( '.', '_', $field['field'] );
946
947
		// get searched value from $_GET/$_POST (string or array)
948
		$value = $this->rgget_or_rgpost( $name );
949
950
		// get form field details
951
		$form_field = gravityview_get_field( $form, $field['field'] );
952
953
		$filter = array(
954
			'key' => $field['field'],
955
			'name' => $name,
956
			'label' => self::get_field_label( $field, $form_field ),
957
			'input' => $field['input'],
958
			'value' => $value,
959
			'type' => $form_field['type'],
960
		);
961
962
		// collect choices
963
		if ( 'post_category' === $form_field['type'] && ! empty( $form_field['displayAllCategories'] ) && empty( $form_field['choices'] ) ) {
964
			$filter['choices'] = gravityview_get_terms_choices();
965
		} elseif ( ! empty( $form_field['choices'] ) ) {
966
			$filter['choices'] = $form_field['choices'];
967
		}
968
969
		if ( 'date_range' === $field['input'] && empty( $value ) ) {
970
			$filter['value'] = array( 'start' => '', 'end' => '' );
971
		}
972
973
		return $filter;
974
975
	}
976
977
	/**
978
	 * Calculate the search choices for the users
979
	 *
980
	 * @since 1.8
981
	 *
982
	 * @return array Array of user choices (value = ID, text = display name)
983
	 */
984
	private static function get_created_by_choices() {
985
986
		/**
987
		 * filter gravityview/get_users/search_widget
988
		 * @see \GVCommon::get_users
989
		 */
990
		$users = GVCommon::get_users( 'search_widget', array( 'fields' => array( 'ID', 'display_name' ) ) );
991
992
		$choices = array();
993
		foreach ( $users as $user ) {
994
			$choices[] = array(
995
				'value' => $user->ID,
996
				'text' => $user->display_name,
997
			);
998
		}
999
1000
		return $choices;
1001
	}
1002
1003
1004
	/**
1005
	 * Output the Clear Search Results button
1006
	 * @since 1.5.4
1007
	 */
1008
	public static function the_clear_search_button() {
1009
		$gravityview_view = GravityView_View::getInstance();
1010
1011
		if ( $gravityview_view->search_clear ) {
1012
1013
			$url = strtok( add_query_arg( array() ), '?' );
1014
1015
			echo gravityview_get_link( $url, esc_html__( 'Clear', 'gravityview' ), 'class=button gv-search-clear' );
0 ignored issues
show
introduced by
Expected a sanitizing function (see Codex for 'Data Validation'), but instead saw 'gravityview_get_link'
Loading history...
1016
1017
		}
1018
	}
1019
1020
	/**
1021
	 * Based on the search method, fetch the value for a specific key
1022
	 * 
1023
	 * @since 1.16.4
1024
	 *
1025
	 * @param string $name Name of the request key to fetch the value for
1026
	 *
1027
	 * @return mixed|string Value of request at $name key. Empty string if empty.
1028
	 */
1029
	private function rgget_or_rgpost( $name ) {
1030
		$value = 'get' === $this->search_method ? rgget( $name ) : rgpost( $name );
1031
1032
		$value = stripslashes_deep( $value );
1033
1034
		$value = gv_map_deep( $value, 'urldecode' );
1035
1036
		$value = gv_map_deep( $value, '_wp_specialchars' );
1037
1038
		return $value;
1039
	}
1040
1041
1042
	/**
1043
	 * Require the datepicker script for the frontend GV script
1044
	 * @param array $js_dependencies Array of existing required scripts for the fe-views.js script
1045
	 */
1046
	public function add_datepicker_js_dependency( $js_dependencies ) {
1047
1048
		$js_dependencies[] = 'jquery-ui-datepicker';
1049
1050
		return $js_dependencies;
1051
	}
1052
1053
	/**
1054
	 * Modify the array passed to wp_localize_script()
1055
	 *
1056
	 * @param array $js_localization The data padded to the Javascript file
0 ignored issues
show
Bug introduced by
There is no parameter named $js_localization. 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...
1057
	 * @param array $view_data View data array with View settings
1058
	 *
1059
	 * @return array
1060
	 */
1061
	public function add_datepicker_localization( $localizations = array(), $view_data = array() ) {
1062
		global $wp_locale;
0 ignored issues
show
Compatibility Best Practice introduced by
Use of global functionality is not recommended; it makes your code harder to test, and less reusable.

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

1. Pass all data via parameters

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

2. Create a class that maintains your state

class MyClass {
    private $a;
    private $b;

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

    public function myFunction() {
        // Do something
    }
}
Loading history...
1063
1064
		/**
1065
		 * @filter `gravityview_datepicker_settings` Modify the datepicker settings
1066
		 * @see http://api.jqueryui.com/datepicker/ Learn what settings are available
1067
		 * @see http://www.renegadetechconsulting.com/tutorials/jquery-datepicker-and-wordpress-i18n Thanks for the helpful information on $wp_locale
1068
		 * @param array $js_localization The data padded to the Javascript file
1069
		 * @param array $view_data View data array with View settings
1070
		 */
1071
		$datepicker_settings = apply_filters( 'gravityview_datepicker_settings', array(
1072
			'yearRange' => '-5:+5',
1073
			'changeMonth' => true,
1074
			'changeYear' => true,
1075
			'closeText' => esc_attr_x( 'Close', 'Close calendar', 'gravityview' ),
1076
			'prevText' => esc_attr_x( 'Prev', 'Previous month in calendar', 'gravityview' ),
1077
			'nextText' => esc_attr_x( 'Next', 'Next month in calendar', 'gravityview' ),
1078
			'currentText' => esc_attr_x( 'Today', 'Today in calendar', 'gravityview' ),
1079
			'weekHeader' => esc_attr_x( 'Week', 'Week in calendar', 'gravityview' ),
1080
			'monthStatus'       => __( 'Show a different month', 'gravityview' ),
1081
			'monthNames'        => array_values( $wp_locale->month ),
1082
			'monthNamesShort'   => array_values( $wp_locale->month_abbrev ),
1083
			'dayNames'          => array_values( $wp_locale->weekday ),
1084
			'dayNamesShort'     => array_values( $wp_locale->weekday_abbrev ),
1085
			'dayNamesMin'       => array_values( $wp_locale->weekday_initial ),
1086
			// get the start of week from WP general setting
1087
			'firstDay'          => get_option( 'start_of_week' ),
1088
			// is Right to left language? default is false
1089
			'isRTL'             => is_rtl(),
1090
		), $view_data );
1091
1092
		$localizations['datepicker'] = $datepicker_settings;
1093
1094
		return $localizations;
1095
1096
	}
1097
1098
	/**
1099
	 * Enqueue the datepicker script
1100
	 *
1101
	 * It sets the $gravityview->datepicker_class parameter
1102
	 *
1103
	 * @todo Use own datepicker javascript instead of GF datepicker.js - that way, we can localize the settings and not require the changeMonth and changeYear pickers.
1104
	 * @return void
1105
	 */
1106
	public function enqueue_datepicker() {
1107
		$gravityview_view = GravityView_View::getInstance();
1108
1109
		wp_enqueue_script( 'jquery-ui-datepicker' );
1110
1111
		add_filter( 'gravityview_js_dependencies', array( $this, 'add_datepicker_js_dependency' ) );
1112
		add_filter( 'gravityview_js_localization', array( $this, 'add_datepicker_localization' ), 10, 2 );
1113
1114
		$scheme = is_ssl() ? 'https://' : 'http://';
1115
		wp_enqueue_style( 'jquery-ui-datepicker', $scheme.'ajax.googleapis.com/ajax/libs/jqueryui/1.8.18/themes/smoothness/jquery-ui.css' );
1116
1117
		/**
1118
		 * @filter `gravityview_search_datepicker_class`
1119
		 * Modify the CSS class for the datepicker, used by the CSS class is used by Gravity Forms' javascript to determine the format for the date picker. The `gv-datepicker` class is required by the GravityView datepicker javascript.
1120
		 * @param string $css_class CSS class to use. Default: `gv-datepicker datepicker mdy` \n
1121
		 * Options are:
1122
		 * - `mdy` (mm/dd/yyyy)
1123
		 * - `dmy` (dd/mm/yyyy)
1124
		 * - `dmy_dash` (dd-mm-yyyy)
1125
		 * - `dmy_dot` (dd.mm.yyyy)
1126
		 * - `ymp_slash` (yyyy/mm/dd)
1127
		 * - `ymd_dash` (yyyy-mm-dd)
1128
		 * - `ymp_dot` (yyyy.mm.dd)
1129
		 */
1130
		$datepicker_class = apply_filters( 'gravityview_search_datepicker_class', 'gv-datepicker datepicker mdy' );
1131
1132
		$gravityview_view->datepicker_class = $datepicker_class;
1133
1134
	}
1135
1136
1137
} // end class
1138
1139
new GravityView_Widget_Search;