Completed
Push — develop ( e5d071...9b5a20 )
by Gennady
39:04 queued 15:57
created

GravityView_Widget_Search::get_searchable_fields()   B

Complexity

Conditions 7
Paths 5

Size

Total Lines 28

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 0
CRAP Score 56

Importance

Changes 0
Metric Value
cc 7
nc 5
nop 0
dl 0
loc 28
ccs 0
cts 12
cp 0
crap 56
rs 8.5386
c 0
b 0
f 0
1
<?php
0 ignored issues
show
Coding Style Compatibility introduced by
For compatibility and reusability of your code, PSR1 recommends that a file should introduce either new symbols (like classes, functions, etc.) or have side-effects (like outputting something, or including other files), but not both at the same time. The first symbol is defined on line 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 \GV\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 25
	public function __construct() {
31
32 25
		$this->widget_id = 'search_bar';
33 25
		$this->widget_description = esc_html__( 'Search form for searching entries.', 'gravityview' );
34
35 25
		self::$instance = &$this;
36
37 25
		self::$file = plugin_dir_path( __FILE__ );
38
39 25
		$default_values = array( 'header' => 0, 'footer' => 0 );
40
41
		$settings = array(
42 25
			'search_layout' => array(
43 25
				'type' => 'radio',
44
				'full_width' => true,
45 25
				'label' => esc_html__( 'Search Layout', 'gravityview' ),
46 25
				'value' => 'horizontal',
47
				'options' => array(
48 25
					'horizontal' => esc_html__( 'Horizontal', 'gravityview' ),
49 25
					'vertical' => esc_html__( 'Vertical', 'gravityview' ),
50
				),
51
			),
52
			'search_clear' => array(
53 25
				'type' => 'checkbox',
54 25
				'label' => __( 'Show Clear button', 'gravityview' ),
55
				'value' => false,
56
			),
57
			'search_fields' => array(
58
				'type' => 'hidden',
59
				'label' => '',
60
				'class' => 'gv-search-fields-value',
61
				'value' => '[{"field":"search_all","input":"input_text"}]', // Default: Search Everything text box
62
			),
63
			'search_mode' => array(
64 25
				'type' => 'radio',
65
				'full_width' => true,
66 25
				'label' => esc_html__( 'Search Mode', 'gravityview' ),
67 25
				'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...
68 25
				'value' => 'any',
69 25
				'class' => 'hide-if-js',
70
				'options' => array(
71 25
					'any' => esc_html__( 'Match Any Fields', 'gravityview' ),
72 25
					'all' => esc_html__( 'Match All Fields', 'gravityview' ),
73
				),
74
			),
75
		);
76
77 25
		if ( ! $this->is_registered() ) {
78
			// frontend - filter entries
79
			add_filter( 'gravityview_fe_search_criteria', array( $this, 'filter_entries' ), 10, 3 );
80
81
			// frontend - add template path
82
			add_filter( 'gravityview_template_paths', array( $this, 'add_template_path' ) );
83
84
			// Add hidden fields for "Default" permalink structure
85
			add_filter( 'gravityview_widget_search_filters', array( $this, 'add_no_permalink_fields' ), 10, 3 );
86
87
			// admin - add scripts - run at 1100 to make sure GravityView_Admin_Views::add_scripts_and_styles() runs first at 999
88
			add_action( 'admin_enqueue_scripts', array( $this, 'add_scripts_and_styles' ), 1100 );
89
			add_action( 'wp_enqueue_scripts', array( $this, 'register_scripts') );
0 ignored issues
show
introduced by
No space before closing parenthesis of array is bad style
Loading history...
90
			add_filter( 'gravityview_noconflict_scripts', array( $this, 'register_no_conflict' ) );
91
92
			// ajax - get the searchable fields
93
			add_action( 'wp_ajax_gv_searchable_fields', array( 'GravityView_Widget_Search', 'get_searchable_fields' ) );
94
		}
95
96 25
		parent::__construct( esc_html__( 'Search Bar', 'gravityview' ), null, $default_values, $settings );
97
98
		// calculate the search method (POST / GET)
99 25
		$this->set_search_method();
100 25
	}
101
102
	/**
103
	 * @return GravityView_Widget_Search
104
	 */
105 5
	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...
106 5
		if ( empty( self::$instance ) ) {
107
			self::$instance = new GravityView_Widget_Search;
108
		}
109 5
		return self::$instance;
110
	}
111
112
	/**
113
	 * Sets the search method to GET (default) or POST
114
	 * @since 1.16.4
115
	 */
116 25
	private function set_search_method() {
117
		/**
118
		 * @filter `gravityview/search/method` Modify the search form method (GET / POST)
119
		 * @since 1.16.4
120
		 * @param string $search_method Assign an input type according to the form field type. Defaults: `boolean`, `multi`, `select`, `date`, `text`
121
		 * @param string $field_type Gravity Forms field type (also the `name` parameter of GravityView_Field classes)
122
		 */
123 25
		$method = apply_filters( 'gravityview/search/method', $this->search_method );
124
125 25
		$method = strtolower( $method );
126
127 25
		$this->search_method = in_array( $method, array( 'get', 'post' ) ) ? $method : 'get';
128 25
	}
129
130
	/**
131
	 * Returns the search method
132
	 * @since 1.16.4
133
	 * @return string
134
	 */
135 5
	public function get_search_method() {
136 5
		return $this->search_method;
137
	}
138
139
	/**
140
	 * Get the input types available for different field types
141
	 *
142
	 * @since 1.17.5
143
	 *
144
	 * @return array [field type name] => (array|string) search bar input types
145
	 */
146
	public static function get_input_types_by_field_type() {
147
		/**
148
		 * Input Type groups
149
		 * @see admin-search-widget.js (getSelectInput)
150
		 * @var array
151
		 */
152
		$input_types = array(
153
			'text' => array( 'input_text' ),
154
			'address' => array( 'input_text' ),
155
			'number' => array( 'input_text' ),
156
			'date' => array( 'date', 'date_range' ),
157
			'boolean' => array( 'single_checkbox' ),
158
			'select' => array( 'select', 'radio', 'link' ),
159
			'multi' => array( 'select', 'multiselect', 'radio', 'checkbox', 'link' ),
160
		);
161
162
		/**
163
		 * @filter `gravityview/search/input_types` Change the types of search fields available to a field type
164
		 * @see GravityView_Widget_Search::get_search_input_labels() for the available input types
165
		 * @param array $input_types Associative array: key is field `name`, value is array of GravityView input types (note: use `input_text` for `text`)
166
		 */
167
		$input_types = apply_filters( 'gravityview/search/input_types', $input_types );
168
169
		return $input_types;
170
	}
171
172
	/**
173
	 * Get labels for different types of search bar inputs
174
	 *
175
	 * @since 1.17.5
176
	 *
177
	 * @return array [input type] => input type label
178
	 */
179
	public static function get_search_input_labels() {
180
		/**
181
		 * Input Type labels l10n
182
		 * @see admin-search-widget.js (getSelectInput)
183
		 * @var array
184
		 */
185
		$input_labels = array(
186
			'input_text' => esc_html__( 'Text', 'gravityview' ),
187
			'date' => esc_html__( 'Date', 'gravityview' ),
188
			'select' => esc_html__( 'Select', 'gravityview' ),
189
			'multiselect' => esc_html__( 'Select (multiple values)', 'gravityview' ),
190
			'radio' => esc_html__( 'Radio', 'gravityview' ),
191
			'checkbox' => esc_html__( 'Checkbox', 'gravityview' ),
192
			'single_checkbox' => esc_html__( 'Checkbox', 'gravityview' ),
193
			'link' => esc_html__( 'Links', 'gravityview' ),
194
			'date_range' => esc_html__( 'Date range', 'gravityview' ),
195
		);
196
197
		/**
198
		 * @filter `gravityview/search/input_types` Change the label of search field input types
199
		 * @param array $input_types Associative array: key is input type name, value is label
200
		 */
201
		$input_labels = apply_filters( 'gravityview/search/input_labels', $input_labels );
202
203
		return $input_labels;
204
	}
205
206
	public static function get_search_input_label( $input_type ) {
207
		$labels = self::get_search_input_labels();
208
209
		return \GV\Utils::get( $labels, $input_type, false );
210
	}
211
212
	/**
213
	 * Add script to Views edit screen (admin)
214
	 * @param  mixed $hook
215
	 */
