Completed
Push — jetpack/branch-9.4 ( 6f8578...4735d8 )
by Jeremy
09:21
created

load_assets_with_parameters()   A

Complexity

Conditions 4
Paths 2

Size

Total Lines 33

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 4
nc 2
nop 2
dl 0
loc 33
rs 9.392
c 0
b 0
f 0
1
<?php
2
/**
3
 * Jetpack Search: Instant Front-End Search and Filtering
4
 *
5
 * @since 8.3.0
6
 * @package jetpack
7
 */
8
9
/**
10
 * Class to load Instant Search experience on the site.
11
 *
12
 * @since 8.3.0
13
 */
14
class Jetpack_Instant_Search extends Jetpack_Search {
15
16
	/**
17
	 * Loads the php for this version of search
18
	 *
19
	 * @since 8.3.0
20
	 */
21
	public function load_php() {
22
		$this->base_load_php();
23
24
		if ( class_exists( 'WP_Customize_Manager' ) ) {
25
			require_once __DIR__ . '/class-jetpack-search-customize.php';
26
			new Jetpack_Search_Customize();
27
		}
28
	}
29
30
	/**
31
	 * Setup the various hooks needed for the plugin to take over search duties.
32
	 *
33
	 * @since 5.0.0
34
	 */
35 View Code Duplication
	public function init_hooks() {
36
		if ( ! is_admin() ) {
37
			add_filter( 'posts_pre_query', array( $this, 'filter__posts_pre_query' ), 10, 2 );
38
			add_action( 'parse_query', array( $this, 'action__parse_query' ), 10, 1 );
39
40
			add_action( 'init', array( $this, 'set_filters_from_widgets' ) );
41
42
			add_action( 'wp_enqueue_scripts', array( $this, 'load_assets' ) );
43
			add_action( 'wp_footer', array( $this, 'print_instant_search_sidebar' ) );
44
		} else {
45
			add_action( 'update_option', array( $this, 'track_widget_updates' ), 10, 3 );
46
		}
47
48
		add_action( 'widgets_init', array( $this, 'register_jetpack_instant_sidebar' ) );
49
		add_action( 'jetpack_deactivate_module_search', array( $this, 'move_search_widgets_to_inactive' ) );
50
	}
51
52
	/**
53
	 * Loads assets for Jetpack Instant Search Prototype featuring Search As You Type experience.
54
	 */
55
	public function load_assets() {
56
		$this->load_assets_with_parameters( '', JETPACK__PLUGIN_FILE );
57
	}
58
59
	/**
60
	 * Loads assets according to parameters provided.
61
	 *
62
	 * @param string $path_prefix - Prefix for assets' relative paths.
63
	 * @param string $plugin_base_path - Base path for use in plugins_url.
64
	 */
65
	public function load_assets_with_parameters( $path_prefix, $plugin_base_path ) {
66
		$polyfill_relative_path = $path_prefix . '_inc/build/instant-search/jp-search-ie11-polyfill-loader.bundle.js';
67
		$script_relative_path   = $path_prefix . '_inc/build/instant-search/jp-search-main.bundle.js';
68
		$style_relative_path    = $path_prefix . '_inc/build/instant-search/jp-search-main.bundle.css';
69
70
		if (
71
			! file_exists( JETPACK__PLUGIN_DIR . $polyfill_relative_path ) ||
72
			! file_exists( JETPACK__PLUGIN_DIR . $script_relative_path ) ||
73
			! file_exists( JETPACK__PLUGIN_DIR . $style_relative_path )
74
		) {
75
			return;
76
		}
77
78
		$polyfill_version = Jetpack_Search_Helpers::get_asset_version( $polyfill_relative_path );
79
		$polyfill_path    = plugins_url( $polyfill_relative_path, $plugin_base_path );
80
		wp_enqueue_script( 'jetpack-instant-search-ie11', $polyfill_path, array(), $polyfill_version, true );
81
		$polyfill_payload_path = plugins_url(
82
			$path_prefix . '_inc/build/instant-search/jp-search-ie11-polyfill-payload.bundle.js',
83
			$plugin_base_path
84
		);
85
		$this->inject_polyfill_js_options( $polyfill_payload_path );
86
87
		$script_version = Jetpack_Search_Helpers::get_asset_version( $script_relative_path );
88
		$script_path    = plugins_url( $script_relative_path, $plugin_base_path );
89
		wp_enqueue_script( 'jetpack-instant-search', $script_path, array(), $script_version, true );
90
		wp_set_script_translations( 'jetpack-instant-search', 'jetpack' );
91
		$this->load_and_initialize_tracks();
92
		$this->inject_javascript_options();
93
94
		$style_version = Jetpack_Search_Helpers::get_asset_version( $style_relative_path );
95
		$style_path    = plugins_url( $style_relative_path, $plugin_base_path );
96
		wp_enqueue_style( 'jetpack-instant-search', $style_path, array(), $style_version );
97
	}
98
99
	/**
100
	 * Passes all options to the JS app.
101
	 */
102
	protected function inject_javascript_options() {
103
		$widget_options = Jetpack_Search_Helpers::get_widgets_from_option();
104
		if ( is_array( $widget_options ) ) {
105
			$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...
106
		}
107
108
		$overlay_widget_ids      = is_active_sidebar( 'jetpack-instant-search-sidebar' ) ?
109
			wp_get_sidebars_widgets()['jetpack-instant-search-sidebar'] : array();
110
		$filters                 = Jetpack_Search_Helpers::get_filters_from_widgets();
111
		$widgets                 = array();
112
		$widgets_outside_overlay = array();
113
		foreach ( $filters as $key => &$filter ) {
114
			$filter['filter_id'] = $key;
115
116
			if ( in_array( $filter['widget_id'], $overlay_widget_ids, true ) ) {
117 View Code Duplication
				if ( ! isset( $widgets[ $filter['widget_id'] ] ) ) {
118
					$widgets[ $filter['widget_id'] ]['filters']   = array();
119
					$widgets[ $filter['widget_id'] ]['widget_id'] = $filter['widget_id'];
120
				}
121
				$widgets[ $filter['widget_id'] ]['filters'][] = $filter;
122
			} else {
123 View Code Duplication
				if ( ! isset( $widgets_outside_overlay[ $filter['widget_id'] ] ) ) {
124
					$widgets_outside_overlay[ $filter['widget_id'] ]['filters']   = array();
125
					$widgets_outside_overlay[ $filter['widget_id'] ]['widget_id'] = $filter['widget_id'];
126
				}
127
				$widgets_outside_overlay[ $filter['widget_id'] ]['filters'][] = $filter;
128
			}
129
		}
130
		unset( $filter );
131
132
		$post_type_objs   = get_post_types( array( 'exclude_from_search' => false ), 'objects' );
133
		$post_type_labels = array();
134
		foreach ( $post_type_objs as $key => $obj ) {
135
			$post_type_labels[ $key ] = array(
136
				'singular_name' => $obj->labels->singular_name,
137
				'name'          => $obj->labels->name,
138
			);
139
		}
140
141
		$prefix         = Jetpack_Search_Options::OPTION_PREFIX;
142
		$posts_per_page = (int) get_option( 'posts_per_page' );
143
		if ( ( $posts_per_page > 20 ) || ( $posts_per_page <= 0 ) ) {
144
			$posts_per_page = 20;
145
		}
146
147
		$excluded_post_types   = get_option( $prefix . 'excluded_post_types' ) ? explode( ',', get_option( $prefix . 'excluded_post_types', '' ) ) : array();
148
		$post_types            = array_values(
149
			get_post_types(
150
				array(
151
					'exclude_from_search' => false,
152
					'public'              => true,
153
				)
154
			)
155
		);
156
		$unexcluded_post_types = array_diff( $post_types, $excluded_post_types );
157
		// NOTE: If all post types are being excluded, ignore the option value.
158
		if ( count( $unexcluded_post_types ) === 0 ) {
159
			$excluded_post_types = array();
160
		}
161
162
		$options = array(
163
			'overlayOptions'        => array(
164
				'colorTheme'      => get_option( $prefix . 'color_theme', 'light' ),
165
				'enableInfScroll' => get_option( $prefix . 'inf_scroll', '1' ) === '1',
166
				'enableSort'      => get_option( $prefix . 'enable_sort', '1' ) === '1',
167
				'highlightColor'  => get_option( $prefix . 'highlight_color', '#FFC' ),
168
				'opacity'         => (int) get_option( $prefix . 'opacity', 97 ),
169
				'overlayTrigger'  => get_option( $prefix . 'overlay_trigger', 'immediate' ),
170
				'resultFormat'    => get_option( $prefix . 'result_format', 'minimal' ),
171
				'showPoweredBy'   => get_option( $prefix . 'show_powered_by', '1' ) === '1',
172
			),
173
174
			// core config.
175
			'homeUrl'               => home_url(),
176
			'locale'                => str_replace( '_', '-', Jetpack_Search_Helpers::is_valid_locale( get_locale() ) ? get_locale() : 'en_US' ),
177
			'postsPerPage'          => $posts_per_page,
178
			'siteId'                => $this->jetpack_blog_id,
179
			'postTypes'             => $post_type_labels,
180
			'webpackPublicPath'     => plugins_url( '_inc/build/instant-search/', JETPACK__PLUGIN_FILE ),
181
182
			// config values related to private site support.
183
			'apiRoot'               => esc_url_raw( rest_url() ),
184
			'apiNonce'              => wp_create_nonce( 'wp_rest' ),
185
			'isPrivateSite'         => '-1' === get_option( 'blog_public' ),
186
			'isWpcom'               => defined( 'IS_WPCOM' ) && IS_WPCOM,
187
188
			// search options.
189
			'defaultSort'           => get_option( $prefix . 'default_sort', 'relevance' ),
190
			'excludedPostTypes'     => $excluded_post_types,
191
192
			// widget info.
193
			'hasOverlayWidgets'     => count( $overlay_widget_ids ) > 0,
194
			'widgets'               => array_values( $widgets ),
195
			'widgetsOutsideOverlay' => array_values( $widgets_outside_overlay ),
196
		);
197
198
		/**
199
		 * Customize Instant Search Options.
200
		 *
201
		 * @module search
202
		 *
203
		 * @since 7.7.0
204
		 *
205
		 * @param array $options Array of parameters used in Instant Search queries.
206
		 */
207
		$options = apply_filters( 'jetpack_instant_search_options', $options );
208
209
		// Use wp_add_inline_script instead of wp_localize_script, see https://core.trac.wordpress.org/ticket/25280.
210
		wp_add_inline_script( 'jetpack-instant-search', 'var JetpackInstantSearchOptions=JSON.parse(decodeURIComponent("' . rawurlencode( wp_json_encode( $options ) ) . '"));', 'before' );
211
	}
212
213
	/**
214
	 * Passes options to the polyfill loader script.
215
	 *
216
	 * @param string $polyfill_payload_path - Absolute path to the IE11 polyfill payload.
217
	 */
218
	protected function inject_polyfill_js_options( $polyfill_payload_path ) {
219
		wp_add_inline_script( 'jetpack-instant-search-ie11', 'var JetpackInstantSearchIe11PolyfillPath=decodeURIComponent("' . rawurlencode( $polyfill_payload_path ) . '");', 'before' );
220
	}
221
222
	/**
223
	 * Registers a widget sidebar for Instant Search.
224
	 */
225
	public function register_jetpack_instant_sidebar() {
226
		$args = array(
227
			'name'          => __( 'Jetpack Search Sidebar', 'jetpack' ),
228
			'id'            => 'jetpack-instant-search-sidebar',
229
			'description'   => __( 'Customize the sidebar inside the Jetpack Search overlay', 'jetpack' ),
230
			'class'         => '',
231
			'before_widget' => '<div id="%1$s" class="widget %2$s">',
232
			'after_widget'  => '</div>',
233
			'before_title'  => '<h2 class="widgettitle">',
234
			'after_title'   => '</h2>',
235
		);
236
		register_sidebar( $args );
237
	}
238
239
	/**
240
	 * Prints Instant Search sidebar.
241
	 */
242
	public function print_instant_search_sidebar() {
243
		?>
244
		<div class="jetpack-instant-search__widget-area" style="display: none">
245
			<?php if ( is_active_sidebar( 'jetpack-instant-search-sidebar' ) ) { ?>
246
				<?php dynamic_sidebar( 'jetpack-instant-search-sidebar' ); ?>
247
			<?php } ?>
248
		</div>
249
		<?php
250
	}
251
252
	/**
253
	 * Loads scripts for Tracks analytics library
254
	 */
255
	public function load_and_initialize_tracks() {
256
		wp_enqueue_script( 'jp-tracks', '//stats.wp.com/w.js', array(), gmdate( 'YW' ), true );
257
	}
258
259
	/**
260
	 * Bypass the normal Search query since we will run it with instant search.
261
	 *
262
	 * @since 8.3.0
263
	 *
264
	 * @param array    $posts Current array of posts (still pre-query).
265
	 * @param WP_Query $query The WP_Query being filtered.
266
	 *
267
	 * @return array Array of matching posts.
268
	 */
269
	public function filter__posts_pre_query( $posts, $query ) {
270
		if ( ! $this->should_handle_query( $query ) ) {
271
			// Intentionally not adding the 'jetpack_search_abort' action since this should fire for every request except for search.
272
			return $posts;
273
		}
274
275
		/**
276
		 * Bypass the main query and return dummy data
277
		 *  WP Core doesn't call the set_found_posts and its filters when filtering
278
		 *  posts_pre_query like we do, so need to do these manually.
279
		 */
280
		$query->found_posts   = 1;
281
		$query->max_num_pages = 1;
282
283
		return array();
284
	}
285
286
	/**
287
	 * Run the aggregations API query for any filtering
288
	 *
289
	 * @since 8.3.0
290
	 */
291
	public function action__parse_query() {
292
		if ( ! empty( $this->search_result ) ) {
293
			return;
294
		}
295
296
		if ( is_admin() ) {
297
			return;
298
		}
299
300
		if ( empty( $this->aggregations ) ) {
301
			return;
302
		}
303
304
		jetpack_require_lib( 'jetpack-wpes-query-builder/jetpack-wpes-query-builder' );
305
306
		$builder = new Jetpack_WPES_Query_Builder();
307
		$this->add_aggregations_to_es_query_builder( $this->aggregations, $builder );
308
		$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...
309
			array(
310
				'aggregations' => $builder->build_aggregation(),
311
				'size'         => 0,
312
				'from'         => 0,
313
			)
314
		);
315
	}
