PluginProbe
Jetpack – WP Security, Backup, Speed, & Growth / 7.5.1
Jetpack – WP Security, Backup, Speed, & Growth v7.5.1
12.0.3 12.1.3 12.2.3 12.3.2 12.4.2 12.5.2 12.6.4 12.7.3 12.8.3 12.9.5 13.0.2 13.1.5 13.2.4 13.3.3 13.4.5 13.5.2 13.6.2 13.7.2 13.8.3 13.9.2 14.0.1 14.1.1 14.2.2 14.3.1 14.4.2 All 500 releases
jetpack / modules / widgets / search.php
search.php
816 lines 26.7 KB
No matching file
Up and down to move Enter to open Esc to close
Raw Download Zip
1 <?php
2 /**
3 * Jetpack Search: Jetpack_Search_Widget class
4 *
5 * @package Jetpack
6 * @subpackage Jetpack Search
7 * @since 5.0.0
8 */
9
10 add_action( 'widgets_init', 'jetpack_search_widget_init' );
11
12 function jetpack_search_widget_init() {
13 if ( ! Jetpack::is_active() || ! Jetpack_Plan::supports( 'search' ) ) {
14 return;
15 }
16
17 require_once JETPACK__PLUGIN_DIR . 'modules/search/class.jetpack-search-helpers.php';
18
19 register_widget( 'Jetpack_Search_Widget' );
20 }
21
22 /**
23 * Provides a widget to show available/selected filters on searches.
24 *
25 * @since 5.0.0
26 *
27 * @see WP_Widget
28 */
29 class Jetpack_Search_Widget extends WP_Widget {
30
31 /**
32 * The Jetpack_Search instance.
33 *
34 * @since 5.7.0
35 * @var Jetpack_Search
36 */
37 protected $jetpack_search;
38
39 /**
40 * Number of aggregations (filters) to show by default.
41 *
42 * @since 5.8.0
43 * @var int
44 */
45 const DEFAULT_FILTER_COUNT = 5;
46
47 /**
48 * Default sort order for search results.
49 *
50 * @since 5.8.0
51 * @var string
52 */
53 const DEFAULT_SORT = 'relevance_desc';
54
55 /**
56 * Jetpack_Search_Widget constructor.
57 *
58 * @since 5.0.0
59 */
60 public function __construct( $name = null ) {
61 if ( empty( $name ) ) {
62 $name = esc_html__( 'Search', 'jetpack' );
63 }
64 parent::__construct(
65 Jetpack_Search_Helpers::FILTER_WIDGET_BASE,
66 /** This filter is documented in modules/widgets/facebook-likebox.php */
67 apply_filters( 'jetpack_widget_name', $name ),
68 array(
69 'classname' => 'jetpack-filters widget_search',
70 'description' => __( 'Replaces the default search with an Elasticsearch-powered search interface and filters.', 'jetpack' ),
71 )
72 );
73
74 if (
75 Jetpack_Search_Helpers::is_active_widget( $this->id ) &&
76 ! $this->is_search_active()
77 ) {
78 $this->activate_search();
79 }
80
81 if ( is_admin() ) {
82 add_action( 'sidebar_admin_setup', array( $this, 'widget_admin_setup' ) );
83 } else {
84 add_action( 'wp_enqueue_scripts', array( $this, 'enqueue_frontend_scripts' ) );
85 }
86
87 add_action( 'jetpack_search_render_filters_widget_title', array( 'Jetpack_Search_Template_Tags', 'render_widget_title' ), 10, 3 );
88 add_action( 'jetpack_search_render_filters', array( 'Jetpack_Search_Template_Tags', 'render_available_filters' ), 10, 2 );
89 }
90
91 /**
92 * Check whether search is currently active
93 *
94 * @since 6.3
95 */
96 public function is_search_active() {
97 return Jetpack::is_module_active( 'search' );
98 }
99
100 /**
101 * Activate search
102 *
103 * @since 6.3
104 */
105 public function activate_search() {
106 Jetpack::activate_module( 'search', false, false );
107 }
108
109
110 /**
111 * Enqueues the scripts and styles needed for the customizer.
112 *
113 * @since 5.7.0
114 */
115 public function widget_admin_setup() {
116 wp_enqueue_style( 'widget-jetpack-search-filters', plugins_url( 'search/css/search-widget-admin-ui.css', __FILE__ ) );
117
118 // Required for Tracks
119 wp_register_script(
120 'jp-tracks',
121 '//stats.wp.com/w.js',
122 array(),
123 gmdate( 'YW' ),
124 true
125 );
126
127 wp_register_script(
128 'jp-tracks-functions',
129 plugins_url( '_inc/lib/tracks/tracks-callables.js', JETPACK__PLUGIN_FILE ),
130 array(),
131 JETPACK__VERSION,
132 false
133 );
134
135 wp_register_script(
136 'jetpack-search-widget-admin',
137 plugins_url( 'search/js/search-widget-admin.js', __FILE__ ),
138 array( 'jquery', 'jquery-ui-sortable', 'jp-tracks', 'jp-tracks-functions' ),
139 JETPACK__VERSION
140 );
141
142 wp_localize_script(
143 'jetpack-search-widget-admin', 'jetpack_search_filter_admin', array(
144 'defaultFilterCount' => self::DEFAULT_FILTER_COUNT,
145 'tracksUserData' => Jetpack_Tracks_Client::get_connected_user_tracks_identity(),
146 'tracksEventData' => array(
147 'is_customizer' => (int) is_customize_preview(),
148 ),
149 'i18n' => array(
150 'month' => Jetpack_Search_Helpers::get_date_filter_type_name( 'month', false ),
151 'year' => Jetpack_Search_Helpers::get_date_filter_type_name( 'year', false ),
152 'monthUpdated' => Jetpack_Search_Helpers::get_date_filter_type_name( 'month', true ),
153 'yearUpdated' => Jetpack_Search_Helpers::get_date_filter_type_name( 'year', true ),
154 ),
155 )
156 );
157
158 wp_enqueue_script( 'jetpack-search-widget-admin' );
159 }
160
161 /**
162 * Enqueue scripts and styles for the frontend.
163 *
164 * @since 5.8.0
165 */
166 public function enqueue_frontend_scripts() {
167 if ( ! is_active_widget( false, false, $this->id_base, true ) ) {
168 return;
169 }
170
171 wp_enqueue_script(
172 'jetpack-search-widget',
173 plugins_url( 'search/js/search-widget.js', __FILE__ ),
174 array( 'jquery' ),
175 JETPACK__VERSION,
176 true
177 );
178
179 wp_enqueue_style( 'jetpack-search-widget', plugins_url( 'search/css/search-widget-frontend.css', __FILE__ ) );
180 }
181
182 /**
183 * Get the list of valid sort types/orders.
184 *
185 * @since 5.8.0
186 *
187 * @return array The sort orders.
188 */
189 private function get_sort_types() {
190 return array(
191 'relevance|DESC' => is_admin() ? esc_html__( 'Relevance (recommended)', 'jetpack' ) : esc_html__( 'Relevance', 'jetpack' ),
192 'date|DESC' => esc_html__( 'Newest first', 'jetpack' ),
193 'date|ASC' => esc_html__( 'Oldest first', 'jetpack' ),
194 );
195 }
196
197 /**
198 * Callback for an array_filter() call in order to only get filters for the current widget.
199 *
200 * @see Jetpack_Search_Widget::widget()
201 *
202 * @since 5.7.0
203 *
204 * @param array $item Filter item.
205 *
206 * @return bool Whether the current filter item is for the current widget.
207 */
208 function is_for_current_widget( $item ) {
209 return isset( $item['widget_id'] ) && $this->id == $item['widget_id'];
210 }
211
212 /**
213 * This method returns a boolean for whether the widget should show site-wide filters for the site.
214 *
215 * This is meant to provide backwards-compatibility for VIP, and other professional plan users, that manually
216 * configured filters via `Jetpack_Search::set_filters()`.
217 *
218 * @since 5.7.0
219 *
220 * @return bool Whether the widget should display site-wide filters or not.
221 */
222 public function should_display_sitewide_filters() {
223 $filter_widgets = get_option( 'widget_jetpack-search-filters' );
224
225 // This shouldn't be empty, but just for sanity
226 if ( empty( $filter_widgets ) ) {
227 return false;
228 }
229
230 // If any widget has any filters, return false
231 foreach ( $filter_widgets as $number => $widget ) {
232 $widget_id = sprintf( '%s-%d', $this->id_base, $number );
233 if ( ! empty( $widget['filters'] ) && is_active_widget( false, $widget_id, $this->id_base ) ) {
234 return false;
235 }
236 }
237
238 return true;
239 }
240
241 public function jetpack_search_populate_defaults( $instance ) {
242 $instance = wp_parse_args(
243 (array) $instance, array(
244 'title' => '',
245 'search_box_enabled' => true,
246 'user_sort_enabled' => true,
247 'sort' => self::DEFAULT_SORT,
248 'filters' => array( array() ),
249 'post_types' => array(),
250 )
251 );
252
253 return $instance;
254 }
255
256 /**
257 * Responsible for rendering the widget on the frontend.
258 *
259 * @since 5.0.0
260 *
261 * @param array $args Widgets args supplied by the theme.
262 * @param array $instance The current widget instance.
263 */
264 public function widget( $args, $instance ) {
265 $instance = $this->jetpack_search_populate_defaults( $instance );
266
267 $display_filters = false;
268
269 if ( Jetpack::is_development_mode() ) {
270 echo $args['before_widget'];
271 ?><div id="<?php echo esc_attr( $this->id ); ?>-wrapper">
272 <div class="jetpack-search-sort-wrapper">
273 <label>
274 <?php esc_html_e( 'Jetpack Search not supported in Development Mode', 'jetpack' ); ?>
275 </label>
276 </div>
277 </div><?php
278 echo $args['after_widget'];
279 return;
280 }
281
282 if ( is_search() ) {
283 if ( Jetpack_Search_Helpers::should_rerun_search_in_customizer_preview() ) {
284 Jetpack_Search::instance()->update_search_results_aggregations();
285 }
286
287 $filters = Jetpack_Search::instance()->get_filters();
288
289 if ( ! Jetpack_Search_Helpers::are_filters_by_widget_disabled() && ! $this->should_display_sitewide_filters() ) {
290 $filters = array_filter( $filters, array( $this, 'is_for_current_widget' ) );
291 }
292
293 if ( ! empty( $filters ) ) {
294 $display_filters = true;
295 }
296 }
297
298 if ( ! $display_filters && empty( $instance['search_box_enabled'] ) && empty( $instance['user_sort_enabled'] ) ) {
299 return;
300 }
301
302 $title = isset( $instance['title'] ) ? $instance['title'] : '';
303
304 if ( empty( $title ) ) {
305 $title = '';
306 }
307
308 /** This filter is documented in core/src/wp-includes/default-widgets.php */
309 $title = apply_filters( 'widget_title', $title, $instance, $this->id_base );
310
311 echo $args['before_widget'];
312 ?><div id="<?php echo esc_attr( $this->id ); ?>-wrapper">
313 <?php
314
315 if ( ! empty( $title ) ) {
316 /**
317 * Responsible for displaying the title of the Jetpack Search filters widget.
318 *
319 * @module search
320 *
321 * @since 5.7.0
322 *
323 * @param string $title The widget's title
324 * @param string $args['before_title'] The HTML tag to display before the title
325 * @param string $args['after_title'] The HTML tag to display after the title
326 */
327 do_action( 'jetpack_search_render_filters_widget_title', $title, $args['before_title'], $args['after_title'] );
328 }
329
330 $default_sort = isset( $instance['sort'] ) ? $instance['sort'] : self::DEFAULT_SORT;
331 list( $orderby, $order ) = $this->sorting_to_wp_query_param( $default_sort );
332 $current_sort = "{$orderby}|{$order}";
333
334 // we need to dynamically inject the sort field into the search box when the search box is enabled, and display
335 // it separately when it's not.
336 if ( ! empty( $instance['search_box_enabled'] ) ) {
337 Jetpack_Search_Template_Tags::render_widget_search_form( $instance['post_types'], $orderby, $order );
338 }
339
340 if ( ! empty( $instance['search_box_enabled'] ) && ! empty( $instance['user_sort_enabled'] ) ) :
341 ?>
342 <div class="jetpack-search-sort-wrapper">
343 <label>
344 <?php esc_html_e( 'Sort by', 'jetpack' ); ?>
345 <select class="jetpack-search-sort">
346 <?php foreach ( $this->get_sort_types() as $sort => $label ) { ?>
347 <option value="<?php echo esc_attr( $sort ); ?>" <?php selected( $current_sort, $sort ); ?>>
348 <?php echo esc_html( $label ); ?>
349 </option>
350 <?php } ?>
351 </select>
352 </label>
353 </div>
354 <?php
355 endif;
356
357 if ( $display_filters ) {
358 /**
359 * Responsible for rendering filters to narrow down search results.
360 *
361 * @module search
362 *
363 * @since 5.8.0
364 *
365 * @param array $filters The possible filters for the current query.
366 * @param array $post_types An array of post types to limit filtering to.
367 */
368 do_action(
369 'jetpack_search_render_filters',
370 $filters,
371 isset( $instance['post_types'] ) ? $instance['post_types'] : null
372 );
373 }
374
375 $this->maybe_render_sort_javascript( $instance, $order, $orderby );
376
377 echo '</div>';
378 echo $args['after_widget'];
379 }
380
381 /**
382 * Renders JavaScript for the sorting controls on the frontend.
383 *
384 * This JS is a bit complicated, but here's what it's trying to do:
385 * - find the search form
386 * - find the orderby/order fields and set default values
387 * - detect changes to the sort field, if it exists, and use it to set the order field values
388 *
389 * @since 5.8.0
390 *
391 * @param array $instance The current widget instance.
392 * @param string $order The order to initialize the select with.
393 * @param string $orderby The orderby to initialize the select with.
394 */
395 private function maybe_render_sort_javascript( $instance, $order, $orderby ) {
396 if ( ! empty( $instance['user_sort_enabled'] ) ) :
397 ?>
398 <script type="text/javascript">
399 jQuery( document ).ready( function( $ ) {
400 var orderByDefault = '<?php echo 'date' === $orderby ? 'date' : 'relevance'; ?>',
401 orderDefault = '<?php echo 'ASC' === $order ? 'ASC' : 'DESC'; ?>',
402 widgetId = decodeURIComponent( '<?php echo rawurlencode( $this->id ); ?>' ),
403 searchQuery = decodeURIComponent( '<?php echo rawurlencode( get_query_var( 's', '' ) ); ?>' ),
404 isSearch = <?php echo (int) is_search(); ?>;
405
406 var container = $( '#' + widgetId + '-wrapper' ),
407 form = container.find('.jetpack-search-form form'),
408 orderBy = form.find( 'input[name=orderby]'),
409 order = form.find( 'input[name=order]'),
410 searchInput = form.find( 'input[name="s"]' );
411
412 orderBy.val( orderByDefault );
413 order.val( orderDefault );
414
415 // Some themes don't set the search query, which results in the query being lost
416 // when doing a sort selection. So, if the query isn't set, let's set it now. This approach
417 // is chosen over running a regex over HTML for every search query performed.
418 if ( isSearch && ! searchInput.val() ) {
419 searchInput.val( searchQuery );
420 }
421
422 searchInput.addClass( 'show-placeholder' );
423
424 container.find( '.jetpack-search-sort' ).change( function( event ) {
425 var values = event.target.value.split( '|' );
426 orderBy.val( values[0] );
427 order.val( values[1] );
428
429 form.submit();
430 });
431 } );
432 </script>
433 <?php
434 endif;
435 }
436
437 /**
438 * Convert a sort string into the separate order by and order parts.
439 *
440 * @since 5.8.0
441 *
442 * @param string $sort A sort string.
443 *
444 * @return array Order by and order.
445 */
446 private function sorting_to_wp_query_param( $sort ) {
447 $parts = explode( '|', $sort );
448 $orderby = isset( $_GET['orderby'] )
449 ? $_GET['orderby']
450 : $parts[0];
451
452 $order = isset( $_GET['order'] )
453 ? strtoupper( $_GET['order'] )
454 : ( ( isset( $parts[1] ) && 'ASC' === strtoupper( $parts[1] ) ) ? 'ASC' : 'DESC' );
455
456 return array( $orderby, $order );
457 }
458
459 /**
460 * Updates a particular instance of the widget. Validates and sanitizes the options.
461 *
462 * @since 5.0.0
463 *
464 * @param array $new_instance New settings for this instance as input by the user via Jetpack_Search_Widget::form().
465 * @param array $old_instance Old settings for this instance.
466 *
467 * @return array Settings to save.
468 */
469 public function update( $new_instance, $old_instance ) {
470 $instance = array();
471
472 $instance['title'] = sanitize_text_field( $new_instance['title'] );
473 $instance['search_box_enabled'] = empty( $new_instance['search_box_enabled'] ) ? '0' : '1';
474 $instance['user_sort_enabled'] = empty( $new_instance['user_sort_enabled'] ) ? '0' : '1';
475 $instance['sort'] = $new_instance['sort'];
476 $instance['post_types'] = empty( $new_instance['post_types'] ) || empty( $instance['search_box_enabled'] )
477 ? array()
478 : array_map( 'sanitize_key', $new_instance['post_types'] );
479
480 $filters = array();
481 if ( isset( $new_instance['filter_type'] ) ) {
482 foreach ( (array) $new_instance['filter_type'] as $index => $type ) {
483 $count = intval( $new_instance['num_filters'][ $index ] );
484 $count = min( 50, $count ); // Set max boundary at 50.
485 $count = max( 1, $count ); // Set min boundary at 1.
486
487 switch ( $type ) {
488 case 'taxonomy':
489 $filters[] = array(
490 'name' => sanitize_text_field( $new_instance['filter_name'][ $index ] ),
491 'type' => 'taxonomy',
492 'taxonomy' => sanitize_key( $new_instance['taxonomy_type'][ $index ] ),
493 'count' => $count,
494 );
495 break;
496 case 'post_type':
497 $filters[] = array(
498 'name' => sanitize_text_field( $new_instance['filter_name'][ $index ] ),
499 'type' => 'post_type',
500 'count' => $count,
501 );
502 break;
503 case 'date_histogram':
504 $filters[] = array(
505 'name' => sanitize_text_field( $new_instance['filter_name'][ $index ] ),
506 'type' => 'date_histogram',
507 'count' => $count,
508 'field' => sanitize_key( $new_instance['date_histogram_field'][ $index ] ),
509 'interval' => sanitize_key( $new_instance['date_histogram_interval'][ $index ] ),
510 );
511 break;
512 }
513 }
514 }
515
516 if ( ! empty( $filters ) ) {
517 $instance['filters'] = $filters;
518 }
519
520 return $instance;
521 }
522
523 /**
524 * Outputs the settings update form.
525 *
526 * @since 5.0.0
527 *
528 * @param array $instance Current settings.
529 */
530 public function form( $instance ) {
531 $instance = $this->jetpack_search_populate_defaults( $instance );
532
533 $title = strip_tags( $instance['title'] );
534
535 $hide_filters = Jetpack_Search_Helpers::are_filters_by_widget_disabled();
536
537 $classes = sprintf(
538 'jetpack-search-filters-widget %s %s %s',
539 $hide_filters ? 'hide-filters' : '',
540 $instance['search_box_enabled'] ? '' : 'hide-post-types',
541 $this->id
542 );
543 ?>
544 <div class="<?php echo esc_attr( $classes ); ?>">
545 <p>
546 <label for="<?php echo esc_attr( $this->get_field_id( 'title' ) ); ?>">
547 <?php esc_html_e( 'Title (optional):', 'jetpack' ); ?>
548 </label>
549 <input
550 class="widefat"
551 id="<?php echo esc_attr( $this->get_field_id( 'title' ) ); ?>"
552 name="<?php echo esc_attr( $this->get_field_name( 'title' ) ); ?>"
553 type="text"
554 value="<?php echo esc_attr( $title ); ?>"
555 />
556 </p>
557
558 <p>
559 <label>
560 <input
561 type="checkbox"
562 class="jetpack-search-filters-widget__search-box-enabled"
563 name="<?php echo esc_attr( $this->get_field_name( 'search_box_enabled' ) ); ?>"
564 <?php checked( $instance['search_box_enabled'] ); ?>
565 />
566 <?php esc_html_e( 'Show search box', 'jetpack' ); ?>
567 </label>
568 </p>
569 <p>
570 <label>
571 <input
572 type="checkbox"
573 class="jetpack-search-filters-widget__sort-controls-enabled"
574 name="<?php echo esc_attr( $this->get_field_name( 'user_sort_enabled' ) ); ?>"
575 <?php checked( $instance['user_sort_enabled'] ); ?>
576 <?php disabled( ! $instance['search_box_enabled'] ); ?>
577 />
578 <?php esc_html_e( 'Show sort selection dropdown', 'jetpack' ); ?>
579 </label>
580 </p>
581
582 <p class="jetpack-search-filters-widget__post-types-select">
583 <label><?php esc_html_e( 'Post types to search (minimum of 1):', 'jetpack' ); ?></label>
584 <?php foreach ( get_post_types( array( 'exclude_from_search' => false ), 'objects' ) as $post_type ) : ?>
585 <label>
586 <input
587 type="checkbox"
588 value="<?php echo esc_attr( $post_type->name ); ?>"
589 name="<?php echo esc_attr( $this->get_field_name( 'post_types' ) ); ?>[]"
590 <?php checked( empty( $instance['post_types'] ) || in_array( $post_type->name, $instance['post_types'] ) ); ?>
591 />&nbsp;
592 <?php echo esc_html( $post_type->label ); ?>
593 </label>
594 <?php endforeach; ?>
595 </p>
596
597 <p>
598 <label>
599 <?php esc_html_e( 'Default sort order:', 'jetpack' ); ?>
600 <select
601 name="<?php echo esc_attr( $this->get_field_name( 'sort' ) ); ?>"
602 class="widefat jetpack-search-filters-widget__sort-order">
603 <?php foreach ( $this->get_sort_types() as $sort_type => $label ) { ?>
604 <option value="<?php echo esc_attr( $sort_type ); ?>" <?php selected( $instance['sort'], $sort_type ); ?>>
605 <?php echo esc_html( $label ); ?>
606 </option>
607 <?php } ?>
608 </select>
609 </label>
610 </p>
611
612 <?php if ( ! $hide_filters ) : ?>
613 <script class="jetpack-search-filters-widget__filter-template" type="text/template">
614 <?php echo $this->render_widget_edit_filter( array(), true ); ?>
615 </script>
616 <div class="jetpack-search-filters-widget__filters">
617 <?php foreach ( (array) $instance['filters'] as $filter ) : ?>
618 <?php $this->render_widget_edit_filter( $filter ); ?>
619 <?php endforeach; ?>
620 </div>
621 <p class="jetpack-search-filters-widget__add-filter-wrapper">
622 <a class="button jetpack-search-filters-widget__add-filter" href="#">
623 <?php esc_html_e( 'Add a filter', 'jetpack' ); ?>
624 </a>
625 </p>
626 <noscript>
627 <p class="jetpack-search-filters-help">
628 <?php echo esc_html_e( 'Adding filters requires JavaScript!', 'jetpack' ); ?>
629 </p>
630 </noscript>
631 <?php if ( is_customize_preview() ) : ?>
632 <p class="jetpack-search-filters-help">
633 <a href="https://jetpack.com/support/search/#filters-not-showing-up" target="_blank">
634 <?php esc_html_e( "Why aren't my filters appearing?", 'jetpack' ); ?>
635 </a>
636 </p>
637 <?php endif; ?>
638 <?php endif; ?>
639 </div>
640 <?php
641 }
642
643 /**
644 * We need to render HTML in two formats: an Underscore template (client-side)
645 * and native PHP (server-side). This helper function allows for easy rendering
646 * of attributes in both formats.
647 *
648 * @since 5.8.0
649 *
650 * @param string $name Attribute name.
651 * @param string $value Attribute value.
652 * @param bool $is_template Whether this is for an Underscore template or not.
653 */
654 private function render_widget_attr( $name, $value, $is_template ) {
655 echo $is_template ? "<%= $name %>" : esc_attr( $value );
656 }
657
658 /**
659 * We need to render HTML in two formats: an Underscore template (client-size)
660 * and native PHP (server-side). This helper function allows for easy rendering
661 * of the "selected" attribute in both formats.
662 *
663 * @since 5.8.0
664 *
665 * @param string $name Attribute name.
666 * @param string $value Attribute value.
667 * @param string $compare Value to compare to the attribute value to decide if it should be selected.
668 * @param bool $is_template Whether this is for an Underscore template or not.
669 */
670 private function render_widget_option_selected( $name, $value, $compare, $is_template ) {
671 $compare_js = rawurlencode( $compare );
672 echo $is_template ? "<%= decodeURIComponent( '$compare_js' ) === $name ? 'selected=\"selected\"' : '' %>" : selected( $value, $compare );
673 }
674
675 /**
676 * Responsible for rendering a single filter in the customizer or the widget administration screen in wp-admin.
677 *
678 * We use this method for two purposes - rendering the fields server-side, and also rendering a script template for Underscore.
679 *
680 * @since 5.7.0
681 *
682 * @param array $filter The filter to render.
683 * @param bool $is_template Whether this is for an Underscore template or not.
684 */
685 public function render_widget_edit_filter( $filter, $is_template = false ) {
686 $args = wp_parse_args(
687 $filter, array(
688 'name' => '',
689 'type' => 'taxonomy',
690 'taxonomy' => '',
691 'post_type' => '',
692 'field' => '',
693 'interval' => '',
694 'count' => self::DEFAULT_FILTER_COUNT,
695 )
696 );
697
698 $args['name_placeholder'] = Jetpack_Search_Helpers::generate_widget_filter_name( $args );
699
700 ?>
701 <div class="jetpack-search-filters-widget__filter is-<?php $this->render_widget_attr( 'type', $args['type'], $is_template ); ?>">
702 <p class="jetpack-search-filters-widget__type-select">
703 <label>
704 <?php esc_html_e( 'Filter Type:', 'jetpack' ); ?>
705 <select name="<?php echo esc_attr( $this->get_field_name( 'filter_type' ) ); ?>[]" class="widefat filter-select">
706 <option value="taxonomy" <?php $this->render_widget_option_selected( 'type', $args['type'], 'taxonomy', $is_template ); ?>>
707 <?php esc_html_e( 'Taxonomy', 'jetpack' ); ?>
708 </option>
709 <option value="post_type" <?php $this->render_widget_option_selected( 'type', $args['type'], 'post_type', $is_template ); ?>>
710 <?php esc_html_e( 'Post Type', 'jetpack' ); ?>
711 </option>
712 <option value="date_histogram" <?php $this->render_widget_option_selected( 'type', $args['type'], 'date_histogram', $is_template ); ?>>
713 <?php esc_html_e( 'Date', 'jetpack' ); ?>
714 </option>
715 </select>
716 </label>
717 </p>
718
719 <p class="jetpack-search-filters-widget__taxonomy-select">
720 <label>
721 <?php
722 esc_html_e( 'Choose a taxonomy:', 'jetpack' );
723 $seen_taxonomy_labels = array();
724 ?>
725 <select name="<?php echo esc_attr( $this->get_field_name( 'taxonomy_type' ) ); ?>[]" class="widefat taxonomy-select">
726 <?php foreach ( get_taxonomies( array( 'public' => true ), 'objects' ) as $taxonomy ) : ?>
727 <option value="<?php echo esc_attr( $taxonomy->name ); ?>" <?php $this->render_widget_option_selected( 'taxonomy', $args['taxonomy'], $taxonomy->name, $is_template ); ?>>
728 <?php
729 $label = in_array( $taxonomy->label, $seen_taxonomy_labels )
730 ? sprintf(
731 /* translators: %1$s is the taxonomy name, %2s is the name of its type to help distinguish between several taxonomies with the same name, e.g. category and tag. */
732 _x( '%1$s (%2$s)', 'A label for a taxonomy selector option', 'jetpack' ),
733 $taxonomy->label,
734 $taxonomy->name
735 )
736 : $taxonomy->label;
737 echo esc_html( $label );
738 $seen_taxonomy_labels[] = $taxonomy->label;
739 ?>
740 </option>
741 <?php endforeach; ?>
742 </select>
743 </label>
744 </p>
745
746 <p class="jetpack-search-filters-widget__date-histogram-select">
747 <label>
748 <?php esc_html_e( 'Choose a field:', 'jetpack' ); ?>
749 <select name="<?php echo esc_attr( $this->get_field_name( 'date_histogram_field' ) ); ?>[]" class="widefat date-field-select">
750 <option value="post_date" <?php $this->render_widget_option_selected( 'field', $args['field'], 'post_date', $is_template ); ?>>
751 <?php esc_html_e( 'Date', 'jetpack' ); ?>
752 </option>
753 <option value="post_date_gmt" <?php $this->render_widget_option_selected( 'field', $args['field'], 'post_date_gmt', $is_template ); ?>>
754 <?php esc_html_e( 'Date GMT', 'jetpack' ); ?>
755 </option>
756 <option value="post_modified" <?php $this->render_widget_option_selected( 'field', $args['field'], 'post_modified', $is_template ); ?>>
757 <?php esc_html_e( 'Modified', 'jetpack' ); ?>
758 </option>
759 <option value="post_modified_gmt" <?php $this->render_widget_option_selected( 'field', $args['field'], 'post_modified_gmt', $is_template ); ?>>
760 <?php esc_html_e( 'Modified GMT', 'jetpack' ); ?>
761 </option>
762 </select>
763 </label>
764 </p>
765
766 <p class="jetpack-search-filters-widget__date-histogram-select">
767 <label>
768 <?php esc_html_e( 'Choose an interval:' ); ?>
769 <select name="<?php echo esc_attr( $this->get_field_name( 'date_histogram_interval' ) ); ?>[]" class="widefat date-interval-select">
770 <option value="month" <?php $this->render_widget_option_selected( 'interval', $args['interval'], 'month', $is_template ); ?>>
771 <?php esc_html_e( 'Month', 'jetpack' ); ?>
772 </option>
773 <option value="year" <?php $this->render_widget_option_selected( 'interval', $args['interval'], 'year', $is_template ); ?>>
774 <?php esc_html_e( 'Year', 'jetpack' ); ?>
775 </option>
776 </select>
777 </label>
778 </p>
779
780 <p class="jetpack-search-filters-widget__title">
781 <label>
782 <?php esc_html_e( 'Title:', 'jetpack' ); ?>
783 <input
784 class="widefat"
785 type="text"
786 name="<?php echo esc_attr( $this->get_field_name( 'filter_name' ) ); ?>[]"
787 value="<?php $this->render_widget_attr( 'name', $args['name'], $is_template ); ?>"
788 placeholder="<?php $this->render_widget_attr( 'name_placeholder', $args['name_placeholder'], $is_template ); ?>"
789 />
790 </label>
791 </p>
792
793 <p>
794 <label>
795 <?php esc_html_e( 'Maximum number of filters (1-50):', 'jetpack' ); ?>
796 <input
797 class="widefat filter-count"
798 name="<?php echo esc_attr( $this->get_field_name( 'num_filters' ) ); ?>[]"
799 type="number"
800 value="<?php $this->render_widget_attr( 'count', $args['count'], $is_template ); ?>"
801 min="1"
802 max="50"
803 step="1"
804 required
805 />
806 </label>
807 </p>
808
809 <p class="jetpack-search-filters-widget__controls">
810 <a href="#" class="delete"><?php esc_html_e( 'Remove', 'jetpack' ); ?></a>
811 </p>
812 </div>
813 <?php
814 }
815 }
816