216
	public function add_scripts_and_styles( $hook ) {
217
		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...
218
219
		// Don't process any scripts below here if it's not a GravityView page or the widgets screen
220
		if ( ! gravityview()->request->is_admin( $hook, 'single' ) && ( 'widgets.php' !== $pagenow ) ) {
0 ignored issues
show
Unused Code introduced by
The call to Request::is_admin() has too many arguments starting with $hook.

This check compares calls to functions or methods with their respective definitions. If the call has more arguments than are defined, it raises an issue.

If a function is defined several times with a different number of parameters, the check may pick up the wrong definition and report false positives. One codebase where this has been known to happen is Wordpress.

In this case you can add the @ignore PhpDoc annotation to the duplicate definition and it will be ignored.

Loading history...
221
			return;
222
		}
223
224
		$script_min = ( defined( 'SCRIPT_DEBUG' ) && SCRIPT_DEBUG ) ? '' : '.min';
225
		$script_source = empty( $script_min ) ? '/source' : '';
226
227
		wp_enqueue_script( 'gravityview_searchwidget_admin', plugins_url( 'assets/js'.$script_source.'/admin-search-widget'.$script_min.'.js', __FILE__ ), array( 'jquery', 'gravityview_views_scripts' ), \GV\Plugin::$version );
228
229
		wp_localize_script( 'gravityview_searchwidget_admin', 'gvSearchVar', array(
230
			'nonce' => wp_create_nonce( 'gravityview_ajaxsearchwidget' ),
231
			'label_nofields' => esc_html__( 'No search fields configured yet.', 'gravityview' ),
232
			'label_addfield' => esc_html__( 'Add Search Field', 'gravityview' ),
233
			'label_label' => esc_html__( 'Label', 'gravityview' ),
234
			'label_searchfield' => esc_html__( 'Search Field', 'gravityview' ),
235
			'label_inputtype' => esc_html__( 'Input Type', 'gravityview' ),
236
			'label_ajaxerror' => esc_html__( 'There was an error loading searchable fields. Save the View or refresh the page to fix this issue.', 'gravityview' ),
237
			'input_labels' => json_encode( self::get_search_input_labels() ),
238
			'input_types' => json_encode( self::get_input_types_by_field_type() ),
239
		) );
240
241
	}
242
243
	/**
244
	 * Add admin script to the no-conflict scripts whitelist
245
	 * @param array $allowed Scripts allowed in no-conflict mode
246
	 * @return array Scripts allowed in no-conflict mode, plus the search widget script
247
	 */
248
	public function register_no_conflict( $allowed ) {
249
		$allowed[] = 'gravityview_searchwidget_admin';
250
		return $allowed;
251
	}
252
253
	/**
254
	 * Ajax
255
	 * Returns the form fields ( only the searchable ones )
256
	 *
257
	 * @access public
258
	 * @return void
259
	 */
260
	public static function get_searchable_fields() {
261
262
		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...
263
			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...
264
		}
265
266
		$form = '';
267
268
		// Fetch the form for the current View
269
		if ( ! empty( $_POST['view_id'] ) ) {
270
271
			$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...
272
273
		} elseif ( ! empty( $_POST['formid'] ) ) {
274
275
			$form = (int) $_POST['formid'];
0 ignored issues
show
introduced by
Detected access of super global var $_POST, probably need manual inspection.
Loading history...
276
277
		} elseif ( ! empty( $_POST['template_id'] ) && class_exists( 'GravityView_Ajax' ) ) {
278
279
			$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...
280
281
		}
282
283
		// fetch form id assigned to the view
284
		$response = self::render_searchable_fields( $form );
285
286
		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...
287
	}
288
289
	/**
290
	 * Generates html for the available Search Fields dropdown
291
	 * @param  int $form_id
292
	 * @param  string $current (for future use)
293
	 * @return string
294
	 */
295
	public static function render_searchable_fields( $form_id = null, $current = '' ) {
296
297
		if ( is_null( $form_id ) ) {
298
			return '';
299
		}
300
301
		// start building output
302
303
		$output = '<select class="gv-search-fields">';
304
305
		$custom_fields = array(
306
			'search_all' => array(
307
				'text' => esc_html__( 'Search Everything', 'gravityview' ),
308
				'type' => 'text',
309
			),
310
			'entry_date' => array(
311
				'text' => esc_html__( 'Entry Date', 'gravityview' ),
312
				'type' => 'date',
313
			),
314
			'entry_id' => array(
315
				'text' => esc_html__( 'Entry ID', 'gravityview' ),
316
				'type' => 'text',
317
			),
318
			'created_by' => array(
319
				'text' => esc_html__( 'Entry Creator', 'gravityview' ),
320
				'type' => 'select',
321
			),
322
			'is_starred' => array(
323
				'text' => esc_html__( 'Is Starred', 'gravityview' ),
324
				'type' => 'boolean',
325
			),
326
		);
327
328
		foreach( $custom_fields as $custom_field_key => $custom_field ) {
329
			$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...
330
		}
331
332
		// Get fields with sub-inputs and no parent
333
		$fields = gravityview_get_form_fields( $form_id, true, true );
334
335
		/**
336
		 * @filter `gravityview/search/searchable_fields` Modify the fields that are displayed as searchable in the Search Bar dropdown\n
337
		 * @since 1.17
338
		 * @see gravityview_get_form_fields() Used to fetch the fields
339
		 * @see GravityView_Widget_Search::get_search_input_types See this method to modify the type of input types allowed for a field
340
		 * @param array $fields Array of searchable fields, as fetched by gravityview_get_form_fields()
341
		 * @param  int $form_id
342
		 */
343
		$fields = apply_filters( 'gravityview/search/searchable_fields', $fields, $form_id );
344
345
		if ( ! empty( $fields ) ) {
346
347
			$blacklist_field_types = apply_filters( 'gravityview_blacklist_field_types', array( 'fileupload', 'post_image', 'post_id', 'section' ), null );
348
349
			foreach ( $fields as $id => $field ) {
350
351
				if ( in_array( $field['type'], $blacklist_field_types ) ) {
352
					continue;
353
				}
354
355
				$types = self::get_search_input_types( $id, $field['type'] );
356
357
				$output .= '<option value="'. $id .'" '. selected( $id, $current, false ).'data-inputtypes="'. esc_attr( $types ) .'">'. esc_html( $field['label'] ) .'</option>';
358
			}
359
		}
360
361
		$output .= '</select>';
362
363
		return $output;
364
365
	}
366
367
	/**
368
	 * Assign an input type according to the form field type
369
	 *
370
	 * @see admin-search-widget.js
371
	 *
372
	 * @param string|int|float $field_id Gravity Forms field ID
373
	 * @param string $field_type Gravity Forms field type (also the `name` parameter of GravityView_Field classes)
374
	 *
375
	 * @return string GV field search input type ('multi', 'boolean', 'select', 'date', 'text')
376
	 */
377
	public static function get_search_input_types( $field_id = '', $field_type = null ) {
378
379
		// @todo - This needs to be improved - many fields have . including products and addresses
380
		if ( false !== strpos( (string) $field_id, '.' ) && in_array( $field_type, array( 'checkbox' ) ) || in_array( $field_id, array( 'is_fulfilled' ) ) ) {
381
			$input_type = 'boolean'; // on/off checkbox
382
		} elseif ( in_array( $field_type, array( 'checkbox', 'post_category', 'multiselect' ) ) ) {
383
			$input_type = 'multi'; //multiselect
384
		} elseif ( in_array( $field_type, array( 'select', 'radio' ) ) ) {
385
			$input_type = 'select';
386
		} elseif ( in_array( $field_type, array( 'date' ) ) || in_array( $field_id, array( 'payment_date' ) ) ) {
387
			$input_type = 'date';
388
		} elseif ( in_array( $field_type, array( 'number' ) ) || in_array( $field_id, array( 'payment_amount' ) ) ) {
389
			$input_type = 'number';
390
		} else {
391
			$input_type = 'text';
392
		}
393
394
		/**
395
		 * @filter `gravityview/extension/search/input_type` Modify the search form input type based on field type
396
		 * @since 1.2
397
		 * @since 1.19.2 Added $field_id parameter
398
		 * @param string $input_type Assign an input type according to the form field type. Defaults: `boolean`, `multi`, `select`, `date`, `text`
399
		 * @param string $field_type Gravity Forms field type (also the `name` parameter of GravityView_Field classes)
400
		 * @param string|int|float $field_id ID of the field being processed
401
		 */
402
		$input_type = apply_filters( 'gravityview/extension/search/input_type', $input_type, $field_type, $field_id );
403
404
		return $input_type;
405
	}