316
317
	/**
318
	 * Run an instant search on the WordPress.com public API.
319
	 *
320
	 * @since 8.3.0
321
	 *
322
	 * @param array $args Args conforming to the WP.com v1.3/sites/<blog_id>/search endpoint.
323
	 *
324
	 * @return object|WP_Error The response from the public API, or a WP_Error.
325
	 */
326
	public function instant_api( array $args ) {
327
		global $wp_version;
328
		$start_time = microtime( true );
329
330
		// Cache locally to avoid remote request slowing the page.
331
		$transient_name = 'jetpack_instant_search_cache_' . md5( wp_json_encode( $args ) );
332
		$cache          = get_transient( $transient_name );
333
		if ( false !== $cache ) {
334
			return $cache;
335
		}
336
337
		$service_url = add_query_arg(
338
			$args,
339
			sprintf(
340
				'https://public-api.wordpress.com/rest/v1.3/sites/%d/search',
341
				$this->jetpack_blog_id
342
			)
343
		);
344
345
		$request_args = array(
346
			'timeout'    => 10,
347
			'user-agent' => "WordPress/{$wp_version} | Jetpack/" . constant( 'JETPACK__VERSION' ),
348
		);
349
350
		$request  = wp_remote_get( esc_url_raw( $service_url ), $request_args );
351
		$end_time = microtime( true );
352
353
		if ( is_wp_error( $request ) ) {
354
			return $request;
355
		}
356
357
		$response_code = wp_remote_retrieve_response_code( $request );
358
		$response      = json_decode( wp_remote_retrieve_body( $request ), true );
359
360 View Code Duplication
		if ( ! $response_code || $response_code < 200 || $response_code >= 300 ) {
361
			/**
362
			 * Fires after a search query request has failed
363
			 *
364
			 * @module search
365
			 *
366
			 * @since  5.6.0
367
			 *
368
			 * @param array Array containing the response code and response from the failed search query
369
			 */
370
			do_action(
371
				'failed_jetpack_search_query',
372
				array(
373
					'response_code' => $response_code,
374
					'json'          => $response,
375
				)
376
			);
377
378
			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...
379
		}
380
381
		$took = is_array( $response ) && ! empty( $response['took'] )
382
			? $response['took']
383
			: null;
384
385
		$query = array(
386
			'args'          => $args,
387
			'response'      => $response,
388
			'response_code' => $response_code,
389
			'elapsed_time'  => ( $end_time - $start_time ) * 1000, // Convert from float seconds to ms.
390
			'es_time'       => $took,
391
			'url'           => $service_url,
392
		);
393
394
		/**
395
		 * Fires after a search request has been performed.
396
		 *
397
		 * Includes the following info in the $query parameter:
398
		 *
399
		 * array args Array of Elasticsearch arguments for the search
400
		 * array response Raw API response, JSON decoded
401
		 * int response_code HTTP response code of the request
402
		 * float elapsed_time Roundtrip time of the search request, in milliseconds
403
		 * float es_time Amount of time Elasticsearch spent running the request, in milliseconds
404
		 * string url API url that was queried
405
		 *
406
		 * @module search
407
		 *
408
		 * @since  5.0.0
409
		 * @since  5.8.0 This action now fires on all queries instead of just successful queries.
410
		 *
411
		 * @param array $query Array of information about the query performed
412
		 */
413
		do_action( 'did_jetpack_search_query', $query );
414
415
		// Update local cache.
416
		set_transient( $transient_name, $response, 1 * HOUR_IN_SECONDS );
417
418
		return $response;
419
	}
