summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
Diffstat (limited to 'plugins/jetpack/modules/widgets/search.php')
-rw-r--r--plugins/jetpack/modules/widgets/search.php483
1 files changed, 370 insertions, 113 deletions
diff --git a/plugins/jetpack/modules/widgets/search.php b/plugins/jetpack/modules/widgets/search.php
index 5cff02f4..291649f2 100644
--- a/plugins/jetpack/modules/widgets/search.php
+++ b/plugins/jetpack/modules/widgets/search.php
@@ -1,4 +1,4 @@
-<?php
+<?php // phpcs:ignore WordPress.Files.FileName.InvalidClassFileName
/**
* Jetpack Search: Jetpack_Search_Widget class
*
@@ -7,21 +7,26 @@
* @since 5.0.0
*/
-use Automattic\Jetpack\Constants;
+use Automattic\Jetpack\Redirect;
+use Automattic\Jetpack\Search\Helper;
+use Automattic\Jetpack\Search\Options;
use Automattic\Jetpack\Status;
+use Automattic\Jetpack\Tracking;
add_action( 'widgets_init', 'jetpack_search_widget_init' );
+/**
+ * Register the widget if Jetpack Search is available and enabled.
+ */
function jetpack_search_widget_init() {
if (
- ! Jetpack::is_active()
+ ! Jetpack::is_connection_ready()
|| ( method_exists( 'Jetpack_Plan', 'supports' ) && ! Jetpack_Plan::supports( 'search' ) )
+ || ! Jetpack::is_module_active( 'search' )
) {
return;
}
- require_once JETPACK__PLUGIN_DIR . 'modules/search/class.jetpack-search-helpers.php';
-
register_widget( 'Jetpack_Search_Widget' );
}
@@ -62,23 +67,25 @@ class Jetpack_Search_Widget extends WP_Widget {
* Jetpack_Search_Widget constructor.
*
* @since 5.0.0
+ *
+ * @param string $name Widget name.
*/
public function __construct( $name = null ) {
if ( empty( $name ) ) {
$name = esc_html__( 'Search', 'jetpack' );
}
parent::__construct(
- Jetpack_Search_Helpers::FILTER_WIDGET_BASE,
+ Helper::FILTER_WIDGET_BASE,
/** This filter is documented in modules/widgets/facebook-likebox.php */
apply_filters( 'jetpack_widget_name', $name ),
array(
'classname' => 'jetpack-filters widget_search',
- 'description' => __( 'Replaces the default search with an Elasticsearch-powered search interface and filters.', 'jetpack' ),
+ 'description' => __( 'Instant search and filtering to help visitors quickly find relevant answers and explore your site.', 'jetpack' ),
)
);
if (
- Jetpack_Search_Helpers::is_active_widget( $this->id ) &&
+ Helper::is_active_widget( $this->id ) &&
! $this->is_search_active()
) {
$this->activate_search();
@@ -90,8 +97,12 @@ class Jetpack_Search_Widget extends WP_Widget {
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 );
+ add_action( 'jetpack_search_render_filters_widget_title', array( 'Automattic\Jetpack\Search\Template_Tags', 'render_widget_title' ), 10, 3 );
+ if ( Options::is_instant_enabled() ) {
+ add_action( 'jetpack_search_render_filters', array( 'Automattic\Jetpack\Search\Template_Tags', 'render_instant_filters' ), 10, 2 );
+ } else {
+ add_action( 'jetpack_search_render_filters', array( 'Automattic\Jetpack\Search\Template_Tags', 'render_available_filters' ), 10, 2 );
+ }
}
/**
@@ -112,51 +123,44 @@ class Jetpack_Search_Widget extends WP_Widget {
Jetpack::activate_module( 'search', false, false );
}
-
/**
* 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',
+ wp_enqueue_style(
+ 'widget-jetpack-search-filters',
+ plugins_url( 'search/css/search-widget-admin-ui.css', __FILE__ ),
array(),
- gmdate( 'YW' ),
- true
+ JETPACK__VERSION
);
- wp_register_script(
- 'jp-tracks-functions',
- plugins_url( '_inc/lib/tracks/tracks-callables.js', JETPACK__PLUGIN_FILE ),
- array(),
- JETPACK__VERSION,
- false
- );
+ // Register jp-tracks and jp-tracks-functions.
+ Tracking::register_tracks_functions_scripts();
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
+ array( 'jquery', 'jquery-ui-sortable', 'jp-tracks-functions' ),
+ JETPACK__VERSION,
+ false
);
wp_localize_script(
- 'jetpack-search-widget-admin', 'jetpack_search_filter_admin', array(
+ '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' => (int) is_customize_preview(),
),
'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 ),
+ 'month' => Helper::get_date_filter_type_name( 'month', false ),
+ 'year' => Helper::get_date_filter_type_name( 'year', false ),
+ 'monthUpdated' => Helper::get_date_filter_type_name( 'month', true ),
+ 'yearUpdated' => Helper::get_date_filter_type_name( 'year', true ),
),
)
);
@@ -170,19 +174,24 @@ class Jetpack_Search_Widget extends WP_Widget {
* @since 5.8.0
*/
public function enqueue_frontend_scripts() {
- if ( ! is_active_widget( false, false, $this->id_base, true ) || Constants::is_true( 'JETPACK_SEARCH_PROTOTYPE' ) ) {
+ if ( ! is_active_widget( false, false, $this->id_base, true ) || Options::is_instant_enabled() ) {
return;
}
wp_enqueue_script(
'jetpack-search-widget',
plugins_url( 'search/js/search-widget.js', __FILE__ ),
- array( 'jquery' ),
+ array(),
JETPACK__VERSION,
true
);
- wp_enqueue_style( 'jetpack-search-widget', plugins_url( 'search/css/search-widget-frontend.css', __FILE__ ) );
+ wp_enqueue_style(
+ 'jetpack-search-widget',
+ plugins_url( 'search/css/search-widget-frontend.css', __FILE__ ),
+ array(),
+ JETPACK__VERSION
+ );
}
/**
@@ -211,8 +220,8 @@ class Jetpack_Search_Widget extends WP_Widget {
*
* @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'];
+ public function is_for_current_widget( $item ) {
+ return isset( $item['widget_id'] ) && $this->id == $item['widget_id']; // phpcs:ignore WordPress.PHP.StrictComparisons.LooseComparison
}
/**
@@ -228,12 +237,12 @@ class Jetpack_Search_Widget extends WP_Widget {
public function should_display_sitewide_filters() {
$filter_widgets = get_option( 'widget_jetpack-search-filters' );
- // This shouldn't be empty, but just for sanity
+ // This shouldn't be empty, but just for sanity.
if ( empty( $filter_widgets ) ) {
return false;
}
- // If any widget has any filters, 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 ) ) {
@@ -244,9 +253,15 @@ class Jetpack_Search_Widget extends WP_Widget {
return true;
}
+ /**
+ * Widget defaults.
+ *
+ * @param array $instance Previously saved values from database.
+ */
public function jetpack_search_populate_defaults( $instance ) {
$instance = wp_parse_args(
- (array) $instance, array(
+ (array) $instance,
+ array(
'title' => '',
'search_box_enabled' => true,
'user_sort_enabled' => true,
@@ -260,6 +275,23 @@ class Jetpack_Search_Widget extends WP_Widget {
}
/**
+ * Populates the instance array with appropriate default values.
+ *
+ * @since 8.6.0
+ * @param array $instance Previously saved values from database.
+ * @return array Instance array with default values approprate for instant search
+ */
+ public function populate_defaults_for_instant_search( $instance ) {
+ return wp_parse_args(
+ (array) $instance,
+ array(
+ 'title' => '',
+ 'filters' => array(),
+ )
+ );
+ }
+
+ /**
* Responsible for rendering the widget on the frontend.
*
* @since 5.0.0
@@ -270,29 +302,50 @@ class Jetpack_Search_Widget extends WP_Widget {
public function widget( $args, $instance ) {
$instance = $this->jetpack_search_populate_defaults( $instance );
- $display_filters = false;
-
- if ( ( new Status() )->is_development_mode() ) {
- echo $args['before_widget'];
+ if ( ( new Status() )->is_offline_mode() ) {
+ echo $args['before_widget']; //phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped
?><div id="<?php echo esc_attr( $this->id ); ?>-wrapper">
<div class="jetpack-search-sort-wrapper">
<label>
- <?php esc_html_e( 'Jetpack Search not supported in Development Mode', 'jetpack' ); ?>
+ <?php esc_html_e( 'Jetpack Search not supported in Offline Mode', 'jetpack' ); ?>
</label>
</div>
- </div><?php
- echo $args['after_widget'];
+ </div>
+ <?php
+ echo $args['after_widget']; //phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped
return;
}
+ if ( Options::is_instant_enabled() ) {
+ if ( array_key_exists( 'id', $args ) && 'jetpack-instant-search-sidebar' === $args['id'] ) {
+ $this->widget_empty_instant( $args, $instance );
+ } else {
+ $this->widget_instant( $args, $instance );
+ }
+ } else {
+ $this->widget_non_instant( $args, $instance );
+ }
+ }
+
+ /**
+ * Render the non-instant frontend widget.
+ *
+ * @since 8.3.0
+ *
+ * @param array $args Widgets args supplied by the theme.
+ * @param array $instance The current widget instance.
+ */
+ public function widget_non_instant( $args, $instance ) {
+ $display_filters = false;
+
if ( is_search() ) {
- if ( Jetpack_Search_Helpers::should_rerun_search_in_customizer_preview() ) {
+ if ( Helper::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() ) {
+ if ( ! Helper::are_filters_by_widget_disabled() && ! $this->should_display_sitewide_filters() ) {
$filters = array_filter( $filters, array( $this, 'is_for_current_widget' ) );
}
@@ -305,18 +358,14 @@ class Jetpack_Search_Widget extends WP_Widget {
return;
}
- $title = isset( $instance['title'] ) ? $instance['title'] : '';
-
- if ( empty( $title ) ) {
- $title = '';
- }
+ $title = ! empty( $instance['title'] ) ? $instance['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'];
- ?><div id="<?php echo esc_attr( $this->id ); ?>-wrapper" class="<?php
- echo Constants::is_true( 'JETPACK_SEARCH_PROTOTYPE' ) ? 'jetpack-instant-search-wrapper' : '' ?>">
+ echo $args['before_widget']; //phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped
+ ?>
+ <div id="<?php echo esc_attr( $this->id ); ?>-wrapper" >
<?php
if ( ! empty( $title ) ) {
@@ -341,11 +390,11 @@ class Jetpack_Search_Widget extends WP_Widget {
// 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 );
+ Automattic\Jetpack\Search\Template_Tags::render_widget_search_form( $instance['post_types'], $orderby, $order );
}
if ( ! empty( $instance['search_box_enabled'] ) && ! empty( $instance['user_sort_enabled'] ) ) :
- ?>
+ ?>
<div class="jetpack-search-sort-wrapper">
<label>
<?php esc_html_e( 'Sort by', 'jetpack' ); ?>
@@ -358,7 +407,7 @@ class Jetpack_Search_Widget extends WP_Widget {
</select>
</label>
</div>
- <?php
+ <?php
endif;
if ( $display_filters ) {
@@ -382,7 +431,118 @@ class Jetpack_Search_Widget extends WP_Widget {
$this->maybe_render_sort_javascript( $instance, $order, $orderby );
echo '</div>';
- echo $args['after_widget'];
+ echo $args['after_widget']; //phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped
+ }
+
+ /**
+ * Render the instant frontend widget.
+ *
+ * @since 8.3.0
+ *
+ * @param array $args Widgets args supplied by the theme.
+ * @param array $instance The current widget instance.
+ */
+ public function widget_instant( $args, $instance ) {
+ if ( Helper::should_rerun_search_in_customizer_preview() ) {
+ Jetpack_Search::instance()->update_search_results_aggregations();
+ }
+
+ $filters = Jetpack_Search::instance()->get_filters();
+ if ( ! Helper::are_filters_by_widget_disabled() && ! $this->should_display_sitewide_filters() ) {
+ $filters = array_filter( $filters, array( $this, 'is_for_current_widget' ) );
+ }
+
+ $display_filters = ! empty( $filters );
+
+ $title = ! empty( $instance['title'] ) ? $instance['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']; //phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped
+ ?>
+ <div id="<?php echo esc_attr( $this->id ); ?>-wrapper" class="jetpack-instant-search-wrapper">
+ <?php
+
+ if ( ! empty( $title ) ) {
+ /**
+ * Responsible for displaying the title of the Jetpack Search filters widget.
+ *
+ * @module search
+ *
+ * @since 5.7.0
+ *
+ * @param string $title The widget's title
+ * @param string $args['before_title'] The HTML tag to display before the title
+ * @param string $args['after_title'] The HTML tag to display after the title
+ */
+ do_action( 'jetpack_search_render_filters_widget_title', $title, $args['before_title'], $args['after_title'] );
+ }
+
+ Automattic\Jetpack\Search\Template_Tags::render_widget_search_form( array(), '', '' );
+
+ if ( $display_filters ) {
+ /**
+ * Responsible for rendering filters to narrow down search results.
+ *
+ * @module search
+ *
+ * @since 5.8.0
+ *
+ * @param array $filters The possible filters for the current query.
+ * @param array $post_types An array of post types to limit filtering to.
+ */
+ do_action(
+ 'jetpack_search_render_filters',
+ $filters,
+ null
+ );
+ }
+
+ echo '</div>';
+ echo $args['after_widget']; //phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped
+ }
+
+ /**
+ * Render the instant widget for the overlay.
+ *
+ * @since 8.3.0
+ *
+ * @param array $args Widgets args supplied by the theme.
+ * @param array $instance The current widget instance.
+ */
+ public function widget_empty_instant( $args, $instance ) {
+ $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']; //phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped
+ ?>
+ <div id="<?php echo esc_attr( $this->id ); ?>-wrapper" class="jetpack-instant-search-wrapper">
+ <?php
+
+ if ( ! empty( $title ) ) {
+ /**
+ * Responsible for displaying the title of the Jetpack Search filters widget.
+ *
+ * @module search
+ *
+ * @since 5.7.0
+ *
+ * @param string $title The widget's title
+ * @param string $args['before_title'] The HTML tag to display before the title
+ * @param string $args['after_title'] The HTML tag to display after the title
+ */
+ do_action( 'jetpack_search_render_filters_widget_title', $title, $args['before_title'], $args['after_title'] );
+ }
+
+ echo '</div>';
+ echo $args['after_widget']; //phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped
}
/**
@@ -400,48 +560,55 @@ class Jetpack_Search_Widget extends WP_Widget {
* @param string $orderby The orderby to initialize the select with.
*/
private function maybe_render_sort_javascript( $instance, $order, $orderby ) {
- if ( Constants::is_true( 'JETPACK_SEARCH_PROTOTYPE' ) ) {
+ if ( Options::is_instant_enabled() ) {
return;
}
if ( ! empty( $instance['user_sort_enabled'] ) ) :
- ?>
+ ?>
<script type="text/javascript">
- jQuery( document ).ready( function( $ ) {
- var orderByDefault = '<?php echo 'date' === $orderby ? 'date' : 'relevance'; ?>',
- orderDefault = '<?php echo 'ASC' === $order ? 'ASC' : 'DESC'; ?>',
- widgetId = decodeURIComponent( '<?php echo rawurlencode( $this->id ); ?>' ),
- searchQuery = decodeURIComponent( '<?php echo rawurlencode( get_query_var( 's', '' ) ); ?>' ),
- isSearch = <?php echo (int) is_search(); ?>;
-
- var container = $( '#' + widgetId + '-wrapper' ),
- form = container.find('.jetpack-search-form form'),
- orderBy = form.find( 'input[name=orderby]'),
- order = form.find( 'input[name=order]'),
- searchInput = form.find( 'input[name="s"]' );
-
- orderBy.val( orderByDefault );
- order.val( orderDefault );
-
- // Some themes don't set the search query, which results in the query being lost
- // when doing a sort selection. So, if the query isn't set, let's set it now. This approach
- // is chosen over running a regex over HTML for every search query performed.
- if ( isSearch && ! searchInput.val() ) {
- searchInput.val( searchQuery );
- }
-
- searchInput.addClass( 'show-placeholder' );
-
- container.find( '.jetpack-search-sort' ).change( function( event ) {
- var values = event.target.value.split( '|' );
- orderBy.val( values[0] );
- order.val( values[1] );
-
- form.submit();
- });
+ var jetpackSearchModuleSorting = function() {
+ var orderByDefault = '<?php echo 'date' === $orderby ? 'date' : 'relevance'; ?>',
+ orderDefault = '<?php echo 'ASC' === $order ? 'ASC' : 'DESC'; ?>',
+ widgetId = decodeURIComponent( '<?php echo rawurlencode( $this->id ); ?>' ),
+ searchQuery = decodeURIComponent( '<?php echo rawurlencode( get_query_var( 's', '' ) ); ?>' ),
+ isSearch = <?php echo (int) is_search(); ?>;
+
+ var container = document.getElementById( widgetId + '-wrapper' ),
+ form = container.querySelector( '.jetpack-search-form form' ),
+ orderBy = form.querySelector( 'input[name=orderby]' ),
+ order = form.querySelector( 'input[name=order]' ),
+ searchInput = form.querySelector( 'input[name="s"]' ),
+ sortSelectInput = container.querySelector( '.jetpack-search-sort' );
+
+ orderBy.value = orderByDefault;
+ order.value = orderDefault;
+
+ // Some themes don't set the search query, which results in the query being lost
+ // when doing a sort selection. So, if the query isn't set, let's set it now. This approach
+ // is chosen over running a regex over HTML for every search query performed.
+ if ( isSearch && ! searchInput.value ) {
+ searchInput.value = searchQuery;
+ }
+
+ searchInput.classList.add( 'show-placeholder' );
+
+ sortSelectInput.addEventListener( 'change', function( event ) {
+ var values = event.target.value.split( '|' );
+ orderBy.value = values[0];
+ order.value = values[1];
+
+ form.submit();
} );
+ }
+
+ if ( document.readyState === 'interactive' || document.readyState === 'complete' ) {
+ jetpackSearchModuleSorting();
+ } else {
+ document.addEventListener( 'DOMContentLoaded', jetpackSearchModuleSorting );
+ }
</script>
- <?php
+ <?php
endif;
}
@@ -455,6 +622,7 @@ class Jetpack_Search_Widget extends WP_Widget {
* @return array Order by and order.
*/
private function sorting_to_wp_query_param( $sort ) {
+ // phpcs:disable WordPress.Security.NonceVerification.Recommended
$parts = explode( '|', $sort );
$orderby = isset( $_GET['orderby'] )
? $_GET['orderby']
@@ -464,6 +632,8 @@ class Jetpack_Search_Widget extends WP_Widget {
? strtoupper( $_GET['order'] )
: ( ( isset( $parts[1] ) && 'ASC' === strtoupper( $parts[1] ) ) ? 'ASC' : 'DESC' );
+ // phpcs:enable WordPress.Security.NonceVerification.Recommended
+
return array( $orderby, $order );
}
@@ -477,8 +647,9 @@ class Jetpack_Search_Widget extends WP_Widget {
*
* @return array Settings to save.
*/
- public function update( $new_instance, $old_instance ) {
- $instance = array();
+ public function update( $new_instance, $old_instance ) { // phpcs:ignore VariableAnalysis.CodeAnalysis.VariableAnalysis.UnusedVariable
+ $new_instance = $this->maybe_reformat_widget( $new_instance );
+ $instance = array();
$instance['title'] = sanitize_text_field( $new_instance['title'] );
$instance['search_box_enabled'] = empty( $new_instance['search_box_enabled'] ) ? '0' : '1';
@@ -491,7 +662,7 @@ class Jetpack_Search_Widget extends WP_Widget {
$filters = array();
if ( isset( $new_instance['filter_type'] ) ) {
foreach ( (array) $new_instance['filter_type'] as $index => $type ) {
- $count = intval( $new_instance['num_filters'][ $index ] );
+ $count = (int) $new_instance['num_filters'][ $index ];
$count = min( 50, $count ); // Set max boundary at 50.
$count = max( 1, $count ); // Set min boundary at 1.
@@ -532,18 +703,48 @@ class Jetpack_Search_Widget extends WP_Widget {
}
/**
+ * Reformats the widget instance array to one that is recognized by the `update` function.
+ * This is only necessary when handling changes from the block-based widget editor.
+ *
+ * @param array $widget_instance - Jetpack Search widget instance.
+ *
+ * @return array - Potentially reformatted instance compatible with the save function.
+ */
+ protected function maybe_reformat_widget( $widget_instance ) {
+ if ( isset( $widget_instance['filter_type'] ) || ! isset( $widget_instance['filters'] ) || ! is_array( $widget_instance['filters'] ) ) {
+ return $widget_instance;
+ }
+
+ $instance = $widget_instance;
+ foreach ( $widget_instance['filters'] as $filter ) {
+ $instance['filter_type'][] = isset( $filter['type'] ) ? $filter['type'] : '';
+ $instance['taxonomy_type'][] = isset( $filter['taxonomy'] ) ? $filter['taxonomy'] : '';
+ $instance['filter_name'][] = isset( $filter['name'] ) ? $filter['name'] : '';
+ $instance['num_filters'][] = isset( $filter['count'] ) ? $filter['count'] : 5;
+ $instance['date_histogram_field'][] = isset( $filter['field'] ) ? $filter['field'] : '';
+ $instance['date_histogram_interval'][] = isset( $filter['interval'] ) ? $filter['interval'] : '';
+ }
+ unset( $instance['filters'] );
+ return $instance;
+ }
+
+ /**
* Outputs the settings update form.
*
* @since 5.0.0
*
- * @param array $instance Current settings.
+ * @param array $instance Previously saved values from database.
*/
public function form( $instance ) {
+ if ( Options::is_instant_enabled() ) {
+ return $this->form_for_instant_search( $instance );
+ }
+
$instance = $this->jetpack_search_populate_defaults( $instance );
- $title = strip_tags( $instance['title'] );
+ $title = wp_strip_all_tags( $instance['title'] );
- $hide_filters = Jetpack_Search_Helpers::are_filters_by_widget_disabled();
+ $hide_filters = Helper::are_filters_by_widget_disabled();
$classes = sprintf(
'jetpack-search-filters-widget %s %s %s',
@@ -577,6 +778,7 @@ class Jetpack_Search_Widget extends WP_Widget {
<?php esc_html_e( 'Show search box', 'jetpack' ); ?>
</label>
</p>
+
<p>
<label>
<input
@@ -598,7 +800,7 @@ class Jetpack_Search_Widget extends WP_Widget {
type="checkbox"
value="<?php echo esc_attr( $post_type->name ); ?>"
name="<?php echo esc_attr( $this->get_field_name( 'post_types' ) ); ?>[]"
- <?php checked( empty( $instance['post_types'] ) || in_array( $post_type->name, $instance['post_types'] ) ); ?>
+ <?php checked( empty( $instance['post_types'] ) || in_array( $post_type->name, $instance['post_types'], true ) ); ?>
/>&nbsp;
<?php echo esc_html( $post_type->label ); ?>
</label>
@@ -622,7 +824,9 @@ class Jetpack_Search_Widget extends WP_Widget {
<?php if ( ! $hide_filters ) : ?>
<script class="jetpack-search-filters-widget__filter-template" type="text/template">
- <?php echo $this->render_widget_edit_filter( array(), true ); ?>
+ <?php
+ echo $this->render_widget_edit_filter( array(), true ); // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped
+ ?>
</script>
<div class="jetpack-search-filters-widget__filters">
<?php foreach ( (array) $instance['filters'] as $filter ) : ?>
@@ -641,7 +845,7 @@ class Jetpack_Search_Widget extends WP_Widget {
</noscript>
<?php if ( is_customize_preview() ) : ?>
<p class="jetpack-search-filters-help">
- <a href="https://jetpack.com/support/search/#filters-not-showing-up" target="_blank">
+ <a href="<?php echo esc_url( Redirect::get_url( 'jetpack-support-search', array( 'anchor' => 'filters-not-showing-up' ) ) ); ?>" target="_blank">
<?php esc_html_e( "Why aren't my filters appearing?", 'jetpack' ); ?>
</a>
</p>
@@ -652,6 +856,58 @@ class Jetpack_Search_Widget extends WP_Widget {
}
/**
+ * Outputs the widget update form to be used in the Customizer for Instant Search.
+ *
+ * @since 8.6.0
+ *
+ * @param array $instance Previously saved values from database.
+ */
+ private function form_for_instant_search( $instance ) {
+ $instance = $this->populate_defaults_for_instant_search( $instance );
+ $classes = sprintf( 'jetpack-search-filters-widget %s', $this->id );
+
+ ?>
+ <div class="<?php echo esc_attr( $classes ); ?>">
+ <!-- Title control -->
+ <p>
+ <label for="<?php echo esc_attr( $this->get_field_id( 'title' ) ); ?>">
+ <?php esc_html_e( 'Title (optional):', 'jetpack' ); ?>
+ </label>
+ <input
+ class="widefat"
+ id="<?php echo esc_attr( $this->get_field_id( 'title' ) ); ?>"
+ name="<?php echo esc_attr( $this->get_field_name( 'title' ) ); ?>"
+ type="text"
+ value="<?php echo esc_attr( wp_strip_all_tags( $instance['title'] ) ); ?>"
+ />
+ </p>
+
+ <!-- Filters control -->
+ <?php if ( ! Helper::are_filters_by_widget_disabled() ) : ?>
+ <div class="jetpack-search-filters-widget__filters">
+ <?php foreach ( (array) $instance['filters'] as $filter ) : ?>
+ <?php $this->render_widget_edit_filter( $filter ); ?>
+ <?php endforeach; ?>
+ </div>
+ <p class="jetpack-search-filters-widget__add-filter-wrapper">
+ <a class="button jetpack-search-filters-widget__add-filter" href="#">
+ <?php esc_html_e( 'Add a filter', 'jetpack' ); ?>
+ </a>
+ </p>
+ <script class="jetpack-search-filters-widget__filter-template" type="text/template">
+ <?php $this->render_widget_edit_filter( array(), true ); ?>
+ </script>
+ <noscript>
+ <p class="jetpack-search-filters-help">
+ <?php echo esc_html_e( 'Adding filters requires JavaScript!', 'jetpack' ); ?>
+ </p>
+ </noscript>
+ <?php endif; ?>
+ </div>
+ <?php
+ }
+
+ /**
* We need to render HTML in two formats: an Underscore template (client-side)
* and native PHP (server-side). This helper function allows for easy rendering
* of attributes in both formats.
@@ -663,7 +919,7 @@ class Jetpack_Search_Widget extends WP_Widget {
* @param bool $is_template Whether this is for an Underscore template or not.
*/
private function render_widget_attr( $name, $value, $is_template ) {
- echo $is_template ? "<%= $name %>" : esc_attr( $value );
+ echo $is_template ? "<%= $name %>" : esc_attr( $value ); // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped
}
/**
@@ -680,7 +936,7 @@ class Jetpack_Search_Widget extends WP_Widget {
*/
private function render_widget_option_selected( $name, $value, $compare, $is_template ) {
$compare_js = rawurlencode( $compare );
- echo $is_template ? "<%= decodeURIComponent( '$compare_js' ) === $name ? 'selected=\"selected\"' : '' %>" : selected( $value, $compare );
+ echo $is_template ? "<%= decodeURIComponent( '$compare_js' ) === $name ? 'selected=\"selected\"' : '' %>" : selected( $value, $compare ); // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped
}
/**
@@ -695,7 +951,8 @@ class Jetpack_Search_Widget extends WP_Widget {
*/
public function render_widget_edit_filter( $filter, $is_template = false ) {
$args = wp_parse_args(
- $filter, array(
+ $filter,
+ array(
'name' => '',
'type' => 'taxonomy',
'taxonomy' => '',
@@ -706,7 +963,7 @@ class Jetpack_Search_Widget extends WP_Widget {
)
);
- $args['name_placeholder'] = Jetpack_Search_Helpers::generate_widget_filter_name( $args );
+ $args['name_placeholder'] = Helper::generate_widget_filter_name( $args );
?>
<div class="jetpack-search-filters-widget__filter is-<?php $this->render_widget_attr( 'type', $args['type'], $is_template ); ?>">
@@ -737,7 +994,7 @@ class Jetpack_Search_Widget extends WP_Widget {
<?php foreach ( get_taxonomies( array( 'public' => true ), 'objects' ) as $taxonomy ) : ?>
<option value="<?php echo esc_attr( $taxonomy->name ); ?>" <?php $this->render_widget_option_selected( 'taxonomy', $args['taxonomy'], $taxonomy->name, $is_template ); ?>>
<?php
- $label = in_array( $taxonomy->label, $seen_taxonomy_labels )
+ $label = in_array( $taxonomy->label, $seen_taxonomy_labels, true )
? sprintf(
/* 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. */
_x( '%1$s (%2$s)', 'A label for a taxonomy selector option', 'jetpack' ),
@@ -776,7 +1033,7 @@ class Jetpack_Search_Widget extends WP_Widget {
<p class="jetpack-search-filters-widget__date-histogram-select">
<label>
- <?php esc_html_e( 'Choose an interval:' ); ?>
+ <?php esc_html_e( 'Choose an interval:', 'jetpack' ); ?>
<select name="<?php echo esc_attr( $this->get_field_name( 'date_histogram_interval' ) ); ?>[]" class="widefat date-interval-select">
<option value="month" <?php $this->render_widget_option_selected( 'interval', $args['interval'], 'month', $is_template ); ?>>
<?php esc_html_e( 'Month', 'jetpack' ); ?>
@@ -821,6 +1078,6 @@ class Jetpack_Search_Widget extends WP_Widget {
<a href="#" class="delete"><?php esc_html_e( 'Remove', 'jetpack' ); ?></a>
</p>
</div>
- <?php
+ <?php
}
}