Completed
Push — add/group-id-search-field ( 378748...2f42b5 )
by
unknown
20:54 queued 09:35
created

Jetpack_Instant_Search   F

Complexity

Total Complexity 82

Size/Duplication

Total Lines 662
Duplicated Lines 6.65 %

Coupling/Cohesion

Components 2
Dependencies 6

Importance

Changes 0
Metric Value
dl 44
loc 662
rs 1.938
c 0
b 0
f 0
wmc 82
lcom 2
cbo 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 automattic/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
	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
69
		if (
70
			! file_exists( JETPACK__PLUGIN_DIR . $polyfill_relative_path ) ||
71
			! file_exists( JETPACK__PLUGIN_DIR . $script_relative_path )
72
		) {
73
			return;
74
		}
75
76
		$polyfill_version = Jetpack_Search_Helpers::get_asset_version( $polyfill_relative_path );
77
		$polyfill_path    = plugins_url( $polyfill_relative_path, $plugin_base_path );
78
		wp_enqueue_script( 'jetpack-instant-search-ie11', $polyfill_path, array(), $polyfill_version, true );
79
		$polyfill_payload_path = plugins_url(
80
			$path_prefix . '_inc/build/instant-search/jp-search-ie11-polyfill-payload.bundle.js',
81
			$plugin_base_path
82
		);
83
		$this->inject_polyfill_js_options( $polyfill_payload_path );
84
85
		$script_version = Jetpack_Search_Helpers::get_asset_version( $script_relative_path );
86
		$script_path    = plugins_url( $script_relative_path, $plugin_base_path );
87
		wp_enqueue_script( 'jetpack-instant-search', $script_path, array(), $script_version, true );
88
		wp_set_script_translations( 'jetpack-instant-search', 'jetpack' );
89
		$this->load_and_initialize_tracks();
90
		$this->inject_javascript_options();
91
	}
92
93
	/**
94
	 * Passes all options to the JS app.
95
	 */