406
407
	/**
408
	 * Display hidden fields to add support for sites using Default permalink structure
409
	 *
410
	 * @since 1.8
411
	 * @return array Search fields, modified if not using permalinks
412
	 */
413 4
	public function add_no_permalink_fields( $search_fields, $object, $widget_args = array() ) {
414
		/** @global WP_Rewrite $wp_rewrite */
415 4
		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...
416
417
		// Support default permalink structure
418 4
		if ( false === $wp_rewrite->using_permalinks() ) {
419
420
			// By default, use current post.
421 4
			$post_id = 0;
422
423
			// We're in the WordPress Widget context, and an overriding post ID has been set.
424 4
			if ( ! empty( $widget_args['post_id'] ) ) {
425
				$post_id = absint( $widget_args['post_id'] );
426
			}
427
			// We're in the WordPress Widget context, and the base View ID should be used
428 4
			else if ( ! empty( $widget_args['view_id'] ) ) {
429
				$post_id = absint( $widget_args['view_id'] );
430
			}
431
432 4
			$args = gravityview_get_permalink_query_args( $post_id );
433
434
			// Add hidden fields to the search form
435 4
			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...
436 4
				$search_fields[] = array(
437 4
					'name'  => $key,
438 4
					'input' => 'hidden',
439 4
					'value' => $value,
440
				);
441
			}
442
		}
443
444 4
		return $search_fields;
445
	}
446
447
	/**
448
	 * Get the fields that are searchable for a View
449
	 *
450
	 * @since 2.0
451
	 * @since 2.0.9 Added $with_full_field parameter
452
	 *
453
	 * @param \GV\View|null $view
454
	 * @param bool $with_full_field Return full field array, or just field ID? Default: false (just field ID)
455
	 *
456
	 * TODO: Move to \GV\View, perhaps? And return a Field_Collection
457
	 * TODO: Use in gravityview()->request->is_search() to calculate whether a valid search
458
	 *
459
	 * @return array If no View, returns empty array. Otherwise, returns array of fields configured in widgets and Search Bar for a View
460
	 */
461 20
	private function get_view_searchable_fields( $view, $with_full_field = false ) {
462
463
		/**
464
		 * Find all search widgets on the view and get the searchable fields settings.
465
		 */
466 20
		$searchable_fields = array();
467
468 20
		if ( ! $view ) {
469
			return $searchable_fields;
470
		}
471
472
		/**
473
		 * Include the sidebar Widgets.
474
		 */
475 20
		$widgets = (array) get_option( 'widget_gravityview_search', array() );
476
477 20
		foreach ( $widgets as $widget ) {
478 20
			if ( ! empty( $widget['view_id'] ) && $widget['view_id'] == $view->ID ) {
479
				if( $_fields = json_decode( $widget['search_fields'], true ) ) {
480
					foreach ( $_fields as $field ) {
481 20
						$searchable_fields [] = $with_full_field ? $field : $field['field'];
482
					}
483
				}
484
			}
485
		}
486
487 20
		foreach ( $view->widgets->by_id( $this->get_widget_id() )->all() as $widget ) {
488 20
			if( $_fields = json_decode( $widget->configuration->get( 'search_fields' ), true ) ) {
489 20
				foreach ( $_fields as $field ) {
490 20
					$searchable_fields [] = $with_full_field ? $field : $field['field'];
491
				}
492
			}
493
		}
494
495 20
		return $searchable_fields;
496
	}
497
498
	/** --- Frontend --- */
499
500
	/**
501
	 * Calculate the search criteria to filter entries
502
	 * @param array $search_criteria The search criteria
503
	 * @param int $form_id The form ID
504
	 * @param array $args Some args
505
	 *
506
	 * @param bool $force_search_criteria Whether to suppress GF_Query filter, internally used in self::gf_query_filter
507
	 *
508
	 * @return array
509
	 */