420
421
	/**
422
	 * Get the raw Aggregation results from the Elasticsearch response.
423
	 *
424
	 * @since  8.4.0
425
	 *
426
	 * @return array Array of Aggregations performed on the search.
427
	 */
428
	public function get_search_aggregations_results() {
429
		if ( empty( $this->search_result ) || is_wp_error( $this->search_result ) || ! isset( $this->search_result['aggregations'] ) ) {
430
			return array();
431
		}
432
433
		return $this->search_result['aggregations'];
434
	}
435
436
	/**
437
	 * Automatically configure necessary settings for instant search
438
	 *
439
	 * @since  8.3.0
440
	 */
441
	public function auto_config_search() {
442
		if ( ! current_user_can( 'edit_theme_options' ) ) {
443
			return;
444
		}
445
446
		// Set default result format to "expanded".
447
		update_option( Jetpack_Search_Options::OPTION_PREFIX . 'result_format', 'expanded' );
448
449
		$this->auto_config_excluded_post_types();
450
		$this->auto_config_overlay_sidebar_widgets();
451
	}
452
453
	/**
454
	 * Automatically copy configured search widgets into the overlay sidebar
455
	 *
456
	 * @since  8.8.0
457
	 */
458
	public function auto_config_overlay_sidebar_widgets() {
459
		global $wp_registered_sidebars;
460
		$sidebars = get_option( 'sidebars_widgets', array() );
461
		$slug     = Jetpack_Search_Helpers::FILTER_WIDGET_BASE;
462
463
		if ( isset( $sidebars['jetpack-instant-search-sidebar'] ) ) {
464
			foreach ( (array) $sidebars['jetpack-instant-search-sidebar'] as $widget_id ) {
465
				if ( 0 === strpos( $widget_id, $slug ) ) {
466
					// Already configured.
467
					return;
468
				}
469
			}
470
		}
471
472
		$has_sidebar           = isset( $wp_registered_sidebars['sidebar-1'] );
473
		$sidebar_id            = false;
474
		$sidebar_searchbox_idx = false;
475
		if ( $has_sidebar ) {
476
			if ( empty( $sidebars['sidebar-1'] ) ) {
477
				// Adding to an empty sidebar is generally a bad idea.
478
				$has_sidebar = false;
479
			}
480
			foreach ( (array) $sidebars['sidebar-1'] as $idx => $widget_id ) {
481
				if ( 0 === strpos( $widget_id, 'search-' ) ) {
482
					$sidebar_searchbox_idx = $idx;
483
				}
484
				if ( 0 === strpos( $widget_id, $slug ) ) {
485
					$sidebar_id = (int) str_replace( Jetpack_Search_Helpers::FILTER_WIDGET_BASE . '-', '', $widget_id );
486
					break;
487
				}
488
			}
489
		}
490
491
		$next_id         = 1;
492
		$widget_opt_name = Jetpack_Search_Helpers::get_widget_option_name();
493
		$widget_options  = get_option( $widget_opt_name, array() );
494
		foreach ( $widget_options as $id => $w ) {
495
			if ( $id >= $next_id ) {
496
				$next_id = $id + 1;
497
			}
498
		}
499
500
		// Copy sidebar settings to overlay.
501
		if ( ( false !== $sidebar_id ) && isset( $widget_options[ $sidebar_id ] ) ) {
502
			$widget_options[ $next_id ] = $widget_options[ $sidebar_id ];
503
			update_option( $widget_opt_name, $widget_options );
504
505
			if ( ! isset( $sidebars['jetpack-instant-search-sidebar'] ) ) {
506
				$sidebars['jetpack-instant-search-sidebar'] = array();
507
			}
508
			array_unshift( $sidebars['jetpack-instant-search-sidebar'], Jetpack_Search_Helpers::build_widget_id( $next_id ) );
509
			update_option( 'sidebars_widgets', $sidebars );
510
511
			return;
512
		}
513
514
		// Configure overlay and sidebar (if it exists).
515
		$preconfig_opts = $this->get_preconfig_widget_options();
516
		if ( ! isset( $sidebars['jetpack-instant-search-sidebar'] ) ) {
517
			$sidebars['jetpack-instant-search-sidebar'] = array();
518
		}
519
		if ( $has_sidebar ) {
520
			$widget_options[ $next_id ] = $preconfig_opts;
521
			if ( false !== $sidebar_searchbox_idx ) {
522
				// Replace Core search box.
523
				$sidebars['sidebar-1'][ $sidebar_searchbox_idx ] = Jetpack_Search_Helpers::build_widget_id( $next_id );
524
			} else {
525
				// Add to top.
526
				array_unshift( $sidebars['sidebar-1'], Jetpack_Search_Helpers::build_widget_id( $next_id ) );
527
			}
528
			$next_id++;
529
		}
530
		$widget_options[ $next_id ] = $preconfig_opts;
531
		array_unshift( $sidebars['jetpack-instant-search-sidebar'], Jetpack_Search_Helpers::build_widget_id( $next_id ) );
532
533
		update_option( $widget_opt_name, $widget_options );
534
		update_option( 'sidebars_widgets', $sidebars );
535
	}