96
	protected function inject_javascript_options() {
97
		$widget_options = Jetpack_Search_Helpers::get_widgets_from_option();
98
		if ( is_array( $widget_options ) ) {
99
			$widget_options = end( $widget_options );
100
		}
101
102
		$overlay_widget_ids      = is_active_sidebar( 'jetpack-instant-search-sidebar' ) ?
103
			wp_get_sidebars_widgets()['jetpack-instant-search-sidebar'] : array();
104
		$filters                 = Jetpack_Search_Helpers::get_filters_from_widgets();
105
		$widgets                 = array();
106
		$widgets_outside_overlay = array();
107
		foreach ( $filters as $key => &$filter ) {
108
			$filter['filter_id'] = $key;
109
110
			if ( in_array( $filter['widget_id'], $overlay_widget_ids, true ) ) {
111
				if ( ! isset( $widgets[ $filter['widget_id'] ] ) ) {
112
					$widgets[ $filter['widget_id'] ]['filters']   = array();
113
					$widgets[ $filter['widget_id'] ]['widget_id'] = $filter['widget_id'];
114
				}
115
				$widgets[ $filter['widget_id'] ]['filters'][] = $filter;
116
			} else {
117
				if ( ! isset( $widgets_outside_overlay[ $filter['widget_id'] ] ) ) {
118
					$widgets_outside_overlay[ $filter['widget_id'] ]['filters']   = array();
119
					$widgets_outside_overlay[ $filter['widget_id'] ]['widget_id'] = $filter['widget_id'];
120
				}
121
				$widgets_outside_overlay[ $filter['widget_id'] ]['filters'][] = $filter;
122
			}
123
		}
124
		unset( $filter );
125
126
		$has_non_search_widgets = false;
127
		foreach ( $overlay_widget_ids as $overlay_widget_id ) {
128
			if ( strpos( $overlay_widget_id, Jetpack_Search_Helpers::FILTER_WIDGET_BASE ) === false ) {
129
				$has_non_search_widgets = true;
130
				break;
131
			}
132
		}
133
134
		$post_type_objs   = get_post_types( array( 'exclude_from_search' => false ), 'objects' );
135
		$post_type_labels = array();
136
		foreach ( $post_type_objs as $key => $obj ) {
137
			$post_type_labels[ $key ] = array(
138
				'singular_name' => $obj->labels->singular_name,
139
				'name'          => $obj->labels->name,
140
			);
141
		}
142
143
		$prefix         = Jetpack_Search_Options::OPTION_PREFIX;
144
		$posts_per_page = (int) get_option( 'posts_per_page' );
145
		if ( ( $posts_per_page > 20 ) || ( $posts_per_page <= 0 ) ) {
146
			$posts_per_page = 20;
147
		}
148
149
		$excluded_post_types   = get_option( $prefix . 'excluded_post_types' ) ? explode( ',', get_option( $prefix . 'excluded_post_types', '' ) ) : array();
150
		$post_types            = array_values(
151
			get_post_types(
152
				array(
153
					'exclude_from_search' => false,
154
					'public'              => true,
155
				)
156
			)
157
		);
158
		$unexcluded_post_types = array_diff( $post_types, $excluded_post_types );
159
		// NOTE: If all post types are being excluded, ignore the option value.
160
		if ( count( $unexcluded_post_types ) === 0 ) {
161
			$excluded_post_types = array();
162
		}
163
164
		projects/plugins/jetpack/tests/php/sync/test_class.jetpack-sync-callables.php		$p2_workspace_hub_blog_id = get_option( $prefix . 'p2_workspace_hub_blog_id' );
0 ignored issues
show
Bug introduced by
This code did not parse for me. Apparently, there is an error somewhere around this line:

Syntax error, unexpected T_VARIABLE
Loading history...
165
		if ( $p2_workspace_hub_blog_id ) {
166
			$group_id = 'p2_workspace_hub_blog_id:' . $p2_workspace_hub_blog_id;
167
		}
168
169
		$is_wpcom                  = defined( 'IS_WPCOM' ) && IS_WPCOM;
170
		$is_private_site           = '-1' === get_option( 'blog_public' );
171
		$is_jetpack_photon_enabled = method_exists( 'Jetpack', 'is_module_active' ) && Jetpack::is_module_active( 'photon' );
172
173
		$options = array(
174
			'overlayOptions'        => array(
175
				'colorTheme'      => get_option( $prefix . 'color_theme', 'light' ),
176
				'enableInfScroll' => get_option( $prefix . 'inf_scroll', '1' ) === '1',
177
				'enableSort'      => get_option( $prefix . 'enable_sort', '1' ) === '1',
178
				'highlightColor'  => get_option( $prefix . 'highlight_color', '#FFC' ),
179
				'overlayTrigger'  => get_option( $prefix . 'overlay_trigger', 'immediate' ),
180
				'resultFormat'    => get_option( $prefix . 'result_format', Jetpack_Search_Options::RESULT_FORMAT_MINIMAL ),
181
				'showPoweredBy'   => get_option( $prefix . 'show_powered_by', '1' ) === '1',
182
			),
183
184
			// core config.
185
			'homeUrl'               => home_url(),
186
			'locale'                => str_replace( '_', '-', Jetpack_Search_Helpers::is_valid_locale( get_locale() ) ? get_locale() : 'en_US' ),
187
			'postsPerPage'          => $posts_per_page,
188
			'siteId'                => $this->jetpack_blog_id,
189
			'postTypes'             => $post_type_labels,
190
			'webpackPublicPath'     => plugins_url( '_inc/build/instant-search/', JETPACK__PLUGIN_FILE ),
191
			'isPhotonEnabled'       => ( $is_wpcom || $is_jetpack_photon_enabled ) && ! $is_private_site,
192
			'groupId'               => $group_id,
193
194
			// config values related to private site support.
195
			'apiRoot'               => esc_url_raw( rest_url() ),
196
			'apiNonce'              => wp_create_nonce( 'wp_rest' ),
197
			'isPrivateSite'         => $is_private_site,
198
			'isWpcom'               => $is_wpcom,
199
200
			// search options.
201
			'defaultSort'           => get_option( $prefix . 'default_sort', 'relevance' ),
202
			'excludedPostTypes'     => $excluded_post_types,
203
204
			// widget info.
205
			'hasOverlayWidgets'     => count( $overlay_widget_ids ) > 0,
206
			'widgets'               => array_values( $widgets ),
207
			'widgetsOutsideOverlay' => array_values( $widgets_outside_overlay ),
208
			'hasNonSearchWidgets'   => $has_non_search_widgets,
209
		);
210
211
		/**
212
		 * Customize Instant Search Options.
213
		 *
214
		 * @module search
215
		 *
216
		 * @since 7.7.0
217
		 *
218
		 * @param array $options Array of parameters used in Instant Search queries.
219
		 */
220
		$options = apply_filters( 'jetpack_instant_search_options', $options );
221
222
		// Use wp_add_inline_script instead of wp_localize_script, see https://core.trac.wordpress.org/ticket/25280.
223
		wp_add_inline_script( 'jetpack-instant-search', 'var JetpackInstantSearchOptions=JSON.parse(decodeURIComponent("' . rawurlencode( wp_json_encode( $options ) ) . '"));', 'before' );
224
	}