510 49
	public function filter_entries( $search_criteria, $form_id = null, $args = array(), $force_search_criteria = false ) {
511 49
		if ( ! $force_search_criteria && gravityview()->plugin->supports( \GV\Plugin::FEATURE_GFQUERY ) ) {
512
			/**
513
			 * If GF_Query is available, we can construct custom conditions with nested
514
			 * booleans on the query, giving up the old ways of flat search_criteria field_filters.
515
			 */
516 30
			add_action( 'gravityview/view/query', array( $this, 'gf_query_filter' ), 10, 3 );
517 30
			return $search_criteria; // Return the original criteria, GF_Query modification kicks in later
518
		}
519
520 48
		if( 'post' === $this->search_method ) {
521
			$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...
522
		} else {
523 48
			$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...
524
		}
525
526 48
		$view = \GV\View::by_id( \GV\Utils::get( $args, 'id' ) );
527
528 48
		gravityview()->log->debug( 'Requested $_{method}: ', array( 'method' => $this->search_method, 'data' => $get ) );
529
530 48
		if ( empty( $get ) || ! is_array( $get ) ) {
531 28
			return $search_criteria;
532
		}
533
534 21
		$get = stripslashes_deep( $get );
535
536 21
		$get = gv_map_deep( $get, 'rawurldecode' );
537
538
		// Make sure array key is set up
539 21
		$search_criteria['field_filters'] = \GV\Utils::get( $search_criteria, 'field_filters', array() );
540
541 21
		$searchable_fields = $this->get_view_searchable_fields( $view );
542
543
		// add free search
544 21
		if ( isset( $get['gv_search'] ) && '' !== $get['gv_search'] && in_array( 'search_all', $searchable_fields ) ) {
545
546 1
			$search_all_value = trim( $get['gv_search'] );
547
548
			/**
549
			 * @filter `gravityview/search-all-split-words` Search for each word separately or the whole phrase?
550
			 * @since 1.20.2
551
			 * @param bool $split_words True: split a phrase into words; False: search whole word only [Default: true]
552
			 */
553 1
			$split_words = apply_filters( 'gravityview/search-all-split-words', true );
554
555 1
			if ( $split_words ) {
556
557
				// Search for a piece
558 1
				$words = explode( ' ', $search_all_value );
559
560 1
				$words = array_filter( $words );
561
562
			} else {
563
564
				// Replace multiple spaces with one space
565 1
				$search_all_value = preg_replace( '/\s+/ism', ' ', $search_all_value );
566
567 1
				$words = array( $search_all_value );
568
			}
569
570 1
			foreach ( $words as $word ) {
571 1
				$search_criteria['field_filters'][] = array(
572 1
					'key' => null, // The field ID to search
573 1
					'value' => $word, // The value to search
574 1
					'operator' => 'contains', // What to search in. Options: `is` or `contains`
575
				);
576
			}
577
		}
578
579
		// start date & end date
580 21
		if ( in_array( 'entry_date', $searchable_fields ) ) {
581
			/**
582
			 * Get and normalize the dates according to the input format.
583
			 */
584 11
			if ( $curr_start = ! empty( $get['gv_start'] ) ? $get['gv_start'] : '' ) {
585 11
				if( $curr_start_date = date_create_from_format( $this->get_datepicker_format( true ), $curr_start ) ) {
586 11
					$curr_start = $curr_start_date->format( 'Y-m-d' );
587
				}
588
			}
589
590 11
			if ( $curr_end = ! empty( $get['gv_start'] ) ? ( ! empty( $get['gv_end'] ) ? $get['gv_end'] : '' ) : '' ) {
591 11
				if( $curr_end_date = date_create_from_format( $this->get_datepicker_format( true ), $curr_end ) ) {
592 11
					$curr_end = $curr_end_date->format( 'Y-m-d' );
593
				}
594
			}
595
596 11
			if ( $view ) {
597
				/**
598
				 * Override start and end dates if View is limited to some already.
599
				 */
600 11
				if ( $start_date = $view->settings->get( 'start_date' ) ) {
601 1
					if ( $start_timestamp = strtotime( $curr_start ) ) {
602 1
						$curr_start = $start_timestamp < strtotime( $start_date ) ? $start_date : $curr_start;
603
					}
604
				}
605 11
				if ( $end_date = $view->settings->get( 'end_date' ) ) {
606
					if ( $end_timestamp = strtotime( $curr_end ) ) {
607
						$curr_end = $end_timestamp > strtotime( $end_date ) ? $end_date : $curr_end;
608
					}
609
				}
610
			}
611
612
			/**
613
			 * @filter `gravityview_date_created_adjust_timezone` Whether to adjust the timezone for entries. \n
614
			 * date_created is stored in UTC format. Convert search date into UTC (also used on templates/fields/date_created.php)
615
			 * @since 1.12
616
			 * @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
617
			 * @param[in] string $context Where the filter is being called from. `search` in this case.
618
			 */
619 11
			$adjust_tz = apply_filters( 'gravityview_date_created_adjust_timezone', true, 'search' );
620
621
			/**
622
			 * Don't set $search_criteria['start_date'] if start_date is empty as it may lead to bad query results (GFAPI::get_entries)
623
			 */
624 11
			if ( ! empty( $curr_start ) ) {
625 11
				$curr_start = date( 'Y-m-d H:i:s', strtotime( $curr_start ) );
626 11
				$search_criteria['start_date'] = $adjust_tz ? get_gmt_from_date( $curr_start ) : $curr_start;
627
			}
628
629 11
			if ( ! empty( $curr_end ) ) {
630
				// Fast-forward 24 hour on the end time
631 11
				$curr_end = date( 'Y-m-d H:i:s', strtotime( $curr_end ) + DAY_IN_SECONDS );
632 11
				$search_criteria['end_date'] = $adjust_tz ? get_gmt_from_date( $curr_end ) : $curr_end;
633 11
				if ( strpos( $search_criteria['end_date'], '00:00:00' ) ) { // See https://github.com/gravityview/GravityView/issues/1056
634 11
					$search_criteria['end_date'] = date( 'Y-m-d H:i:s', strtotime( $search_criteria['end_date'] ) - 1 );
635
				}
636
			}
637
		}
638
639
		// search for a specific entry ID
640 21
		if ( ! empty( $get[ 'gv_id' ] ) && in_array( 'entry_id', $searchable_fields ) ) {
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...
641 2
			$search_criteria['field_filters'][] = array(
642 2
				'key' => 'id',
643 2
				'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...
644 2
				'operator' => '=',
645
			);
646
		}
647
648
		// search for a specific Created_by ID
649 21
		if ( ! empty( $get[ 'gv_by' ] ) && in_array( 'created_by', $searchable_fields ) ) {
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...
650 2
			$search_criteria['field_filters'][] = array(
651 2
				'key' => 'created_by',
652 2
				'value' => absint( $get['gv_by'] ),
653 2
				'operator' => '=',
654
			);
655
		}
656
0 ignored issues
show
Coding Style introduced by
Functions must not contain multiple empty lines in a row; found 2 empty lines
Loading history...
657
658
		// Get search mode passed in URL
659 21
		$mode = isset( $get['mode'] ) && in_array( $get['mode'], array( 'any', 'all' ) ) ?  $get['mode'] : 'any';
660
661
		// get the other search filters
662 21
		foreach ( $get as $key => $value ) {
663
664 21
			if ( 0 !== strpos( $key, 'filter_' ) || gv_empty( $value, false, false ) || ( is_array( $value ) && count( $value ) === 1 && gv_empty( $value[0], false, false ) ) ) {
0 ignored issues
show
introduced by
Found "=== 1". Use Yoda Condition checks, you must
Loading history...
665 11
				continue;
666
			}
667
668 11
			$filter_key = $this->convert_request_key_to_filter_key( $key );
669
670
			// could return simple filter or multiple filters
671 11
			if ( ! in_array( 'search_all', $searchable_fields ) && ! in_array( $filter_key , $searchable_fields ) ) {
672 1
				continue;
673
			}
674
675 10
			$filter = $this->prepare_field_filter( $filter_key, $value, $view );
676
677 10
			if ( isset( $filter[0]['value'] ) ) {
678
				$search_criteria['field_filters'] = array_merge( $search_criteria['field_filters'], $filter );
679
680
				// if date range type, set search mode to ALL
681
				if ( ! empty( $filter[0]['operator'] ) && in_array( $filter[0]['operator'], array( '>=', '<=', '>', '<' ) ) ) {
682
					$mode = 'all';
683
				}
684 10
			} elseif( !empty( $filter ) ) {
0 ignored issues
show
introduced by
Expected 1 space after "!"; 0 found
Loading history...
685 10
				$search_criteria['field_filters'][] = $filter;
686
			}
687
		}
688
689
		/**
690
		 * @filter `gravityview/search/mode` Set the Search Mode (`all` or `any`)
691
		 * @since 1.5.1
692
		 * @param[out,in] string $mode Search mode (`any` vs `all`)
693
		 */
694 21
		$search_criteria['field_filters']['mode'] = apply_filters( 'gravityview/search/mode', $mode );
695
696 21
		gravityview()->log->debug( 'Returned Search Criteria: ', array( 'data' => $search_criteria ) );
697
698 21
		unset( $get );
699
700 21
		return $search_criteria;
701
	}
702
703
	/**
704
	 * Filters the \GF_Query with advanced logic.
705
	 *
706
	 * Dropin for the legacy flat filters when \GF_Query is available.
707
	 *
708
	 * @param \GF_Query $query The current query object reference
709
	 * @param \GV\View $this The current view object
0 ignored issues
show
Bug introduced by
There is no parameter named $this. 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...
710
	 * @param \GV\Request $request The request object
711
	 */
712 29
	public function gf_query_filter( &$query, $view, $request ) {
0 ignored issues
show
Unused Code introduced by
The parameter $request 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...
713
		/**
714
		 * This is a shortcut to get all the needed search criteria.
715
		 * We feed these into an new GF_Query and tack them onto the current object.
716
		 */
717 29
		$search_criteria = $this->filter_entries( array(), null, array( 'id' => $view->ID ), true /** force search_criteria */ );
718
719 29
		if ( empty( $search_criteria['field_filters'] ) ) {
720 27
			return;
721
		}
722
723 2
		foreach ( $search_criteria['field_filters'] as &$filter ) {
724 2
			if ( ! is_array( $filter ) ) {
725 2
				continue;
726
			}
727
728
			// By default, we want searches to be wildcard for each field.
729 2
			$filter['operator'] = empty( $filter['operator'] ) ? 'contains' : $filter['operator'];
730
731
			/**
732
			 * @filter `gravityview_search_operator` Modify the search operator for the field (contains, is, isnot, etc)
733
			 * @param string $operator Existing search operator
734
			 * @param array $filter array with `key`, `value`, `operator`, `type` keys
735
			 */
736 2
			$filter['operator'] = apply_filters( 'gravityview_search_operator', $filter['operator'], $filter );
737
		}
738
739
		/**
740
		 * Parse the filter criteria to generate the needed
741
		 * WHERE clauses. This is a trick to not write our own generation
742
		 * code by reusing what's inside GF_Query already.
743
		 */
744 2
		$_tmp_query       = new GF_Query( $view->form->ID, $search_criteria );
745 2
		$_tmp_query_parts = $_tmp_query->_introspect();
746
747
		/**
748
		 * Grab the current clauses. We'll be combining them shortly.
749
		 */
750 2
		$query_parts      = $query->_introspect();
751
752
		/**
753
		 * Combine the parts as a new WHERE clause.
754
		 */
755 2
		$query->where( GF_Query_Condition::_and( $query_parts['where'], $_tmp_query_parts['where'] ) );
756 2
	}
757
758
	/**
759
	 * Convert $_GET/$_POST key to the field/meta ID
760
	 *
761
	 * Examples:
762
	 * - `filter_is_starred` => `is_starred`
763
	 * - `filter_1_2` => `1.2`
764
	 * - `filter_5` => `5`
765
	 *
766
	 * @since 2.0
767
	 *
768
	 * @param string $key $_GET/_$_POST search key
769
	 *
770
	 * @return string
771
	 */
772 11
	private function convert_request_key_to_filter_key( $key ) {
773
774 11
		$field_id = str_replace( 'filter_', '', $key );
775
776
		// calculates field_id, removing 'filter_' and for '_' for advanced fields ( like name or checkbox )
777 11
		if ( preg_match('/^[0-9_]+$/ism', $field_id ) ) {
0 ignored issues
show
Coding Style introduced by
Expected 1 spaces after opening bracket; 0 found
Loading history...
778 11
			$field_id = str_replace( '_', '.', $field_id );
779
		}
780
781 11
		return $field_id;
782
	}
783
784
	/**
785
	 * Prepare the field filters to GFAPI
786
	 *
787
	 * 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.
788
	 *
789
	 * Format searched values
790
	 *
791
	 * @param  string $filter_key ID of the field, or entry meta key
792
	 * @param  string $value $_GET/$_POST search value
793
	 * @param  \GV\View $view The view we're looking at
794
	 *
795
	 * @return array        1 or 2 deph levels
796
	 */