536
537
	/**
538
	 * Autoconfig search by adding filter widgets
539
	 *
540
	 * @since  8.4.0
541
	 *
542
	 * @return array Array of config settings for search widget.
543
	 */
544
	protected function get_preconfig_widget_options() {
545
		$settings = array(
546
			'title'   => '',
547
			'filters' => array(),
548
		);
549
550
		$post_types = get_post_types(
551
			array(
552
				'public'   => true,
553
				'_builtin' => false,
554
			)
555
		);
556
557
		if ( ! empty( $post_types ) ) {
558
			$settings['filters'][] = array(
559
				array(
560
					'name'  => '',
561
					'type'  => 'post_type',
562
					'count' => 5,
563
				),
564
			);
565
		}
566
567
		// Grab a maximum of 3 taxonomies.
568
		$taxonomies = array_slice(
569
			get_taxonomies(
570
				array(
571
					'public'   => true,
572
					'_builtin' => false,
573
				)
574
			),
575
			0,
576
			3
577
		);
578
579
		foreach ( $taxonomies as $t ) {
580
			$settings['filters'][] = array(
581
				'name'     => '',
582
				'type'     => 'taxonomy',
583
				'taxonomy' => $t,
584
				'count'    => 5,
585
			);
586
		}
587
588
		$settings['filters'][] = array(
589
			'name'     => '',
590
			'type'     => 'taxonomy',
591
			'taxonomy' => 'category',
592
			'count'    => 5,
593
		);
594
595
		$settings['filters'][] = array(
596
			'name'     => '',
597
			'type'     => 'taxonomy',
598
			'taxonomy' => 'post_tag',
599
			'count'    => 5,
600
		);
601
602
		$settings['filters'][] = array(
603
			'name'     => '',
604
			'type'     => 'date_histogram',
605
			'count'    => 5,
606
			'field'    => 'post_date',
607
			'interval' => 'year',
608
		);
609
610
		return $settings;
611
	}