225
226
	/**
227
	 * Passes options to the polyfill loader script.
228
	 *
229
	 * @param string $polyfill_payload_path - Absolute path to the IE11 polyfill payload.
230
	 */
231
	protected function inject_polyfill_js_options( $polyfill_payload_path ) {
232
		wp_add_inline_script( 'jetpack-instant-search-ie11', 'var JetpackInstantSearchIe11PolyfillPath=decodeURIComponent("' . rawurlencode( $polyfill_payload_path ) . '");', 'before' );
233
	}
234
235
	/**
236
	 * Registers a widget sidebar for Instant Search.
237
	 */
238
	public function register_jetpack_instant_sidebar() {
239
		$args = array(
240
			'name'          => __( 'Jetpack Search Sidebar', 'jetpack' ),
241
			'id'            => 'jetpack-instant-search-sidebar',
242
			'description'   => __( 'Customize the sidebar inside the Jetpack Search overlay', 'jetpack' ),
243
			'class'         => '',
244
			'before_widget' => '<div id="%1$s" class="widget %2$s">',
245
			'after_widget'  => '</div>',
246
			'before_title'  => '<h2 class="widgettitle">',
247
			'after_title'   => '</h2>',
248
		);
249
		register_sidebar( $args );
250
	}
251
252
	/**
253
	 * Prints Instant Search sidebar.
254
	 */
255
	public function print_instant_search_sidebar() {
256
		?>
257
		<div class="jetpack-instant-search__widget-area" style="display: none">
258
			<?php if ( is_active_sidebar( 'jetpack-instant-search-sidebar' ) ) { ?>
259
				<?php dynamic_sidebar( 'jetpack-instant-search-sidebar' ); ?>
260
			<?php } ?>
261
		</div>
262
		<?php
263
	}
264
265
	/**
266
	 * Loads scripts for Tracks analytics library
267
	 */
268
	public function load_and_initialize_tracks() {
269
		wp_enqueue_script( 'jp-tracks', '//stats.wp.com/w.js', array(), gmdate( 'YW' ), true );
270
	}
271
272
	/**
273
	 * Bypass the normal Search query since we will run it with instant search.
274
	 *
275
	 * @since 8.3.0
276
	 *
277
	 * @param array    $posts Current array of posts (still pre-query).
278
	 * @param WP_Query $query The WP_Query being filtered.
279
	 *
280
	 * @return array Array of matching posts.
281
	 */
282
	public function filter__posts_pre_query( $posts, $query ) {
283
		if ( ! $this->should_handle_query( $query ) ) {
284
			// Intentionally not adding the 'jetpack_search_abort' action since this should fire for every request except for search.
285
			return $posts;
286
		}
287
288
		/**
289
		 * Bypass the main query and return dummy data
290
		 *  WP Core doesn't call the set_found_posts and its filters when filtering
291
		 *  posts_pre_query like we do, so need to do these manually.
292
		 */
293
		$query->found_posts   = 1;
294
		$query->max_num_pages = 1;
295
296
		return array();
297
	}
298
299
	/**
300
	 * Run the aggregations API query for any filtering
301
	 *
302
	 * @since 8.3.0
303
	 */
304
	public function action__parse_query() {
305
		if ( ! empty( $this->search_result ) ) {
306
			return;
307
		}
308
309
		if ( is_admin() ) {
310
			return;
311
		}
312
313
		if ( empty( $this->aggregations ) ) {
314
			return;
315
		}
316
317
		jetpack_require_lib( 'jetpack-wpes-query-builder/jetpack-wpes-query-builder' );
318
319
		$builder = new Jetpack_WPES_Query_Builder();
320
		$this->add_aggregations_to_es_query_builder( $this->aggregations, $builder );
321
		$this->search_result = $this->instant_api(
322
			array(
323
				'aggregations' => $builder->build_aggregation(),
324
				'size'         => 0,
325
				'from'         => 0,
326
			)
327
		);
328
	}
