'jetpack-filters widget_search', 'description' => __( 'Replaces the default search with an Elasticsearch-powered search interface and filters.', 'jetpack' ), ) ); if ( Jetpack_Search_Helpers::is_active_widget( $this->id ) && ! Jetpack::is_module_active( 'search' ) ) { Jetpack::activate_module( 'search', false, false ); } if ( is_admin() ) { add_action( 'sidebar_admin_setup', array( $this, 'widget_admin_setup' ) ); } else { add_action( 'wp_enqueue_scripts', array( $this, 'enqueue_frontend_scripts' ) ); } add_action( 'jetpack_search_render_filters_widget_title', array( 'Jetpack_Search_Template_Tags', 'render_widget_title' ), 10, 3 ); add_action( 'jetpack_search_render_filters', array( 'Jetpack_Search_Template_Tags', 'render_available_filters' ), 10, 2 ); } /** * Enqueues the scripts and styles needed for the customizer. * * @since 5.7.0 */ public function widget_admin_setup() { wp_enqueue_style( 'widget-jetpack-search-filters', plugins_url( 'search/css/search-widget-admin-ui.css', __FILE__ ) ); // Required for Tracks wp_register_script( 'jp-tracks', '//stats.wp.com/w.js', array(), gmdate( 'YW' ), true ); wp_register_script( 'jp-tracks-functions', plugins_url( '_inc/lib/tracks/tracks-callables.js', JETPACK__PLUGIN_FILE ), array(), JETPACK__VERSION, false ); wp_register_script( 'jetpack-search-widget-admin', plugins_url( 'search/js/search-widget-admin.js', __FILE__ ), array( 'jquery', 'jquery-ui-sortable', 'jp-tracks', 'jp-tracks-functions' ), JETPACK__VERSION ); wp_localize_script( 'jetpack-search-widget-admin', 'jetpack_search_filter_admin', array( 'defaultFilterCount' => self::DEFAULT_FILTER_COUNT, 'tracksUserData' => Jetpack_Tracks_Client::get_connected_user_tracks_identity(), 'tracksEventData' => array( 'is_customizer' => ( function_exists( 'is_customize_preview' ) && is_customize_preview() ) ? 1 : 0, ), 'i18n' => array( 'month' => Jetpack_Search_Helpers::get_date_filter_type_name( 'month', false ), 'year' => Jetpack_Search_Helpers::get_date_filter_type_name( 'year', false ), 'monthUpdated' => Jetpack_Search_Helpers::get_date_filter_type_name( 'month', true ), 'yearUpdated' => Jetpack_Search_Helpers::get_date_filter_type_name( 'year', true ), ), ) ); wp_enqueue_script( 'jetpack-search-widget-admin' ); } /** * Enqueue scripts and styles for the frontend. * * @since 5.8.0 */ public function enqueue_frontend_scripts() { if ( ! is_active_widget( false, false, $this->id_base, true ) ) { return; } wp_enqueue_script( 'jetpack-search-widget', plugins_url( 'search/js/search-widget.js', __FILE__ ), array( 'jquery' ), JETPACK__VERSION, true ); wp_enqueue_style( 'jetpack-search-widget', plugins_url( 'search/css/search-widget-frontend.css', __FILE__ ) ); } /** * Get the list of valid sort types/orders. * * @since 5.8.0 * * @return array The sort orders. */ private function get_sort_types() { return array( 'relevance|DESC' => is_admin() ? esc_html__( 'Relevance (recommended)', 'jetpack' ) : esc_html__( 'Relevance', 'jetpack' ), 'date|DESC' => esc_html__( 'Newest first', 'jetpack' ), 'date|ASC' => esc_html__( 'Oldest first', 'jetpack' ) ); } /** * Callback for an array_filter() call in order to only get filters for the current widget. * * @see Jetpack_Search_Widget::widget() * * @since 5.7.0 * * @param array $item Filter item. * * @return bool Whether the current filter item is for the current widget. */ function is_for_current_widget( $item ) { return isset( $item['widget_id'] ) && $this->id == $item['widget_id']; } /** * This method returns a boolean for whether the widget should show site-wide filters for the site. * * This is meant to provide backwards-compatibility for VIP, and other professional plan users, that manually * configured filters via `Jetpack_Search::set_filters()`. * * @since 5.7.0 * * @return bool Whether the widget should display site-wide filters or not. */ public function should_display_sitewide_filters() { $filter_widgets = get_option( 'widget_jetpack-search-filters' ); // This shouldn't be empty, but just for sanity if ( empty( $filter_widgets ) ) { return false; } // If any widget has any filters, return false foreach ( $filter_widgets as $number => $widget ) { $widget_id = sprintf( '%s-%d', $this->id_base, $number ); if ( ! empty( $widget['filters'] ) && is_active_widget( false, $widget_id, $this->id_base ) ) { return false; } } return true; } public function jetpack_search_populate_defaults( $instance ) { $instance = wp_parse_args( (array) $instance, array( 'title' => '', 'search_box_enabled' => true, 'user_sort_enabled' => true, 'sort' => self::DEFAULT_SORT, 'filters' => array( array() ), ) ); return $instance; } /** * Responsible for rendering the widget on the frontend. * * @since 5.0.0 * * @param array $args Widgets args supplied by the theme. * @param array $instance The current widget instance. */ public function widget( $args, $instance ) { $instance = $this->jetpack_search_populate_defaults( $instance ); $display_filters = false; if ( is_search() ) { if ( Jetpack_Search_Helpers::should_rerun_search_in_customizer_preview() ) { Jetpack_Search::instance()->update_search_results_aggregations(); } $filters = Jetpack_Search::instance()->get_filters(); if ( ! Jetpack_Search_Helpers::are_filters_by_widget_disabled() && ! $this->should_display_sitewide_filters() ) { $filters = array_filter( $filters, array( $this, 'is_for_current_widget' ) ); } if ( ! empty( $filters ) ) { $display_filters = true; } } if ( ! $display_filters && empty( $instance['search_box_enabled'] ) && empty( $instance['user_sort_enabled'] ) ) { return; } $title = isset( $instance['title'] ) ? $instance['title'] : ''; if ( empty( $title ) ) { $title = ''; } /** This filter is documented in core/src/wp-includes/default-widgets.php */ $title = apply_filters( 'widget_title', $title, $instance, $this->id_base ); echo $args['before_widget']; ?>
sorting_to_wp_query_param( $default_sort ); $current_sort = "{$orderby}|{$order}"; // we need to dynamically inject the sort field into the search box when the search box is enabled, and display // it separately when it's not. if ( ! empty( $instance['search_box_enabled'] ) ) { Jetpack_Search_Template_Tags::render_widget_search_form( $instance['post_types'], $orderby, $order ); } if ( ! empty( $instance['search_box_enabled'] ) && ! empty( $instance['user_sort_enabled'] ) ): ?>
maybe_render_sort_javascript( $instance, $order, $orderby ); echo "
"; echo $args['after_widget']; } /** * Renders JavaScript for the sorting controls on the frontend. * * This JS is a bit complicated, but here's what it's trying to do: * - find the search form * - find the orderby/order fields and set default values * - detect changes to the sort field, if it exists, and use it to set the order field values * * @since 5.8.0 * * @param array $instance The current widget instance. * @param string $order The order to initialize the select with. * @param string $orderby The orderby to initialize the select with. */ private function maybe_render_sort_javascript( $instance, $order, $orderby ) { if ( ! empty( $instance['user_sort_enabled'] ) ) : ?> $type ) { $count = intval( $new_instance['num_filters'][ $index ] ); $count = min( 50, $count ); // Set max boundary at 20. $count = max( 1, $count ); // Set min boundary at 1. switch ( $type ) { case 'taxonomy': $filters[] = array( 'name' => sanitize_text_field( $new_instance['filter_name'][ $index ] ), 'type' => 'taxonomy', 'taxonomy' => sanitize_key( $new_instance['taxonomy_type'][ $index ] ), 'count' => $count, ); break; case 'post_type': $filters[] = array( 'name' => sanitize_text_field( $new_instance['filter_name'][ $index ] ), 'type' => 'post_type', 'count' => $count, ); break; case 'date_histogram': $filters[] = array( 'name' => sanitize_text_field( $new_instance['filter_name'][ $index ] ), 'type' => 'date_histogram', 'count' => $count, 'field' => sanitize_key( $new_instance['date_histogram_field'][ $index ] ), 'interval' => sanitize_key( $new_instance['date_histogram_interval'][ $index ] ), ); break; } } } if ( ! empty( $filters ) ) { $instance['filters'] = $filters; } return $instance; } /** * Outputs the settings update form. * * @since 5.0.0 * * @param array $instance Current settings. */ public function form( $instance ) { $instance = $this->jetpack_search_populate_defaults( $instance ); $title = strip_tags( $instance['title'] ); $hide_filters = Jetpack_Search_Helpers::are_filters_by_widget_disabled(); $classes = sprintf( 'jetpack-search-filters-widget %s %s %s', $hide_filters ? 'hide-filters' : '', $instance['search_box_enabled'] ? '' : 'hide-post-types', $this->id ); ?>

false ), 'objects' ) as $post_type ) : ?>