797 10
	public function prepare_field_filter( $filter_key, $value, $view ) {
798
799
		// get form field array
800 10
		$form_field = is_numeric( $filter_key ) ? \GV\GF_Field::by_id( $view->form, $filter_key ) : \GV\Internal_Field::by_id( $filter_key );
801
802
		// default filter array
803
		$filter = array(
804 10
			'key'   => $filter_key,
805 10
			'value' => $value,
806
		);
807
808 10
		switch ( $form_field->type ) {
809
810 10
			case 'select':
811 10
			case 'radio':
812 1
				$filter['operator'] = 'is';
813 1
				break;
814
815 9
			case 'post_category':
816
817
				if ( ! is_array( $value ) ) {
818
					$value = array( $value );
819
				}
820
821
				// Reset filter variable
822
				$filter = array();
823
824
				foreach ( $value as $val ) {
825
					$cat = get_term( $val, 'category' );
826
					$filter[] = array(
827
						'key'      => $filter_key,
828
						'value'    => esc_attr( $cat->name ) . ':' . $val,
829
						'operator' => 'is',
830
					);
831
				}
832
833
				break;
834
835 9
			case 'multiselect':
836
837
				if ( ! is_array( $value ) ) {
838
					break;
839
				}
840
841
				// Reset filter variable
842
				$filter = array();
843
844
				foreach ( $value as $val ) {
845
					$filter[] = array( 'key' => $filter_key, 'value' => $val );
846
				}
847
848
				break;
849
850 9
			case 'checkbox':
851
				// convert checkbox on/off into the correct search filter
852
				if ( false !== strpos( $filter_key, '.' ) && ! empty( $form_field->inputs ) && ! empty( $form_field->choices ) ) {
853
					foreach ( $form_field->inputs as $k => $input ) {
854
						if ( $input['id'] == $filter_key ) {
855
							$filter['value'] = $form_field->choices[ $k ]['value'];
856
							$filter['operator'] = 'is';
857
							break;
858
						}
859
					}
860
				} elseif ( is_array( $value ) ) {
861
862
					// Reset filter variable
863
					$filter = array();
864
865
					foreach ( $value as $val ) {
866
						$filter[] = array(
867
							'key'      => $filter_key,
868
							'value'    => $val,
869
							'operator' => 'is',
870
						);
871
					}
872
				}
873
874
				break;
875
876 9
			case 'name':
877 9
			case 'address':
878
879
				if ( false === strpos( $filter_key, '.' ) ) {
880
881
					$words = explode( ' ', $value );
882
883
					$filters = array();
884
					foreach ( $words as $word ) {
885
						if ( ! empty( $word ) && strlen( $word ) > 1 ) {
886
							// Keep the same key for each filter
887
							$filter['value'] = $word;
888
							// Add a search for the value
889
							$filters[] = $filter;
890
						}
891
					}
892
893
					$filter = $filters;
894
				}
895
896
				// State/Province should be exact matches
897
				if ( 'address' === $form_field->field->type ) {
898
899
					$searchable_fields = $this->get_view_searchable_fields( $view, true );
900
901
					foreach ( $searchable_fields as $searchable_field ) {
902
903
						if( $form_field->ID !== $searchable_field['field'] ) {
904
							continue;
905
						}
906
907
						// Only exact-match dropdowns, not text search
908
						if( in_array( $searchable_field['input'], array( 'text', 'search' ), true ) ) {
909
							continue;
910
						}
911
912
						$input_id = gravityview_get_input_id_from_id( $form_field->ID );
913
914
						if ( 4 === $input_id ) {
915
							$filter['operator'] = 'is';
916
						};
917
					}
918
				}
919
920
				break;
921
922 9
			case 'date':
923
924 8
				$date_format = $this->get_datepicker_format( true );
925
926 8
				if ( is_array( $value ) ) {
927
928
					// Reset filter variable
929
					$filter = array();
930
931
					foreach ( $value as $k => $date ) {
932
						if ( empty( $date ) ) {
933
							continue;
934
						}
935
						$operator = 'start' === $k ? '>=' : '<=';
936
937
						/**
938
						 * @hack
939
						 * @since 1.16.3
940
						 * Safeguard until GF implements '<=' operator
941
						 */
942
						if( !GFFormsModel::is_valid_operator( $operator ) && $operator === '<=' ) {
0 ignored issues
show
introduced by
Expected 1 space after "!"; 0 found
Loading history...
943
							$operator = '<';
944
							$date = date( 'Y-m-d', strtotime( self::get_formatted_date( $date, 'Y-m-d', $date_format ) . ' +1 day' ) );
945
						}
946
947
						$filter[] = array(
948
							'key'      => $filter_key,
949
							'value'    => self::get_formatted_date( $date, 'Y-m-d', $date_format ),
950
							'operator' => $operator,
951
						);
952
					}
953
				} else {
954 8
					$date = $value;
955 8
					$filter['value'] = self::get_formatted_date( $date, 'Y-m-d', $date_format );
956
				}
957
958 8
				break;
959
0 ignored issues
show
Coding Style introduced by
Functions must not contain multiple empty lines in a row; found 2 empty lines
Loading history...
960
961
		} // switch field type
962
963 10
		return $filter;
964
	}
965
966
	/**
967
	 * Get the Field Format form GravityForms
968
	 *
969
	 * @param GF_Field_Date $field The field object
970
	 * @since 1.10
971
	 *
972
	 * @return string Format of the date in the database
973
	 */
974
	public static function get_date_field_format( GF_Field_Date $field ) {
975
		$format = 'm/d/Y';
976
		$datepicker = array(
977
			'mdy' => 'm/d/Y',
978
			'dmy' => 'd/m/Y',
979
			'dmy_dash' => 'd-m-Y',
980
			'dmy_dot' => 'd.m.Y',
981
			'ymd_slash' => 'Y/m/d',
982
			'ymd_dash' => 'Y-m-d',
983
			'ymd_dot' => 'Y.m.d',
984
		);
985
986
		if ( ! empty( $field->dateFormat ) && isset( $datepicker[ $field->dateFormat ] ) ){
987
			$format = $datepicker[ $field->dateFormat ];
988
		}
989
990
		return $format;
991
	}
992
993
	/**
994
	 * Format a date value
995
	 *
996
	 * @param string $value Date value input
997
	 * @param string $format Wanted formatted date
998
	 *
999
	 * @since 2.1.2
1000
	 * @param string $value_format The value format. Default: Y-m-d
1001
	 *
1002
	 * @return string
1003
	 */
1004 8
	public static function get_formatted_date( $value = '', $format = 'Y-m-d', $value_format = 'Y-m-d' ) {
1005
1006 8
		$date = date_create_from_format( $value_format, $value );
1007
1008 8
		if ( empty( $date ) ) {
1009
			gravityview()->log->debug( 'Date format not valid: {value}', array( 'value' => $value ) );
1010
			return '';
1011
		}
1012 8
		return $date->format( $format );
1013
	}
1014
1015
1016
	/**
1017
	 * Include this extension templates path
1018
	 * @param array $file_paths List of template paths ordered
1019
	 */
1020 1
	public function add_template_path( $file_paths ) {
1021
1022
		// Index 100 is the default GravityView template path.
1023 1
		$file_paths[102] = self::$file . 'templates/';
1024
1025 1
		return $file_paths;
1026
	}
1027
1028
	/**
1029
	 * Check whether the configured search fields have a date field
1030
	 *
1031
	 * @since 1.17.5
1032
	 *
1033
	 * @param array $search_fields
1034
	 *
1035
	 * @return bool True: has a `date` or `date_range` field
1036
	 */
1037 4
	private function has_date_field( $search_fields ) {
1038
1039 4
		$has_date = false;
1040
1041 4
		foreach ( $search_fields as $k => $field ) {
1042 4
			if ( in_array( $field['input'], array( 'date', 'date_range', 'entry_date' ) ) ) {
1043
				$has_date = true;
1044 4
				break;
1045
			}
1046
		}
1047
1048 4
		return $has_date;
1049
	}
1050
1051
	/**
1052
	 * Renders the Search Widget
1053
	 * @param array $widget_args
1054
	 * @param string $content
1055
	 * @param string $context
1056
	 *
1057
	 * @return void
1058
	 */