329
330
	/**
331
	 * Run an instant search on the WordPress.com public API.
332
	 *
333
	 * @since 8.3.0
334
	 *
335
	 * @param array $args Args conforming to the WP.com v1.3/sites/<blog_id>/search endpoint.
336
	 *
337
	 * @return object|WP_Error The response from the public API, or a WP_Error.
338
	 */
339
	public function instant_api( array $args ) {
340
		global $wp_version;
341
		$start_time = microtime( true );
342
343
		// Cache locally to avoid remote request slowing the page.
344
		$transient_name = 'jetpack_instant_search_cache_' . md5( wp_json_encode( $args ) );
345
		$cache          = get_transient( $transient_name );
346
		if ( false !== $cache ) {
347
			return $cache;
348
		}
349
350
		$service_url = add_query_arg(
351
			$args,
352
			sprintf(
353
				'https://public-api.wordpress.com/rest/v1.3/sites/%d/search',
354
				$this->jetpack_blog_id
355
			)
356
		);
357
358
		$request_args = array(
359
			'timeout'    => 10,
360
			'user-agent' => "WordPress/{$wp_version} | Jetpack/" . constant( 'JETPACK__VERSION' ),
361
		);
362
363
		$request  = wp_remote_get( esc_url_raw( $service_url ), $request_args );
364
		$end_time = microtime( true );
365
366
		if ( is_wp_error( $request ) ) {
367
			return $request;
368
		}
369
370
		$response_code = wp_remote_retrieve_response_code( $request );
371
		$response      = json_decode( wp_remote_retrieve_body( $request ), true );
372
373
		if ( ! $response_code || $response_code < 200 || $response_code >= 300 ) {
374
			/**
375
			 * Fires after a search query request has failed
376
			 *
377
			 * @module search
378
			 *
379
			 * @since  5.6.0
380
			 *
381
			 * @param array Array containing the response code and response from the failed search query
382
			 */
383
			do_action(
384
				'failed_jetpack_search_query',
385
				array(
386
					'response_code' => $response_code,
387
					'json'          => $response,
388
				)
389
			);
390
391
			return new WP_Error( 'invalid_search_api_response', 'Invalid response from API - ' . $response_code );
392
		}
393
394
		$took = is_array( $response ) && ! empty( $response['took'] )
395
			? $response['took']
396
			: null;
397
398
		$query = array(
399
			'args'          => $args,
400
			'response'      => $response,
401
			'response_code' => $response_code,
402
			'elapsed_time'  => ( $end_time - $start_time ) * 1000, // Convert from float seconds to ms.
403
			'es_time'       => $took,
404
			'url'           => $service_url,
405
		);
406
407
		/**
408
		 * Fires after a search request has been performed.
409
		 *
410
		 * Includes the following info in the $query parameter:
411
		 *
412
		 * array args Array of Elasticsearch arguments for the search
413
		 * array response Raw API response, JSON decoded
414
		 * int response_code HTTP response code of the request
415
		 * float elapsed_time Roundtrip time of the search request, in milliseconds
416
		 * float es_time Amount of time Elasticsearch spent running the request, in milliseconds
417
		 * string url API url that was queried
418
		 *
419
		 * @module search
420
		 *
421
		 * @since  5.0.0
422
		 * @since  5.8.0 This action now fires on all queries instead of just successful queries.
423
		 *
424
		 * @param array $query Array of information about the query performed
425
		 */
426
		do_action( 'did_jetpack_search_query', $query );
427
428
		// Update local cache.
429
		set_transient( $transient_name, $response, 1 * HOUR_IN_SECONDS );
430
431
		return $response;
432
	}
433
434
	/**
435
	 * Get the raw Aggregation results from the Elasticsearch response.
436
	 *
437
	 * @since  8.4.0
438
	 *
439
	 * @return array Array of Aggregations performed on the search.
440
	 */
441
	public function get_search_aggregations_results() {
442
		if ( empty( $this->search_result ) || is_wp_error( $this->search_result ) || ! isset( $this->search_result['aggregations'] ) ) {
443
			return array();
444
		}
445
446
		return $this->search_result['aggregations'];
447
	}
448
449
	/**
450
	 * Automatically configure necessary settings for instant search
451
	 *
452
	 * @since  8.3.0
453
	 */
