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