1059 4
	public function render_frontend( $widget_args, $content = '', $context = '' ) {
1060
		/** @var GravityView_View $gravityview_view */
1061 4
		$gravityview_view = GravityView_View::getInstance();
1062
1063 4
		if ( empty( $gravityview_view ) ) {
1064
			gravityview()->log->debug( '$gravityview_view not instantiated yet.' );
1065
			return;
1066
		}
1067
1068
		// get configured search fields
1069 4
		$search_fields = ! empty( $widget_args['search_fields'] ) ? json_decode( $widget_args['search_fields'], true ) : '';
1070
1071 4
		if ( empty( $search_fields ) || ! is_array( $search_fields ) ) {
1072
			gravityview()->log->debug( 'No search fields configured for widget:', array( 'data' => $widget_args ) );
1073
			return;
1074
		}
1075
0 ignored issues
show
Coding Style introduced by
Functions must not contain multiple empty lines in a row; found 2 empty lines
Loading history...
1076
1077
		// prepare fields
1078 4
		foreach ( $search_fields as $k => $field ) {
1079
1080 4
			$updated_field = $field;
1081
1082 4
			$updated_field = $this->get_search_filter_details( $updated_field );
1083
1084 4
			switch ( $field['field'] ) {
1085
1086 4
				case 'search_all':
1087 4
					$updated_field['key'] = 'search_all';
1088 4
					$updated_field['input'] = 'search_all';
1089 4
					$updated_field['value'] = $this->rgget_or_rgpost( 'gv_search' );
1090 4
					break;
1091
1092
				case 'entry_date':
1093
					$updated_field['key'] = 'entry_date';
1094
					$updated_field['input'] = 'entry_date';
1095
					$updated_field['value'] = array(
1096
						'start' => $this->rgget_or_rgpost( 'gv_start' ),
1097
						'end' => $this->rgget_or_rgpost( 'gv_end' ),
1098
					);
1099
					break;
1100
1101
				case 'entry_id':
1102
					$updated_field['key'] = 'entry_id';
1103
					$updated_field['input'] = 'entry_id';
1104
					$updated_field['value'] = $this->rgget_or_rgpost( 'gv_id' );
1105
					break;
1106
1107
				case 'created_by':
1108
					$updated_field['key'] = 'created_by';
1109
					$updated_field['name'] = 'gv_by';
1110
					$updated_field['value'] = $this->rgget_or_rgpost( 'gv_by' );
1111
					$updated_field['choices'] = self::get_created_by_choices();
1112
					break;
1113
			}
1114
1115 4
			$search_fields[ $k ] = $updated_field;
1116
		}
1117
1118 4
		gravityview()->log->debug( 'Calculated Search Fields: ', array( 'data' => $search_fields ) );
1119
1120
		/**
1121
		 * @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.
1122
		 * @param array $search_fields Array of search filters with `key`, `label`, `value`, `type`, `choices` keys
1123
		 * @param GravityView_Widget_Search $this Current widget object
1124
		 * @param array $widget_args Args passed to this method. {@since 1.8}
1125
		 * @param \GV\Template_Context $context {@since 2.0}
1126
		 * @var array
1127
		 */
1128 4
		$gravityview_view->search_fields = apply_filters( 'gravityview_widget_search_filters', $search_fields, $this, $widget_args, $context );
0 ignored issues
show
Bug introduced by
The property search_fields does not seem to exist. Did you mean fields?

An attempt at access to an undefined property has been detected. This may either be a typographical error or the property has been renamed but there are still references to its old name.

If you really want to allow access to undefined properties, you can define magic methods to allow access. See the php core documentation on Overloading.

Loading history...
1129
1130 4
		$gravityview_view->search_layout = ! empty( $widget_args['search_layout'] ) ? $widget_args['search_layout'] : 'horizontal';
0 ignored issues
show
Bug introduced by
The property search_layout does not seem to exist in GravityView_View.

An attempt at access to an undefined property has been detected. This may either be a typographical error or the property has been renamed but there are still references to its old name.

If you really want to allow access to undefined properties, you can define magic methods to allow access. See the php core documentation on Overloading.

Loading history...
1131
1132
		/** @since 1.14 */
1133 4
		$gravityview_view->search_mode = ! empty( $widget_args['search_mode'] ) ? $widget_args['search_mode'] : 'any';
0 ignored issues
show
Bug introduced by
The property search_mode does not seem to exist in GravityView_View.

An attempt at access to an undefined property has been detected. This may either be a typographical error or the property has been renamed but there are still references to its old name.

If you really want to allow access to undefined properties, you can define magic methods to allow access. See the php core documentation on Overloading.

Loading history...
1134
1135 4
		$custom_class = ! empty( $widget_args['custom_class'] ) ? $widget_args['custom_class'] : '';
1136
1137 4
		$gravityview_view->search_class = self::get_search_class( $custom_class );
0 ignored issues
show
Bug introduced by
The property search_class does not seem to exist in GravityView_View.

An attempt at access to an undefined property has been detected. This may either be a typographical error or the property has been renamed but there are still references to its old name.

If you really want to allow access to undefined properties, you can define magic methods to allow access. See the php core documentation on Overloading.

Loading history...
1138
1139 4
		$gravityview_view->search_clear = ! empty( $widget_args['search_clear'] ) ? $widget_args['search_clear'] : false;
0 ignored issues
show
Bug introduced by
The property search_clear does not seem to exist in GravityView_View.

An attempt at access to an undefined property has been detected. This may either be a typographical error or the property has been renamed but there are still references to its old name.

If you really want to allow access to undefined properties, you can define magic methods to allow access. See the php core documentation on Overloading.

Loading history...
1140
1141 4
		if ( $this->has_date_field( $search_fields ) ) {
1142
			// enqueue datepicker stuff only if needed!
1143
			$this->enqueue_datepicker();
1144
		}
1145
1146 4
		$this->maybe_enqueue_flexibility();
1147
1148 4
		$gravityview_view->render( 'widget', 'search', false );
1149 4
	}
1150
1151
	/**
1152
	 * Get the search class for a search form
1153
	 *
1154
	 * @since 1.5.4
1155
	 *
1156
	 * @return string Sanitized CSS class for the search form
1157
	 */
1158 4
	public static function get_search_class( $custom_class = '' ) {
1159 4
		$gravityview_view = GravityView_View::getInstance();
1160
1161 4
		$search_class = 'gv-search-'.$gravityview_view->search_layout;
0 ignored issues
show
Documentation introduced by
The property search_layout does not exist on object<GravityView_View>. Since you implemented __get, maybe consider adding a @property annotation.

Since your code implements the magic getter _get, this function will be called for any read access on an undefined variable. You can add the @property annotation to your class or interface to document the existence of this variable.

<?php

/**
 * @property int $x
 * @property int $y
 * @property string $text
 */
class MyLabel
{
    private $properties;

    private $allowedProperties = array('x', 'y', 'text');

    public function __get($name)
    {
        if (isset($properties[$name]) && in_array($name, $this->allowedProperties)) {
            return $properties[$name];
        } else {
            return null;
        }
    }

    public function __set($name, $value)
    {
        if (in_array($name, $this->allowedProperties)) {
            $properties[$name] = $value;
        } else {
            throw new \LogicException("Property $name is not defined.");
        }
    }

}

If the property has read access only, you can use the @property-read annotation instead.

Of course, you may also just have mistyped another name, in which case you should fix the error.

See also the PhpDoc documentation for @property.

Loading history...
1162
1163 4
		if ( ! empty( $custom_class )  ) {
1164
			$search_class .= ' '.$custom_class;
1165
		}
1166
1167
		/**
1168
		 * @filter `gravityview_search_class` Modify the CSS class for the search form
1169
		 * @param string $search_class The CSS class for the search form
1170
		 */
1171 4
		$search_class = apply_filters( 'gravityview_search_class', $search_class );
1172
1173
		// Is there an active search being performed? Used by fe-views.js
1174 4
		$search_class .= GravityView_frontend::getInstance()->isSearch() ? ' gv-is-search' : '';
1175
1176 4
		return gravityview_sanitize_html_class( $search_class );
1177
	}
1178
1179
1180
	/**
1181
	 * Calculate the search form action
1182
	 * @since 1.6
1183
	 *
1184
	 * @return string
1185
	 */
1186 4
	public static function get_search_form_action() {
1187 4
		$gravityview_view = GravityView_View::getInstance();
1188
1189 4
		$post_id = $gravityview_view->getPostId() ? $gravityview_view->getPostId() : $gravityview_view->getViewId();
1190
1191 4
		$url = add_query_arg( array(), get_permalink( $post_id ) );
1192
1193 4
		return esc_url( $url );
1194
	}
