Completed
Push — renovate/mocha-8.x ( 07030e...e8e64c )
by
unknown
28:17 queued 19:09
created

Jetpack_Instant_Search   F

Complexity

Total Complexity 71

Size/Duplication

Total Lines 588
Duplicated Lines 7.48 %

Coupling/Cohesion

Components 2
Dependencies 5

Importance

Changes 0
Metric Value
dl 44
loc 588
rs 2.7199
c 0
b 0
f 0
wmc 71
lcom 2
cbo 5

15 Methods

Rating   Name   Duplication   Size   Complexity  
A load_php() 0 8 2
A init_hooks() 16 16 2
A load_assets() 0 18 3
F inject_javascript_options() 8 110 14
A register_jetpack_instant_sidebar() 0 13 1
A print_instant_search_sidebar() 0 9 2
A load_and_initialize_tracks() 0 3 1
A filter__posts_pre_query() 0 16 2
A action__parse_query() 0 25 4
C instant_api() 20 94 8
A get_search_aggregations_results() 0 7 4
A auto_config_search() 0 11 2
F auto_config_overlay_sidebar_widgets() 0 78 17
B get_preconfig_widget_options() 0 60 3
B auto_config_excluded_post_types() 0 26 6

How to fix   Duplicated Code    Complexity   

Duplicated Code

Duplicate code is one of the most pungent code smells. A rule that is often used is to re-structure code once it is duplicated in three or more places.

Common duplication problems, and corresponding solutions are:

Complex Class

 Tip:   Before tackling complexity, make sure that you eliminate any duplication first. This often can reduce the size of classes significantly.

Complex classes like Jetpack_Instant_Search often do a lot of different things. To break such a class down, we need to identify a cohesive component within that class. A common approach to find such a component is to look for fields/methods that share the same prefixes, or suffixes. You can also have a look at the cohesion graph to spot any un-connected, or weakly-connected components.

Once you have determined the fields that belong together, you can apply the Extract Class refactoring. If the component makes sense as a sub-class, Extract Subclass is also a candidate, and is often faster.

While breaking up the class, it is a good idea to analyze how other classes use Jetpack_Instant_Search, and based on these observations, apply Extract Interface, too.

1
<?php
2
/**
3
 * Jetpack Search: Instant Front-End Search and Filtering
4
 *
5
 * @since 8.3.0
6
 * @package jetpack
7
 */
8
9
use Automattic\Jetpack\Connection\Client;
10
use Automattic\Jetpack\Constants;
11
12
/**
13
 * Class to load Instant Search experience on the site.
14
 *
15
 * @since 8.3.0
16
 */