454
	public function auto_config_search() {
455
		if ( ! current_user_can( 'edit_theme_options' ) ) {
456
			return;
457
		}
458
459
		// Set default result format to "expanded".
460
		update_option( Jetpack_Search_Options::OPTION_PREFIX . 'result_format', Jetpack_Search_Options::RESULT_FORMAT_EXPANDED );
461
462
		$this->auto_config_excluded_post_types();
463
		$this->auto_config_overlay_sidebar_widgets();
464
		$this->auto_config_woo_result_format();
465
	}
466
467
	/**
468
	 * Automatically copy configured search widgets into the overlay sidebar
469
	 *
470
	 * @since  8.8.0
471
	 */
472
	public function auto_config_overlay_sidebar_widgets() {
473
		global $wp_registered_sidebars;
474
		$sidebars = get_option( 'sidebars_widgets', array() );
475
		$slug     = Jetpack_Search_Helpers::FILTER_WIDGET_BASE;
476
477
		if ( isset( $sidebars['jetpack-instant-search-sidebar'] ) ) {
478
			foreach ( (array) $sidebars['jetpack-instant-search-sidebar'] as $widget_id ) {
479
				if ( 0 === strpos( $widget_id, $slug ) ) {
480
					// Already configured.
481
					return;
482
				}
483
			}
484
		}
485
486
		$has_sidebar           = isset( $wp_registered_sidebars['sidebar-1'] );
487
		$sidebar_id            = false;
488
		$sidebar_searchbox_idx = false;
489
		if ( $has_sidebar ) {
490
			if ( empty( $sidebars['sidebar-1'] ) ) {
491
				// Adding to an empty sidebar is generally a bad idea.
492
				$has_sidebar = false;
493
			}
494
			foreach ( (array) $sidebars['sidebar-1'] as $idx => $widget_id ) {
495
				if ( 0 === strpos( $widget_id, 'search-' ) ) {
496
					$sidebar_searchbox_idx = $idx;
497
				}
498
				if ( 0 === strpos( $widget_id, $slug ) ) {
499
					$sidebar_id = (int) str_replace( Jetpack_Search_Helpers::FILTER_WIDGET_BASE . '-', '', $widget_id );
500
					break;
501
				}
502
			}
503
		}
504
505
		$next_id         = 1;
506
		$widget_opt_name = Jetpack_Search_Helpers::get_widget_option_name();
507
		$widget_options  = get_option( $widget_opt_name, array() );
508
		foreach ( $widget_options as $id => $w ) {
509
			if ( $id >= $next_id ) {
510
				$next_id = $id + 1;
511
			}
512
		}
513
514
		// Copy sidebar settings to overlay.
515
		if ( ( false !== $sidebar_id ) && isset( $widget_options[ $sidebar_id ] ) ) {
516
			$widget_options[ $next_id ] = $widget_options[ $sidebar_id ];
517
			update_option( $widget_opt_name, $widget_options );
518
519
			if ( ! isset( $sidebars['jetpack-instant-search-sidebar'] ) ) {
520
				$sidebars['jetpack-instant-search-sidebar'] = array();
521
			}
522
			array_unshift( $sidebars['jetpack-instant-search-sidebar'], Jetpack_Search_Helpers::build_widget_id( $next_id ) );
523
			update_option( 'sidebars_widgets', $sidebars );
524
525
			return;
526
		}
527
528
		// Configure overlay and sidebar (if it exists).
529
		$preconfig_opts = $this->get_preconfig_widget_options();
530
		if ( ! isset( $sidebars['jetpack-instant-search-sidebar'] ) ) {
531
			$sidebars['jetpack-instant-search-sidebar'] = array();
532
		}
533
		if ( $has_sidebar ) {
534
			$widget_options[ $next_id ] = $preconfig_opts;
535
			if ( false !== $sidebar_searchbox_idx ) {
536
				// Replace Core search box.
537
				$sidebars['sidebar-1'][ $sidebar_searchbox_idx ] = Jetpack_Search_Helpers::build_widget_id( $next_id );
538
			} else {
539
				// Add to top.
540
				array_unshift( $sidebars['sidebar-1'], Jetpack_Search_Helpers::build_widget_id( $next_id ) );
541
			}
542
			$next_id++;
543
		}
544
		$widget_options[ $next_id ] = $preconfig_opts;
545
		array_unshift( $sidebars['jetpack-instant-search-sidebar'], Jetpack_Search_Helpers::build_widget_id( $next_id ) );
546
547
		update_option( $widget_opt_name, $widget_options );
548
		update_option( 'sidebars_widgets', $sidebars );
549
	}