612
	/**
613
	 * Automatically configure post types to exclude from one of the search widgets
614
	 *
615
	 * @since  8.8.0
616
	 */
617
	public function auto_config_excluded_post_types() {
618
		$post_types         = get_post_types(
619
			array(
620
				'exclude_from_search' => false,
621
				'public'              => true,
622
			)
623
		);
624
		$enabled_post_types = array();
625
		$widget_options     = get_option( Jetpack_Search_Helpers::get_widget_option_name(), array() );
626
627
		// Prior to Jetpack 8.8, post types were enabled via Jetpack Search widgets rather than disabled via the Customizer.
628
		// To continue supporting post types set up in the old way, we iterate through each Jetpack Search
629
		// widget configuration and append each enabled post type to $enabled_post_types.
630
		foreach ( $widget_options as $widget_option ) {
631
			if ( isset( $widget_option['post_types'] ) && is_array( $widget_option['post_types'] ) ) {
632
				foreach ( $widget_option['post_types'] as $enabled_post_type ) {
633
					$enabled_post_types[ $enabled_post_type ] = $enabled_post_type;
634
				}
635
			}
636
		}
637
638
		if ( ! empty( $enabled_post_types ) ) {
639
			$post_types_to_disable = array_diff( $post_types, $enabled_post_types );
640
			update_option( Jetpack_Search_Options::OPTION_PREFIX . 'excluded_post_types', join( ',', $post_types_to_disable ) );
641
		}
642
	}
643
}
644