1195
1196
	/**
1197
	 * Get the label for a search form field
1198
	 * @param  array $field      Field setting as sent by the GV configuration - has `field`, `input` (input type), and `label` keys
1199
	 * @param  array $form_field Form field data, as fetched by `gravityview_get_field()`
1200
	 * @return string             Label for the search form
1201
	 */
1202 4
	private static function get_field_label( $field, $form_field = array() ) {
1203
1204 4
		$label = \GV\Utils::_GET( 'label', \GV\Utils::get( $field, 'label' ) );
1205
1206 4
		if ( ! $label ) {
1207
1208 4
			$label = isset( $form_field['label'] ) ? $form_field['label'] : '';
1209
1210 4
			switch( $field['field'] ) {
1211 4
				case 'search_all':
1212 4
					$label = __( 'Search Entries:', 'gravityview' );
1213 4
					break;
1214
				case 'entry_date':
1215
					$label = __( 'Filter by date:', 'gravityview' );
1216
					break;
1217
				case 'entry_id':
1218
					$label = __( 'Entry ID:', 'gravityview' );
1219
					break;
1220
				default:
1221
					// If this is a field input, not a field
1222
					if ( strpos( $field['field'], '.' ) > 0 && ! empty( $form_field['inputs'] ) ) {
1223
1224
						// Get the label for the field in question, which returns an array
1225
						$items = wp_list_filter( $form_field['inputs'], array( 'id' => $field['field'] ) );
1226
1227
						// Get the item with the `label` key
1228
						$values = wp_list_pluck( $items, 'label' );
1229
1230
						// There will only one item in the array, but this is easier
1231
						foreach ( $values as $value ) {
1232
							$label = $value;
1233
							break;
1234
						}
1235
					}
1236
			}
1237
		}
1238
1239
		/**
1240
		 * @filter `gravityview_search_field_label` Modify the label for a search field. Supports returning HTML
1241
		 * @since 1.17.3 Added $field parameter
1242
		 * @param[in,out] string $label Existing label text, sanitized.
1243
		 * @param[in] array $form_field Gravity Forms field array, as returned by `GFFormsModel::get_field()`
1244
		 * @param[in] array $field Field setting as sent by the GV configuration - has `field`, `input` (input type), and `label` keys
1245
		 */
1246 4
		$label = apply_filters( 'gravityview_search_field_label', esc_attr( $label ), $form_field, $field );
1247
1248 4
		return $label;
1249
	}
1250
1251
	/**
1252
	 * Prepare search fields to frontend render with other details (label, field type, searched values)
1253
	 *
1254
	 * @param array $field
1255
	 * @return array
1256
	 */
1257 4
	private function get_search_filter_details( $field ) {
1258
1259 4
		$gravityview_view = GravityView_View::getInstance();
1260
1261 4
		$form = $gravityview_view->getForm();
1262
1263
		// for advanced field ids (eg, first name / last name )
1264 4
		$name = 'filter_' . str_replace( '.', '_', $field['field'] );
1265
1266
		// get searched value from $_GET/$_POST (string or array)
1267 4
		$value = $this->rgget_or_rgpost( $name );
1268
1269
		// get form field details
1270 4
		$form_field = gravityview_get_field( $form, $field['field'] );
1271
1272
		$filter = array(
1273 4
			'key' => $field['field'],
1274 4
			'name' => $name,
1275 4
			'label' => self::get_field_label( $field, $form_field ),
1276 4
			'input' => $field['input'],
1277 4
			'value' => $value,
1278 4
			'type' => $form_field['type'],
1279
		);
1280
1281
		// collect choices
1282 4
		if ( 'post_category' === $form_field['type'] && ! empty( $form_field['displayAllCategories'] ) && empty( $form_field['choices'] ) ) {
1283
			$filter['choices'] = gravityview_get_terms_choices();
1284 4
		} elseif ( ! empty( $form_field['choices'] ) ) {
1285
			$filter['choices'] = $form_field['choices'];
1286
		}
1287
1288 4
		if ( 'date_range' === $field['input'] && empty( $value ) ) {
1289
			$filter['value'] = array( 'start' => '', 'end' => '' );
1290
		}
1291
1292 4
		return $filter;
1293
1294
	}
1295
1296
	/**
1297
	 * Calculate the search choices for the users
1298
	 *
1299
	 * @since 1.8
1300
	 *
1301
	 * @return array Array of user choices (value = ID, text = display name)
1302
	 */
1303
	private static function get_created_by_choices() {
1304
1305
		/**
1306
		 * filter gravityview/get_users/search_widget
1307
		 * @see \GVCommon::get_users
1308
		 */
1309
		$users = GVCommon::get_users( 'search_widget', array( 'fields' => array( 'ID', 'display_name' ) ) );
1310
1311
		$choices = array();
1312
		foreach ( $users as $user ) {
1313
			$choices[] = array(
1314
				'value' => $user->ID,
1315
				'text' => $user->display_name,
1316
			);
1317
		}
1318
1319
		return $choices;
1320
	}
1321
1322
1323
	/**
1324
	 * Output the Clear Search Results button
1325
	 * @since 1.5.4
1326
	 */
1327 4
	public static function the_clear_search_button() {
1328 4
		$gravityview_view = GravityView_View::getInstance();
1329
1330 4
		if ( $gravityview_view->search_clear ) {
0 ignored issues
show
Documentation introduced by
The property search_clear does not exist on object<GravityView_View>. Since you implemented __get, maybe consider adding a @property annotation.

Since your code implements the magic getter _get, this function will be called for any read access on an undefined variable. You can add the @property annotation to your class or interface to document the existence of this variable.

<?php

/**
 * @property int $x
 * @property int $y
 * @property string $text
 */
class MyLabel
{
    private $properties;

    private $allowedProperties = array('x', 'y', 'text');

    public function __get($name)
    {
        if (isset($properties[$name]) && in_array($name, $this->allowedProperties)) {
            return $properties[$name];
        } else {
            return null;
        }
    }

    public function __set($name, $value)
    {
        if (in_array($name, $this->allowedProperties)) {
            $properties[$name] = $value;
        } else {
            throw new \LogicException("Property $name is not defined.");
        }
    }

}

If the property has read access only, you can use the @property-read annotation instead.

Of course, you may also just have mistyped another name, in which case you should fix the error.

See also the PhpDoc documentation for @property.

Loading history...
1331
1332
			$url = strtok( add_query_arg( array() ), '?' );
1333
1334
			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...
1335
1336
		}
1337 4
	}
1338
1339
	/**
1340
	 * Based on the search method, fetch the value for a specific key
1341
	 *
1342
	 * @since 1.16.4
1343
	 *
1344
	 * @param string $name Name of the request key to fetch the value for
1345
	 *
1346
	 * @return mixed|string Value of request at $name key. Empty string if empty.
1347
	 */
1348 4
	private function rgget_or_rgpost( $name ) {
1349 4
		$value = \GV\Utils::_REQUEST( $name );
1350
1351 4
		$value = stripslashes_deep( $value );
1352
1353 4
		$value = gv_map_deep( $value, 'rawurldecode' );
1354
1355 4
		$value = gv_map_deep( $value, '_wp_specialchars' );
1356
1357 4
		return $value;
1358
	}
1359
1360
1361
	/**
1362
	 * Require the datepicker script for the frontend GV script
1363
	 * @param array $js_dependencies Array of existing required scripts for the fe-views.js script
1364
	 * @return array Array required scripts, with `jquery-ui-datepicker` added
1365
	 */
1366
	public function add_datepicker_js_dependency( $js_dependencies ) {
1367
1368
		$js_dependencies[] = 'jquery-ui-datepicker';
1369
1370
		return $js_dependencies;
1371
	}
1372
1373
	/**
1374
	 * Modify the array passed to wp_localize_script()
1375
	 *
1376
	 * @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...
1377
	 * @param array $view_data View data array with View settings
1378
	 *
1379
	 * @return array
1380
	 */