550
551
	/**
552
	 * Autoconfig search by adding filter widgets
553
	 *
554
	 * @since  8.4.0
555
	 *
556
	 * @return array Array of config settings for search widget.
557
	 */
558
	protected function get_preconfig_widget_options() {
559
		$settings = array(
560
			'title'   => '',
561
			'filters' => array(),
562
		);
563
564
		$post_types = get_post_types(
565
			array(
566
				'public'   => true,
567
				'_builtin' => false,
568
			)
569
		);
570
571
		if ( ! empty( $post_types ) ) {
572
			$settings['filters'][] = array(
573
				'name'  => '',
574
				'type'  => 'post_type',
575
				'count' => 5,
576
			);
577
		}
578
579
		// Grab a maximum of 3 taxonomies.
580
		$taxonomies = array_slice(
581
			get_taxonomies(
582
				array(
583
					'public'   => true,
584
					'_builtin' => false,
585
				)
586
			),
587
			0,
588
			3
589
		);
590
591
		foreach ( $taxonomies as $t ) {
592
			$settings['filters'][] = array(
593
				'name'     => '',
594
				'type'     => 'taxonomy',
595
				'taxonomy' => $t,
596
				'count'    => 5,
597
			);
598
		}
599
600
		$settings['filters'][] = array(
601
			'name'     => '',
602
			'type'     => 'taxonomy',
603
			'taxonomy' => 'category',
604
			'count'    => 5,
605
		);
606
607
		$settings['filters'][] = array(
608
			'name'     => '',
609
			'type'     => 'taxonomy',
610
			'taxonomy' => 'post_tag',
611
			'count'    => 5,
612
		);
613
614
		$settings['filters'][] = array(
615
			'name'     => '',
616
			'type'     => 'date_histogram',
617
			'count'    => 5,
618
			'field'    => 'post_date',
619
			'interval' => 'year',
620
		);
621
622
		return $settings;
623
	}
624
625
	/**
626
	 * Automatically configure post types to exclude from one of the search widgets
627
	 *
628
	 * @since  8.8.0
629
	 */
630
	public function auto_config_excluded_post_types() {
631
		$post_types         = get_post_types(
632
			array(
633
				'exclude_from_search' => false,
634
				'public'              => true,
635
			)
636
		);
637
		$enabled_post_types = array();
638
		$widget_options     = get_option( Jetpack_Search_Helpers::get_widget_option_name(), array() );
639
640
		// Prior to Jetpack 8.8, post types were enabled via Jetpack Search widgets rather than disabled via the Customizer.
641
		// To continue supporting post types set up in the old way, we iterate through each Jetpack Search
642
		// widget configuration and append each enabled post type to $enabled_post_types.
643
		foreach ( $widget_options as $widget_option ) {
644
			if ( isset( $widget_option['post_types'] ) && is_array( $widget_option['post_types'] ) ) {
645
				foreach ( $widget_option['post_types'] as $enabled_post_type ) {
646
					$enabled_post_types[ $enabled_post_type ] = $enabled_post_type;
647
				}
648
			}
649
		}
650
651
		if ( ! empty( $enabled_post_types ) ) {
652
			$post_types_to_disable = array_diff( $post_types, $enabled_post_types );
653
			update_option( Jetpack_Search_Options::OPTION_PREFIX . 'excluded_post_types', join( ',', $post_types_to_disable ) );
654
		}
655
	}
656
657
	/**
658
	 * Automatically set result format to 'product' if WooCommerce is installed
659
	 *
660
	 * @since  9.6.0
661
	 */
662
	public function auto_config_woo_result_format() {
663
		if ( ! method_exists( 'Jetpack', 'get_active_plugins' ) ) {
664
			return false;
665
		}
666
667
		// Check if WooCommerce plugin is active (based on https://docs.woocommerce.com/document/create-a-plugin/).
668
		if ( ! in_array( 'woocommerce/woocommerce.php', apply_filters( 'active_plugins', Jetpack::get_active_plugins() ), true ) ) {
669
			return false;
670
		}
671
672
		update_option( Jetpack_Search_Options::OPTION_PREFIX . 'result_format', Jetpack_Search_Options::RESULT_FORMAT_PRODUCT );
673
	}
674
}
675