render_widget_edit_filter( $filter ); ?>

" : esc_attr( $value ); } /** * We need to render HTML in two formats: an Underscore template (client-size) * and native PHP (server-side). This helper function allows for easy rendering * of the "selected" attribute in both formats. * * @since 5.8.0 * * @param string $name Attribute name. * @param string $value Attribute value. * @param string $compare Value to compare to the attribute value to decide if it should be selected. * @param bool $is_template Whether this is for an Underscore template or not. */ private function render_widget_option_selected( $name, $value, $compare, $is_template ) { $compare_json = wp_json_encode( $compare ); echo $is_template ? "<%= $compare_json === $name ? 'selected=\"selected\"' : '' %>" : selected( $value, $compare ); } /** * Responsible for rendering a single filter in the customizer or the widget administration screen in wp-admin. * * We use this method for two purposes - rendering the fields server-side, and also rendering a script template for Underscore. * * @since 5.7.0 * * @param array $filter The filter to render. * @param bool $is_template Whether this is for an Underscore template or not. */ public function render_widget_edit_filter( $filter, $is_template = false ) { $args = wp_parse_args( $filter, array( 'name' => '', 'type' => 'taxonomy', 'taxonomy' => '', 'post_type' => '', 'field' => '', 'interval' => '', 'count' => self::DEFAULT_FILTER_COUNT, ) ); $args['name_placeholder'] = Jetpack_Search_Helpers::generate_widget_filter_name( $args ); ?>