1381
	public function add_datepicker_localization( $localizations = array(), $view_data = array() ) {
1382
		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...
1383
1384
		/**
1385
		 * @filter `gravityview_datepicker_settings` Modify the datepicker settings
1386
		 * @see http://api.jqueryui.com/datepicker/ Learn what settings are available
1387
		 * @see http://www.renegadetechconsulting.com/tutorials/jquery-datepicker-and-wordpress-i18n Thanks for the helpful information on $wp_locale
1388
		 * @param array $js_localization The data padded to the Javascript file
1389
		 * @param array $view_data View data array with View settings
1390
		 */
1391
		$datepicker_settings = apply_filters( 'gravityview_datepicker_settings', array(
1392
			'yearRange' => '-5:+5',
1393
			'changeMonth' => true,
1394
			'changeYear' => true,
1395
			'closeText' => esc_attr_x( 'Close', 'Close calendar', 'gravityview' ),
1396
			'prevText' => esc_attr_x( 'Prev', 'Previous month in calendar', 'gravityview' ),
1397
			'nextText' => esc_attr_x( 'Next', 'Next month in calendar', 'gravityview' ),
1398
			'currentText' => esc_attr_x( 'Today', 'Today in calendar', 'gravityview' ),
1399
			'weekHeader' => esc_attr_x( 'Week', 'Week in calendar', 'gravityview' ),
1400
			'monthStatus'       => __( 'Show a different month', 'gravityview' ),
1401
			'monthNames'        => array_values( $wp_locale->month ),
1402
			'monthNamesShort'   => array_values( $wp_locale->month_abbrev ),
1403
			'dayNames'          => array_values( $wp_locale->weekday ),
1404
			'dayNamesShort'     => array_values( $wp_locale->weekday_abbrev ),
1405
			'dayNamesMin'       => array_values( $wp_locale->weekday_initial ),
1406
			// get the start of week from WP general setting
1407
			'firstDay'          => get_option( 'start_of_week' ),
1408
			// is Right to left language? default is false
1409
			'isRTL'             => is_rtl(),
1410
		), $view_data );
1411
1412
		$localizations['datepicker'] = $datepicker_settings;
1413
1414
		return $localizations;
1415
1416
	}
1417
1418
	/**
1419
	 * Register search widget scripts, including Flexibility
1420
	 *
1421
	 * @see https://github.com/10up/flexibility
1422
	 *
1423
	 * @since 1.17
1424
	 *
1425
	 * @return void
1426
	 */
1427
	public function register_scripts() {
1428
		wp_register_script( 'gv-flexibility', plugins_url( 'assets/lib/flexibility/flexibility.js', GRAVITYVIEW_FILE ), array(), \GV\Plugin::$version, true );
1429
	}
1430
1431
	/**
1432
	 * If the current visitor is running IE 8 or 9, enqueue Flexibility
1433
	 *
1434
	 * @since 1.17
1435
	 *
1436
	 * @return void
1437
	 */
1438 4
	private function maybe_enqueue_flexibility() {
1439 4
		if ( isset( $_SERVER['HTTP_USER_AGENT'] ) && preg_match( '/MSIE [8-9]/', $_SERVER['HTTP_USER_AGENT'] ) ) {
0 ignored issues
show
introduced by
Due to using Batcache, server side based client related logic will not work, use JS instead.
Loading history...
introduced by
Detected usage of a non-sanitized input variable: $_SERVER
Loading history...
1440
			wp_enqueue_script( 'gv-flexibility' );
1441
		}
1442 4
	}
1443
1444
	/**
1445
	 * Enqueue the datepicker script
1446
	 *
1447
	 * It sets the $gravityview->datepicker_class parameter
1448
	 *
1449
	 * @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.
1450
	 * @return void
1451
	 */
1452
	public function enqueue_datepicker() {
1453
		$gravityview_view = GravityView_View::getInstance();
1454
1455
		wp_enqueue_script( 'jquery-ui-datepicker' );
1456
1457
		add_filter( 'gravityview_js_dependencies', array( $this, 'add_datepicker_js_dependency' ) );
1458
		add_filter( 'gravityview_js_localization', array( $this, 'add_datepicker_localization' ), 10, 2 );
1459
1460
		$scheme = is_ssl() ? 'https://' : 'http://';
1461
		wp_enqueue_style( 'jquery-ui-datepicker', $scheme.'ajax.googleapis.com/ajax/libs/jqueryui/1.8.18/themes/smoothness/jquery-ui.css' );
1462
1463
		/**
1464
		 * @filter `gravityview_search_datepicker_class`
1465
		 * 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.
1466
		 * @param string $css_class CSS class to use. Default: `gv-datepicker datepicker mdy` \n
1467
		 * Options are:
1468
		 * - `mdy` (mm/dd/yyyy)
1469
		 * - `dmy` (dd/mm/yyyy)
1470
		 * - `dmy_dash` (dd-mm-yyyy)
1471
		 * - `dmy_dot` (dd.mm.yyyy)
1472
		 * - `ymd_slash` (yyyy/mm/dd)
1473
		 * - `ymd_dash` (yyyy-mm-dd)
1474
		 * - `ymd_dot` (yyyy.mm.dd)
1475
		 */
1476
		$datepicker_class = apply_filters( 'gravityview_search_datepicker_class', "gv-datepicker datepicker " . $this->get_datepicker_format() );
0 ignored issues
show
Coding Style Comprehensibility introduced by
The string literal gv-datepicker datepicker does not require double quotes, as per coding-style, please use single quotes.

PHP provides two ways to mark string literals. Either with single quotes 'literal' or with double quotes "literal". The difference between these is that string literals in double quotes may contain variables with are evaluated at run-time as well as escape sequences.

String literals in single quotes on the other hand are evaluated very literally and the only two characters that needs escaping in the literal are the single quote itself (\') and the backslash (\\). Every other character is displayed as is.

Double quoted string literals may contain other variables or more complex escape sequences.

<?php

$singleQuoted = 'Value';
$doubleQuoted = "\tSingle is $singleQuoted";

print $doubleQuoted;

will print an indented: Single is Value

If your string literal does not contain variables or escape sequences, it should be defined using single quotes to make that fact clear.

For more information on PHP string literals and available escape sequences see the PHP core documentation.

Loading history...
1477
1478
		$gravityview_view->datepicker_class = $datepicker_class;
0 ignored issues
show
Bug introduced by
The property datepicker_class does not seem to exist in GravityView_View.

An attempt at access to an undefined property has been detected. This may either be a typographical error or the property has been renamed but there are still references to its old name.

If you really want to allow access to undefined properties, you can define magic methods to allow access. See the php core documentation on Overloading.

Loading history...
1479
	}
1480
1481
	/**
1482
	 * Retrieve the datepicker format.
1483
	 *
1484
	 * @param bool $date_format Whether to return the PHP date format or the datpicker class name. Default: false.
1485
	 *
1486
	 * @see https://docs.gravityview.co/article/115-changing-the-format-of-the-search-widgets-date-picker
1487
	 *
1488
	 * @return string The datepicker format placeholder, or the PHP date format.
1489
	 */
1490 18
	private function get_datepicker_format( $date_format = false ) {
1491
1492 18
		$default_format = 'mdy';
1493
1494
		/**
1495
		 * @filter `gravityview/widgets/search/datepicker/format`
1496
		 * @since 2.1.1
1497
		 * @param string           $format Default: mdy
1498
		 * Options are:
1499
		 * - `mdy` (mm/dd/yyyy)
1500
		 * - `dmy` (dd/mm/yyyy)
1501
		 * - `dmy_dash` (dd-mm-yyyy)
1502
		 * - `dmy_dot` (dd.mm.yyyy)
1503
		 * - `ymd_slash` (yyyy/mm/dd)
1504
		 * - `ymd_dash` (yyyy-mm-dd)
1505
		 * - `ymd_dot` (yyyy.mm.dd)
1506
		 */
1507 18
		$format = apply_filters( 'gravityview/widgets/search/datepicker/format', $default_format );
1508
1509
		$gf_date_formats = array(
1510 18
			'mdy' => 'm/d/Y',
1511
1512
			'dmy_dash' => 'd-m-Y',
1513
			'dmy_dot' => 'd.m.Y',
1514
			'dmy' => 'd/m/Y',
1515
1516
			'ymd_slash' => 'Y/m/d',
1517
			'ymd_dash' => 'Y-m-d',
1518
			'ymd_dot' => 'Y.m.d',
1519
		);
1520
1521 18
		if ( ! $date_format ) {
1522
			// If the format key isn't valid, return default format key
1523
			return isset( $gf_date_formats[ $format ] ) ? $format : $default_format;
1524
		}
1525
1526
		// If the format key isn't valid, return default format value
1527 18
		return \GV\Utils::get( $gf_date_formats, $format, $gf_date_formats[ $default_format ] );
1528
	}
1529
1530
1531
} // end class
1532
1533
new GravityView_Widget_Search;
1534