Completed
Push — update/instant-search-with-wpc... ( 39f50a )
by
unknown
64:28 queued 55:32
created

inject_polyfill_js_options()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 3

Duplication

Lines 0
Ratio 0 %

Importance

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