17
class Jetpack_Instant_Search extends Jetpack_Search {
18
19
	/**
20
	 * Loads the php for this version of search
21
	 *
22
	 * @since 8.3.0
23
	 */
24
	public function load_php() {
25
		$this->base_load_php();
26
27
		if ( class_exists( 'WP_Customize_Manager' ) ) {
28
			require_once dirname( __FILE__ ) . '/class-jetpack-search-customize.php';
29
			new Jetpack_Search_Customize();
30
		}
31
	}
32
33
	/**
34
	 * Setup the various hooks needed for the plugin to take over search duties.
35
	 *
36
	 * @since 5.0.0
37
	 */
38 View Code Duplication
	public function init_hooks() {
39
		if ( ! is_admin() ) {
40
			add_filter( 'posts_pre_query', array( $this, 'filter__posts_pre_query' ), 10, 2 );
41
			add_action( 'parse_query', array( $this, 'action__parse_query' ), 10, 1 );
42
43
			add_action( 'init', array( $this, 'set_filters_from_widgets' ) );
44
45
			add_action( 'wp_enqueue_scripts', array( $this, 'load_assets' ) );
46
			add_action( 'wp_footer', array( $this, 'print_instant_search_sidebar' ) );
47
		} else {
48
			add_action( 'update_option', array( $this, 'track_widget_updates' ), 10, 3 );
49
		}
50
51
		add_action( 'widgets_init', array( $this, 'register_jetpack_instant_sidebar' ) );
52
		add_action( 'jetpack_deactivate_module_search', array( $this, 'move_search_widgets_to_inactive' ) );
53
	}
54
55
	/**
56
	 * Loads assets for Jetpack Instant Search Prototype featuring Search As You Type experience.
57
	 */
58
	public function load_assets() {
59
		$script_relative_path = '_inc/build/instant-search/jp-search.bundle.js';
60
		$style_relative_path  = '_inc/build/instant-search/jp-search.bundle.css';
61
		if ( ! file_exists( JETPACK__PLUGIN_DIR . $script_relative_path ) || ! file_exists( JETPACK__PLUGIN_DIR . $style_relative_path ) ) {
62
			return;
63
		}
64
65
		$script_version = Jetpack_Search_Helpers::get_asset_version( $script_relative_path );
66
		$script_path    = plugins_url( $script_relative_path, JETPACK__PLUGIN_FILE );
67
		wp_enqueue_script( 'jetpack-instant-search', $script_path, array(), $script_version, true );
68
		wp_set_script_translations( 'jetpack-instant-search', 'jetpack' );
69
		$this->load_and_initialize_tracks();
70
		$this->inject_javascript_options();
71
72
		$style_version = Jetpack_Search_Helpers::get_asset_version( $style_relative_path );
73
		$style_path    = plugins_url( $style_relative_path, JETPACK__PLUGIN_FILE );
74
		wp_enqueue_style( 'jetpack-instant-search', $style_path, array(), $style_version );
75
	}
76
77
	/**
78
	 * Passes all options to the JS app.
79
	 */
80
	protected function inject_javascript_options() {
81
		$widget_options = Jetpack_Search_Helpers::get_widgets_from_option();
82
		if ( is_array( $widget_options ) ) {
83
			$widget_options = end( $widget_options );
0 ignored issues
show
Unused Code introduced by
$widget_options is not used, you could remove the assignment.

This check looks for variable assignements that are either overwritten by other assignments or where the variable is not used subsequently.

$myVar = 'Value';
$higher = false;

if (rand(1, 6) > 3) {
    $higher = true;
} else {
    $higher = false;
}

Both the $myVar assignment in line 1 and the $higher assignment in line 2 are dead. The first because $myVar is never used and the second because $higher is always overwritten for every possible time line.

Loading history...
84
		}
85
86
		$overlay_widget_ids      = is_active_sidebar( 'jetpack-instant-search-sidebar' ) ?
87
			wp_get_sidebars_widgets()['jetpack-instant-search-sidebar'] : array();
88
		$filters                 = Jetpack_Search_Helpers::get_filters_from_widgets();
89
		$widgets                 = array();
90
		$widgets_outside_overlay = array();
91
		foreach ( $filters as $key => &$filter ) {
92
			$filter['filter_id'] = $key;
93
94
			if ( in_array( $filter['widget_id'], $overlay_widget_ids, true ) ) {
95 View Code Duplication
				if ( ! isset( $widgets[ $filter['widget_id'] ] ) ) {
96
					$widgets[ $filter['widget_id'] ]['filters']   = array();
97
					$widgets[ $filter['widget_id'] ]['widget_id'] = $filter['widget_id'];
98
				}
99
				$widgets[ $filter['widget_id'] ]['filters'][] = $filter;
100
			} else {
101 View Code Duplication
				if ( ! isset( $widgets_outside_overlay[ $filter['widget_id'] ] ) ) {
102
					$widgets_outside_overlay[ $filter['widget_id'] ]['filters']   = array();
103
					$widgets_outside_overlay[ $filter['widget_id'] ]['widget_id'] = $filter['widget_id'];
104
				}
105
				$widgets_outside_overlay[ $filter['widget_id'] ]['filters'][] = $filter;
106
			}
107
		}
108
		unset( $filter );
109
110
		$post_type_objs   = get_post_types( array( 'exclude_from_search' => false ), 'objects' );
111
		$post_type_labels = array();
112
		foreach ( $post_type_objs as $key => $obj ) {
113
			$post_type_labels[ $key ] = array(
114
				'singular_name' => $obj->labels->singular_name,
115
				'name'          => $obj->labels->name,
116
			);
117
		}
118
119
		$prefix         = Jetpack_Search_Options::OPTION_PREFIX;
120
		$posts_per_page = (int) get_option( 'posts_per_page' );
121
		if ( ( $posts_per_page > 20 ) || ( $posts_per_page <= 0 ) ) {
122
			$posts_per_page = 20;
123
		}
124
125
		$excluded_post_types   = get_option( $prefix . 'excluded_post_types' ) ? explode( ',', get_option( $prefix . 'excluded_post_types', '' ) ) : array();
126
		$post_types            = array_values(
127
			get_post_types(
128
				array(
129
					'exclude_from_search' => false,
130
					'public'              => true,
131
				)
132
			)
133
		);
134
		$unexcluded_post_types = array_diff( $post_types, $excluded_post_types );
135
		// NOTE: If all post types are being excluded, ignore the option value.
136
		if ( count( $unexcluded_post_types ) === 0 ) {
137
			$excluded_post_types = array();
138
		}
139
140
		$options = array(
141
			'overlayOptions'        => array(
142
				'colorTheme'      => get_option( $prefix . 'color_theme', 'light' ),
143
				'enableInfScroll' => get_option( $prefix . 'inf_scroll', '1' ) === '1',
144
				'enableSort'      => get_option( $prefix . 'enable_sort', '1' ) === '1',
145
				'highlightColor'  => get_option( $prefix . 'highlight_color', '#FFC' ),
146
				'opacity'         => (int) get_option( $prefix . 'opacity', 97 ),
147
				'overlayTrigger'  => get_option( $prefix . 'overlay_trigger', 'immediate' ),
148
				'resultFormat'    => get_option( $prefix . 'result_format', 'minimal' ),
149
				'showPoweredBy'   => get_option( $prefix . 'show_powered_by', '1' ) === '1',
150
			),
151
152
			// core config.
153
			'homeUrl'               => home_url(),
154
			'locale'                => str_replace( '_', '-', Jetpack_Search_Helpers::is_valid_locale( get_locale() ) ? get_locale() : 'en_US' ),
155
			'postsPerPage'          => $posts_per_page,
156
			'siteId'                => $this->jetpack_blog_id,
157
			'postTypes'             => $post_type_labels,
158
			'webpackPublicPath'     => plugins_url( '_inc/build/instant-search/', JETPACK__PLUGIN_FILE ),
159
160
			// config values related to private site support.
161
			'apiRoot'               => esc_url_raw( rest_url() ),
162
			'apiNonce'              => wp_create_nonce( 'wp_rest' ),
163
			'isPrivateSite'         => '-1' === get_option( 'blog_public' ),
164
			'isWpcom'               => defined( 'IS_WPCOM' ) && IS_WPCOM,
165
166
			// search options.
167
			'defaultSort'           => get_option( $prefix . 'default_sort', 'relevance' ),
168
			'excludedPostTypes'     => $excluded_post_types,
169
170
			// widget info.
171
			'hasOverlayWidgets'     => count( $overlay_widget_ids ) > 0,
172
			'widgets'               => array_values( $widgets ),
173
			'widgetsOutsideOverlay' => array_values( $widgets_outside_overlay ),
174
		);
175
176
		/**
177
		 * Customize Instant Search Options.
178
		 *
179
		 * @module search
180
		 *
181
		 * @since 7.7.0
182
		 *
183
		 * @param array $options Array of parameters used in Instant Search queries.
184
		 */
185
		$options = apply_filters( 'jetpack_instant_search_options', $options );
186
187
		// Use wp_add_inline_script instead of wp_localize_script, see https://core.trac.wordpress.org/ticket/25280.
188
		wp_add_inline_script( 'jetpack-instant-search', 'var JetpackInstantSearchOptions=JSON.parse(decodeURIComponent("' . rawurlencode( wp_json_encode( $options ) ) . '"));', 'before' );
189
	}
190
191
	/**
192
	 * Registers a widget sidebar for Instant Search.
193
	 */
194
	public function register_jetpack_instant_sidebar() {
195
		$args = array(
196
			'name'          => __( 'Jetpack Search Sidebar', 'jetpack' ),
197
			'id'            => 'jetpack-instant-search-sidebar',
198
			'description'   => __( 'Customize the sidebar inside the Jetpack Search overlay', 'jetpack' ),
199
			'class'         => '',
200
			'before_widget' => '<div id="%1$s" class="widget %2$s">',
201
			'after_widget'  => '</div>',
202
			'before_title'  => '<h2 class="widgettitle">',
203
			'after_title'   => '</h2>',
204
		);
205
		register_sidebar( $args );
206
	}
207
208
	/**
209
	 * Prints Instant Search sidebar.
210
	 */
211
	public function print_instant_search_sidebar() {
212
		?>
213
		<div class="jetpack-instant-search__widget-area" style="display: none">
214
			<?php if ( is_active_sidebar( 'jetpack-instant-search-sidebar' ) ) { ?>
215
				<?php dynamic_sidebar( 'jetpack-instant-search-sidebar' ); ?>
216
			<?php } ?>
217
		</div>
218
		<?php
219
	}
220
221
	/**
222
	 * Loads scripts for Tracks analytics library
223
	 */
224
	public function load_and_initialize_tracks() {
225
		wp_enqueue_script( 'jp-tracks', '//stats.wp.com/w.js', array(), gmdate( 'YW' ), true );
226
	}
227
228
	/**
229
	 * Bypass the normal Search query since we will run it with instant search.
230
	 *
231
	 * @since 8.3.0
232
	 *
233
	 * @param array    $posts Current array of posts (still pre-query).
234
	 * @param WP_Query $query The WP_Query being filtered.
235
	 *
236
	 * @return array Array of matching posts.
237
	 */
238
	public function filter__posts_pre_query( $posts, $query ) {
239
		if ( ! $this->should_handle_query( $query ) ) {
240
			// Intentionally not adding the 'jetpack_search_abort' action since this should fire for every request except for search.
241
			return $posts;
242
		}
243
244
		/**
245
		 * Bypass the main query and return dummy data
246
		 *  WP Core doesn't call the set_found_posts and its filters when filtering
247
		 *  posts_pre_query like we do, so need to do these manually.
248
		 */
249
		$query->found_posts   = 1;
250
		$query->max_num_pages = 1;
251
252
		return array();
253
	}
254
255
	/**
256
	 * Run the aggregations API query for any filtering
257
	 *
258
	 * @since 8.3.0
259
	 */
260
	public function action__parse_query() {
261
		if ( ! empty( $this->search_result ) ) {
262
			return;
263
		}
264
265
		if ( is_admin() ) {
266
			return;
267
		}
268
269
		if ( empty( $this->aggregations ) ) {
270
			return;
271
		}
272
273
		jetpack_require_lib( 'jetpack-wpes-query-builder/jetpack-wpes-query-builder' );
274
275
		$builder = new Jetpack_WPES_Query_Builder();
276
		$this->add_aggregations_to_es_query_builder( $this->aggregations, $builder );
277
		$this->search_result = $this->instant_api(
0 ignored issues
show
Documentation Bug introduced by
It seems like $this->instant_api(array...ze' => 0, 'from' => 0)) of type object is incompatible with the declared type array of property $search_result.

Our type inference engine has found an assignment to a property that is incompatible with the declared type of that property.

Either this assignment is in error or the assigned type should be added to the documentation/type hint for that property..

Loading history...
278
			array(
279
				'aggregations' => $builder->build_aggregation(),
280
				'size'         => 0,
281
				'from'         => 0,
282
			)
283
		);
284
	}
285
286
	/**
287
	 * Run an instant search on the WordPress.com public API.
288
	 *
289
	 * @since 8.3.0
290
	 *
291
	 * @param array $args Args conforming to the WP.com v1.3/sites/<blog_id>/search endpoint.
292
	 *
293
	 * @return object|WP_Error The response from the public API, or a WP_Error.
294
	 */
295
	public function instant_api( array $args ) {
296
		global $wp_version;
297
		$start_time = microtime( true );
298
299
		// Cache locally to avoid remote request slowing the page.
300
		$transient_name = 'jetpack_instant_search_cache_' . md5( wp_json_encode( $args ) );
301
		$cache          = get_transient( $transient_name );
302
		if ( false !== $cache ) {
303
			return $cache;
304
		}
305
306
		$service_url = add_query_arg(
307
			$args,
308
			sprintf(
309
				'https://public-api.wordpress.com/rest/v1.3/sites/%d/search',
310
				$this->jetpack_blog_id
311
			)
312
		);
313
314
		$request_args = array(
315
			'timeout'    => 10,
316
			'user-agent' => "WordPress/{$wp_version} | Jetpack/" . constant( 'JETPACK__VERSION' ),
317
		);
318
319
		$request  = wp_remote_get( esc_url_raw( $service_url ), $request_args );
320
		$end_time = microtime( true );
321
322
		if ( is_wp_error( $request ) ) {
323
			return $request;
324
		}
325
326
		$response_code = wp_remote_retrieve_response_code( $request );
327
		$response      = json_decode( wp_remote_retrieve_body( $request ), true );
328
329 View Code Duplication
		if ( ! $response_code || $response_code < 200 || $response_code >= 300 ) {
330
			/**
331
			 * Fires after a search query request has failed
332
			 *
333
			 * @module search
334
			 *
335
			 * @since  5.6.0
336
			 *
337
			 * @param array Array containing the response code and response from the failed search query
338
			 */
339
			do_action(
340
				'failed_jetpack_search_query',
341
				array(
342
					'response_code' => $response_code,
343
					'json'          => $response,
344
				)
345
			);
346
347
			return new WP_Error( 'invalid_search_api_response', 'Invalid response from API - ' . $response_code );
0 ignored issues
show
Unused Code introduced by
The call to WP_Error::__construct() has too many arguments starting with 'invalid_search_api_response'.

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...
348
		}
349
350
		$took = is_array( $response ) && ! empty( $response['took'] )
351
			? $response['took']
352
			: null;
353
354
		$query = array(
355
			'args'          => $args,
356
			'response'      => $response,
357
			'response_code' => $response_code,
358
			'elapsed_time'  => ( $end_time - $start_time ) * 1000, // Convert from float seconds to ms.
359
			'es_time'       => $took,
360
			'url'           => $service_url,
361
		);
362
363
		/**
364
		 * Fires after a search request has been performed.
365
		 *
366
		 * Includes the following info in the $query parameter:
367
		 *
368
		 * array args Array of Elasticsearch arguments for the search
369
		 * array response Raw API response, JSON decoded
370
		 * int response_code HTTP response code of the request
371
		 * float elapsed_time Roundtrip time of the search request, in milliseconds
372
		 * float es_time Amount of time Elasticsearch spent running the request, in milliseconds
373
		 * string url API url that was queried
374
		 *
375
		 * @module search
376
		 *
377
		 * @since  5.0.0
378
		 * @since  5.8.0 This action now fires on all queries instead of just successful queries.
379
		 *
380
		 * @param array $query Array of information about the query performed
381
		 */
382
		do_action( 'did_jetpack_search_query', $query );
383
384
		// Update local cache.
385
		set_transient( $transient_name, $response, 1 * HOUR_IN_SECONDS );
386
387
		return $response;
388
	}
389
390
	/**
391
	 * Get the raw Aggregation results from the Elasticsearch response.
392
	 *
393
	 * @since  8.4.0
394
	 *
395
	 * @return array Array of Aggregations performed on the search.
396
	 */
397
	public function get_search_aggregations_results() {
398
		if ( empty( $this->search_result ) || is_wp_error( $this->search_result ) || ! isset( $this->search_result['aggregations'] ) ) {
399
			return array();
400
		}
401
402
		return $this->search_result['aggregations'];
403
	}
404
405
	/**
406
	 * Automatically configure necessary settings for instant search
407
	 *
408
	 * @since  8.3.0
409
	 */
410
	public function auto_config_search() {
411
		if ( ! current_user_can( 'edit_theme_options' ) ) {
412
			return;
413
		}
414
415
		// Set default result format to "expanded".
416
		update_option( Jetpack_Search_Options::OPTION_PREFIX . 'result_format', 'expanded' );
417
418
		$this->auto_config_excluded_post_types();
419
		$this->auto_config_overlay_sidebar_widgets();
420
	}
421
422
	/**
423
	 * Automatically copy configured search widgets into the overlay sidebar
424
	 *
425
	 * @since  8.8.0
426
	 */
427
	public function auto_config_overlay_sidebar_widgets() {
428
		global $wp_registered_sidebars;
429
		$sidebars = get_option( 'sidebars_widgets', array() );
430
		$slug     = Jetpack_Search_Helpers::FILTER_WIDGET_BASE;
431
432
		if ( isset( $sidebars['jetpack-instant-search-sidebar'] ) ) {
433
			foreach ( (array) $sidebars['jetpack-instant-search-sidebar'] as $widget_id ) {
434
				if ( 0 === strpos( $widget_id, $slug ) ) {
435
					// Already configured.
436
					return;
437
				}
438
			}
439
		}
440
441
		$has_sidebar           = isset( $wp_registered_sidebars['sidebar-1'] );
442
		$sidebar_id            = false;
443
		$sidebar_searchbox_idx = false;
444
		if ( $has_sidebar ) {
445
			if ( empty( $sidebars['sidebar-1'] ) ) {
446
				// Adding to an empty sidebar is generally a bad idea.
447
				$has_sidebar = false;
448
			}
449
			foreach ( (array) $sidebars['sidebar-1'] as $idx => $widget_id ) {
450
				if ( 0 === strpos( $widget_id, 'search-' ) ) {
451
					$sidebar_searchbox_idx = $idx;
452
				}
453
				if ( 0 === strpos( $widget_id, $slug ) ) {
454
					$sidebar_id = (int) str_replace( Jetpack_Search_Helpers::FILTER_WIDGET_BASE . '-', '', $widget_id );
455
					break;
456
				}
457
			}
458
		}
459
460
		$next_id         = 1;
461
		$widget_opt_name = Jetpack_Search_Helpers::get_widget_option_name();
462
		$widget_options  = get_option( $widget_opt_name, array() );
463
		foreach ( $widget_options as $id => $w ) {
464
			if ( $id >= $next_id ) {
465
				$next_id = $id + 1;
466
			}
467
		}
468
469
		// Copy sidebar settings to overlay.
470
		if ( ( false !== $sidebar_id ) && isset( $widget_options[ $sidebar_id ] ) ) {
471
			$widget_options[ $next_id ] = $widget_options[ $sidebar_id ];
472
			update_option( $widget_opt_name, $widget_options );
473
474
			if ( ! isset( $sidebars['jetpack-instant-search-sidebar'] ) ) {
475
				$sidebars['jetpack-instant-search-sidebar'] = array();
476
			}
477
			array_unshift( $sidebars['jetpack-instant-search-sidebar'], Jetpack_Search_Helpers::build_widget_id( $next_id ) );
478
			update_option( 'sidebars_widgets', $sidebars );
479
480
			return;
481
		}
482
483
		// Configure overlay and sidebar (if it exists).
484
		$preconfig_opts = $this->get_preconfig_widget_options();
485
		if ( ! isset( $sidebars['jetpack-instant-search-sidebar'] ) ) {
486
			$sidebars['jetpack-instant-search-sidebar'] = array();
487
		}
488
		if ( $has_sidebar ) {
489
			$widget_options[ $next_id ] = $preconfig_opts;
490
			if ( false !== $sidebar_searchbox_idx ) {
491
				// Replace Core search box.
492
				$sidebars['sidebar-1'][ $sidebar_searchbox_idx ] = Jetpack_Search_Helpers::build_widget_id( $next_id );
493
			} else {
494
				// Add to top.
495
				array_unshift( $sidebars['sidebar-1'], Jetpack_Search_Helpers::build_widget_id( $next_id ) );
496
			}
497
			$next_id++;
498
		}
499
		$widget_options[ $next_id ] = $preconfig_opts;
500
		array_unshift( $sidebars['jetpack-instant-search-sidebar'], Jetpack_Search_Helpers::build_widget_id( $next_id ) );
501
502
		update_option( $widget_opt_name, $widget_options );
503
		update_option( 'sidebars_widgets', $sidebars );
504
	}
505
506
	/**
507
	 * Autoconfig search by adding filter widgets
508
	 *
509
	 * @since  8.4.0
510
	 *
511
	 * @return array Array of config settings for search widget.
512
	 */
513
	protected function get_preconfig_widget_options() {
514
		$settings = array(
515
			'title'   => '',
516
			'filters' => array(),
517
		);
518
519
		$post_types = get_post_types(
520
			array(
521
				'public'   => true,
522
				'_builtin' => false,
523
			)
524
		);
525
526
		if ( ! empty( $post_types ) ) {
527
			$settings['filters'][] = array(
528
				array(
529
					'name'  => '',
530
					'type'  => 'post_type',
531
					'count' => 5,
532
				),
533
			);
534
		}
535
536
		$taxonomies = get_taxonomies(
537
			array(
538
				'public'   => true,
539
				'_builtin' => false,
540
			)
541
		);
542
543
		foreach ( $taxonomies as $t ) {
544
			$settings['filters'][] = array(
545
				'name'     => '',
546
				'type'     => 'taxonomy',
547
				'taxonomy' => $t,
548
				'count'    => 5,
549
			);
550
		}
551
552
		$settings['filters'][] = array(
553
			'name'     => '',
554
			'type'     => 'taxonomy',
555
			'taxonomy' => 'category',
556
			'count'    => 5,
557
		);
558
		$settings['filters'][] = array(
559
			'name'     => '',
560
			'type'     => 'taxonomy',
561
			'taxonomy' => 'post_tag',
562
			'count'    => 5,
563
		);
564
		$settings['filters'][] = array(
565
			'name'     => '',
566
			'type'     => 'date_histogram',
567
			'count'    => 5,
568
			'field'    => 'post_date',
569
			'interval' => 'year',
570
		);
571
		return $settings;
572
	}
573
	/**
574
	 * Automatically configure post types to exclude from one of the search widgets
575
	 *
576
	 * @since  8.8.0
577
	 */
578
	public function auto_config_excluded_post_types() {
579
		$post_types         = get_post_types(
580
			array(
581
				'exclude_from_search' => false,
582
				'public'              => true,
583
			)
584
		);
585
		$enabled_post_types = array();
586
		$widget_options     = get_option( Jetpack_Search_Helpers::get_widget_option_name(), array() );
587
588
		// Prior to Jetpack 8.8, post types were enabled via Jetpack Search widgets rather than disabled via the Customizer.
589
		// To continue supporting post types set up in the old way, we iterate through each Jetpack Search
590
		// widget configuration and append each enabled post type to $enabled_post_types.
591
		foreach ( $widget_options as $widget_option ) {
592
			if ( isset( $widget_option['post_types'] ) && is_array( $widget_option['post_types'] ) ) {
593
				foreach ( $widget_option['post_types'] as $enabled_post_type ) {
594
					$enabled_post_types[ $enabled_post_type ] = $enabled_post_type;
595
				}
596
			}
597
		}
598
599
		if ( ! empty( $enabled_post_types ) ) {
600
			$post_types_to_disable = array_diff( $post_types, $enabled_post_types );
601
			update_option( Jetpack_Search_Options::OPTION_PREFIX . 'excluded_post_types', join( ',', $post_types_to_disable ) );
602
		}
603
	}
604
}
605