From 29a00bc12ef3ead4d156394ea88801e716a1da5d Mon Sep 17 00:00:00 2001 From: Jason Moon Date: Fri, 23 Aug 2019 15:10:57 -0600 Subject: [PATCH 01/13] Polish styling for search results --- .../instant-search/components/search-result.jsx | 12 ++++++------ .../instant-search/components/search-result.scss | 11 ++++++++++- .../instant-search/components/search-results.scss | 3 +++ modules/search/instant-search/instant-search.scss | 1 + 4 files changed, 20 insertions(+), 7 deletions(-) create mode 100644 modules/search/instant-search/components/search-results.scss diff --git a/modules/search/instant-search/components/search-result.jsx b/modules/search/instant-search/components/search-result.jsx index 26df807f00ce9..5c35152b18037 100644 --- a/modules/search/instant-search/components/search-result.jsx +++ b/modules/search/instant-search/components/search-result.jsx @@ -13,8 +13,6 @@ class SearchResult extends Component {
{ strip( this.props.result.fields.title_html ) || 'Unknown Title' } @@ -25,10 +23,12 @@ class SearchResult extends Component { { strip( this.props.result.fields.date ).split( ' ' )[ 0 ] }
-
- { strip( this.props.result.fields.excerpt_html ) } -
-
+ { this.props.result.fields.excerpt_html && ( +
+ { strip( this.props.result.fields.excerpt_html ) } +
+ ) } +
{ sprintf( _n( '%d comment', '%d comments', this.props.result.fields.comment_count, 'jetpack' ), this.props.result.fields.comment_count diff --git a/modules/search/instant-search/components/search-result.scss b/modules/search/instant-search/components/search-result.scss index 5bb1b9926d472..79d5d754765f4 100644 --- a/modules/search/instant-search/components/search-result.scss +++ b/modules/search/instant-search/components/search-result.scss @@ -3,6 +3,11 @@ .jetpack-instant-search__result { padding: 0.125em 0; margin: 1em 0; + + &:first-child { + margin-top: 0; + } + a { box-shadow: inset 0 0 0 rgba( black, 0 ), 0 1px 0 rgba( black, 1 ); transition: color 80ms ease-in, box-shadow 130ms ease-in-out; @@ -14,7 +19,7 @@ } .jetpack-instant-search__result-author-and-date { - margin: 0.5em 0; + margin: 0.25em 0; display: flex; justify-content: space-between; } @@ -26,3 +31,7 @@ .jetpack-instant-search__result-excerpt { color: $gray; } + +.jetpack-instant-search__comment-count { + margin-top: 0.25em; +} diff --git a/modules/search/instant-search/components/search-results.scss b/modules/search/instant-search/components/search-results.scss new file mode 100644 index 0000000000000..2b0a7c0f10c4c --- /dev/null +++ b/modules/search/instant-search/components/search-results.scss @@ -0,0 +1,3 @@ +.jetpack-instant-search__search-results > p { + margin-bottom: 1em; +} diff --git a/modules/search/instant-search/instant-search.scss b/modules/search/instant-search/instant-search.scss index c42b08a53d8a0..06fda0d469113 100644 --- a/modules/search/instant-search/instant-search.scss +++ b/modules/search/instant-search/instant-search.scss @@ -1 +1,2 @@ +@import './components/search-results.scss'; @import './components/search-result.scss'; From cc766bf47960a140edaabfd63e444efc3593700c Mon Sep 17 00:00:00 2001 From: Jason Moon Date: Fri, 23 Aug 2019 15:13:44 -0600 Subject: [PATCH 02/13] Send aggregation information in API request --- modules/search/class.jetpack-search.php | 21 ++++++-- .../search/instant-search/components/api.js | 52 ++++++++++++++++--- .../components/search-widget.jsx | 2 +- modules/search/instant-search/index.jsx | 22 +++++--- package.json | 1 + yarn.lock | 5 ++ 6 files changed, 82 insertions(+), 21 deletions(-) diff --git a/modules/search/class.jetpack-search.php b/modules/search/class.jetpack-search.php index dc87b16a53996..6f8d38c09bc52 100644 --- a/modules/search/class.jetpack-search.php +++ b/modules/search/class.jetpack-search.php @@ -204,10 +204,23 @@ public function load_assets() { $script_version = self::get_asset_version( $script_relative_path ); $script_path = plugins_url( $script_relative_path, JETPACK__PLUGIN_FILE ); wp_enqueue_script( 'jetpack-instant-search', $script_path, array(), $script_version, true ); - $_blog_id = Jetpack::get_option( 'id' ); + + $filters = Jetpack_Search_Helpers::get_filters_from_widgets(); + $widgets = array(); + foreach( $filters as $key => $filter ) { + if ( ! isset( $widgets[$filter[ 'widget_id' ]] ) ) { + $widgets[$filter[ 'widget_id' ]][ 'filters' ] = array(); + $widgets[$filter[ 'widget_id' ]][ 'widget_id' ] = $filter[ 'widget_id' ]; + } + $new_filter = $filter; + $new_filter[ 'filter_id' ] = $key; + $widgets[$filter[ 'widget_id' ]][ 'filters' ][] = $new_filter; + } + // This is probably a temporary filter for testing the prototype. $options = array( - 'siteId' => $_blog_id, + 'siteId' => Jetpack::get_option( 'id' ), + 'widgets' => array_values( $widgets ), ); /** * Customize Instant Search Options. @@ -221,9 +234,7 @@ public function load_assets() { $options = apply_filters( 'jetpack_instant_search_options', $options ); wp_localize_script( - 'jetpack-instant-search', - 'jetpack_instant_search_options', - $options + 'jetpack-instant-search', 'JetpackInstantSearchOptions', $options ); } diff --git a/modules/search/instant-search/components/api.js b/modules/search/instant-search/components/api.js index 0cbbbcd5cefb1..3d1ad9522c710 100644 --- a/modules/search/instant-search/components/api.js +++ b/modules/search/instant-search/components/api.js @@ -2,6 +2,8 @@ * External dependencies */ import fetch from 'unfetch'; +import { encode } from 'qss'; +import { flatten } from 'q-flat'; const FIELDS = [ 'author', @@ -13,16 +15,50 @@ const FIELDS = [ 'title_html', ]; -function stringifyArray( fieldName, array ) { - return array.map( ( element, index ) => `${ fieldName }[${ index }]=${ element }` ).join( '&' ); +export function buildFilterAggregations( widgets = [] ) { + const aggregation = {}; + widgets.forEach( ( { filters: widgetFilters } ) => + widgetFilters.forEach( filter => { + switch ( filter.type ) { + case 'date_histogram': { + const field = filter.field === 'post_date_gmt' ? 'date_gmt' : 'date'; + aggregation[ filter.filter_id ] = { + date_histogram: { field, interval: filter.interval }, + }; + break; + } + case 'taxonomy': { + let field = `taxonomy.${ filter.taxonomy }.slug`; + if ( filter.taxonomy === 'post_tag' ) { + field = 'tag.slug'; + } else if ( filter.type === 'category' ) { + field = 'category.slug'; + } + aggregation[ filter.filter_id ] = { terms: { field, size: filter.count } }; + break; + } + case 'post_type': { + aggregation[ filter.filter_id ] = { terms: { field: filter.type, size: filter.count } }; + break; + } + } + } ) + ); + return aggregation; } -function getAPIUrl( siteId, query ) { - return `https://public-api.wordpress.com/rest/v1.3/sites/${ siteId }/search?query=${ encodeURIComponent( - query - ) }&${ stringifyArray( 'fields', FIELDS ) }`; +function getAPIUrl( siteId, query, widgets ) { + const queryString = encode( + flatten( { + aggregations: buildFilterAggregations( widgets ), + fields: FIELDS, + query: encodeURIComponent( query ), + } ) + ); + + return `https://public-api.wordpress.com/rest/v1.3/sites/${ siteId }/search?${ queryString }`; } -export function search( siteId, query ) { - return fetch( getAPIUrl( siteId, query ) ); +export function search( siteId, query, widgets ) { + return fetch( getAPIUrl( siteId, query, widgets ) ); } diff --git a/modules/search/instant-search/components/search-widget.jsx b/modules/search/instant-search/components/search-widget.jsx index 07f6140e9d43d..7f50fad8bb808 100644 --- a/modules/search/instant-search/components/search-widget.jsx +++ b/modules/search/instant-search/components/search-widget.jsx @@ -47,7 +47,7 @@ class SearchApp extends Component { this.requestId++; const requestId = this.requestId; - search( this.props.siteId, query ) + search( this.props.siteId, query, this.props.widgets ) .then( response => response.json() ) .then( json => { if ( this.requestId === requestId ) { diff --git a/modules/search/instant-search/index.jsx b/modules/search/instant-search/index.jsx index 65b8274f3be66..913788da03b52 100644 --- a/modules/search/instant-search/index.jsx +++ b/modules/search/instant-search/index.jsx @@ -24,24 +24,32 @@ const hideSearchHeader = () => { } }; -const injectSearchWidget = ( initialValue, target, siteId, grabFocus ) => { +const injectSearchWidget = ( initialValue, target, grabFocus ) => { render( - , + , target ); }; document.addEventListener( 'DOMContentLoaded', function() { - //This var is provided by wp_localize_script() so we have limited control - const options = jetpack_instant_search_options; // eslint-disable-line no-undef - - if ( 'siteId' in options && document.body && document.body.classList.contains( 'search' ) ) { + if ( + !! window.JetpackInstantSearchOptions && + 'siteId' in window.JetpackInstantSearchOptions && + 'widgets' in window.JetpackInstantSearchOptions && + document.body && + document.body.classList.contains( 'search' ) + ) { const widget = document.querySelector( '.widget_search' ); if ( !! widget ) { removeChildren( widget ); removeChildren( document.querySelector( 'main' ) ); hideSearchHeader(); - injectSearchWidget( getSearchQuery(), widget, options.siteId ); + injectSearchWidget( getSearchQuery(), widget ); } } } ); diff --git a/package.json b/package.json index 13af00d7bdd7f..425d035c7bff0 100644 --- a/package.json +++ b/package.json @@ -132,6 +132,7 @@ "preact": "8.4.2", "preact-portal": "1.1.3", "prop-types": "15.7.2", + "q-flat": "1.0.7", "qss": "2.0.3", "react-pure-render": "1.0.2", "react-redux": "6.0.1", diff --git a/yarn.lock b/yarn.lock index d216954e4d461..90414caa745fe 100644 --- a/yarn.lock +++ b/yarn.lock @@ -10307,6 +10307,11 @@ puppeteer@1.19.0: rimraf "^2.6.1" ws "^6.1.0" +q-flat@1.0.7: + version "1.0.7" + resolved "https://registry.yarnpkg.com/q-flat/-/q-flat-1.0.7.tgz#4cf81aede99d2a9acbafcf503af0d0184a850d3d" + integrity sha512-Ug+B6yajVE5HF7eAszOvAcYmQ+DbYaDcQlxYuW9RaAqwZTRZQq+lHMGqHlnaxKP7CfuGCpXQXOb4qymRYMkYEQ== + q@^1.1.2: version "1.5.1" resolved "https://registry.yarnpkg.com/q/-/q-1.5.1.tgz#7e32f75b41381291d04611f1bf14109ac00651d7" From 103768c7458575fa86b64e9e596fd20f978d75f1 Mon Sep 17 00:00:00 2001 From: Jason Moon Date: Fri, 23 Aug 2019 17:08:32 -0600 Subject: [PATCH 03/13] Move API utility into lib folder --- modules/search/instant-search/{components => lib}/api.js | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) rename modules/search/instant-search/{components => lib}/api.js (87%) diff --git a/modules/search/instant-search/components/api.js b/modules/search/instant-search/lib/api.js similarity index 87% rename from modules/search/instant-search/components/api.js rename to modules/search/instant-search/lib/api.js index 3d1ad9522c710..e2d58ee44ca8b 100644 --- a/modules/search/instant-search/components/api.js +++ b/modules/search/instant-search/lib/api.js @@ -47,10 +47,10 @@ export function buildFilterAggregations( widgets = [] ) { return aggregation; } -function getAPIUrl( siteId, query, widgets ) { +function getAPIUrl( siteId, query, aggregations ) { const queryString = encode( flatten( { - aggregations: buildFilterAggregations( widgets ), + aggregations, fields: FIELDS, query: encodeURIComponent( query ), } ) @@ -59,6 +59,6 @@ function getAPIUrl( siteId, query, widgets ) { return `https://public-api.wordpress.com/rest/v1.3/sites/${ siteId }/search?${ queryString }`; } -export function search( siteId, query, widgets ) { - return fetch( getAPIUrl( siteId, query, widgets ) ); +export function search( siteId, query, aggregations ) { + return fetch( getAPIUrl( siteId, query, aggregations ) ); } From ee461ff665f1ce2cd9531784f32086e413be7754 Mon Sep 17 00:00:00 2001 From: Jason Moon Date: Fri, 23 Aug 2019 17:09:02 -0600 Subject: [PATCH 04/13] Refactor DOM utility into a lib file --- modules/search/instant-search/index.jsx | 7 +------ modules/search/instant-search/lib/dom.js | 5 +++++ 2 files changed, 6 insertions(+), 6 deletions(-) create mode 100644 modules/search/instant-search/lib/dom.js diff --git a/modules/search/instant-search/index.jsx b/modules/search/instant-search/index.jsx index 913788da03b52..14d60f4062cc5 100644 --- a/modules/search/instant-search/index.jsx +++ b/modules/search/instant-search/index.jsx @@ -9,14 +9,9 @@ import { h, render } from 'preact'; * Internal dependencies */ import SearchWidget from './components/search-widget'; +import { removeChildren } from './lib/dom'; import { getSearchQuery } from './lib/query-string'; -function removeChildren( htmlElement ) { - while ( htmlElement.lastChild ) { - htmlElement.removeChild( htmlElement.lastChild ); - } -} - const hideSearchHeader = () => { const titleElements = document.getElementById( 'content' ).getElementsByClassName( 'page-title' ); if ( titleElements.length > 0 ) { diff --git a/modules/search/instant-search/lib/dom.js b/modules/search/instant-search/lib/dom.js new file mode 100644 index 0000000000000..a55fe918d7422 --- /dev/null +++ b/modules/search/instant-search/lib/dom.js @@ -0,0 +1,5 @@ +export function removeChildren( htmlElement ) { + while ( htmlElement.lastChild ) { + htmlElement.removeChild( htmlElement.lastChild ); + } +} From a6860d4c75bc6a66421a2209717f1721a1ef0718 Mon Sep 17 00:00:00 2001 From: Jason Moon Date: Fri, 23 Aug 2019 17:10:53 -0600 Subject: [PATCH 05/13] Render disabled filter widgets --- .../components/search-filter-dates.jsx | 42 ++++++++++++++++++ .../components/search-filter-post-types.jsx | 37 ++++++++++++++++ .../components/search-filter-taxonomies.jsx | 37 ++++++++++++++++ .../components/search-filters-widget.jsx | 43 +++++++++++++++++++ .../components/search-filters-widget.scss | 5 +++ .../components/search-widget.jsx | 26 ++++++++--- modules/search/instant-search/index.jsx | 4 +- .../search/instant-search/instant-search.scss | 1 + 8 files changed, 188 insertions(+), 7 deletions(-) create mode 100644 modules/search/instant-search/components/search-filter-dates.jsx create mode 100644 modules/search/instant-search/components/search-filter-post-types.jsx create mode 100644 modules/search/instant-search/components/search-filter-taxonomies.jsx create mode 100644 modules/search/instant-search/components/search-filters-widget.jsx create mode 100644 modules/search/instant-search/components/search-filters-widget.scss diff --git a/modules/search/instant-search/components/search-filter-dates.jsx b/modules/search/instant-search/components/search-filter-dates.jsx new file mode 100644 index 0000000000000..7ea7d5363dfc9 --- /dev/null +++ b/modules/search/instant-search/components/search-filter-dates.jsx @@ -0,0 +1,42 @@ +/** @jsx h */ + +/** + * External dependencies + */ +import { h, Component } from 'preact'; +import strip from 'strip'; + +export default class SearchFilterDates extends Component { + render() { + return ( +
+

{ this.props.filter.name }

+
    + { this.props.aggregation && + 'buckets' in this.props.aggregation && + [ + ...this.props.aggregation.buckets + // TODO: Remove this filter; API should only be sending buckets with document counts. + .filter( bucket => !! bucket && bucket.doc_count > 0 ) + .map( bucket => ( +
    + + +
    + ) ), + ] + // TODO: Remove this reverse & slice when API adds filter count support + .reverse() + .slice( 0, 5 ) } +
+
+ ); + } +} diff --git a/modules/search/instant-search/components/search-filter-post-types.jsx b/modules/search/instant-search/components/search-filter-post-types.jsx new file mode 100644 index 0000000000000..9f9738d241393 --- /dev/null +++ b/modules/search/instant-search/components/search-filter-post-types.jsx @@ -0,0 +1,37 @@ +/** @jsx h */ + +/** + * External dependencies + */ +import { h, Component } from 'preact'; +import strip from 'strip'; + +export default class SearchFilterPostTypes extends Component { + render() { + return ( +
+

{ this.props.filter.name }

+
    + { this.props.aggregation && + 'buckets' in this.props.aggregation && + this.props.aggregation.buckets + // TODO: Remove this filter; API should only be sending buckets with document counts. + .filter( bucket => !! bucket && bucket.doc_count > 0 ) + .map( bucket => ( +
    + + +
    + ) ) } +
+
+ ); + } +} diff --git a/modules/search/instant-search/components/search-filter-taxonomies.jsx b/modules/search/instant-search/components/search-filter-taxonomies.jsx new file mode 100644 index 0000000000000..4b185d66fc26e --- /dev/null +++ b/modules/search/instant-search/components/search-filter-taxonomies.jsx @@ -0,0 +1,37 @@ +/** @jsx h */ + +/** + * External dependencies + */ +import { h, Component } from 'preact'; +import strip from 'strip'; + +export default class SearchFilterTaxonomies extends Component { + render() { + return ( +
+

{ this.props.filter.name }

+
    + { this.props.aggregation && + 'buckets' in this.props.aggregation && + this.props.aggregation.buckets + // TODO: Remove this filter; API should only be sending buckets with document counts. + .filter( bucket => !! bucket && bucket.doc_count > 0 ) + .map( bucket => ( +
    + + +
    + ) ) } +
+
+ ); + } +} diff --git a/modules/search/instant-search/components/search-filters-widget.jsx b/modules/search/instant-search/components/search-filters-widget.jsx new file mode 100644 index 0000000000000..83ff91d26c2cd --- /dev/null +++ b/modules/search/instant-search/components/search-filters-widget.jsx @@ -0,0 +1,43 @@ +/** @jsx h */ + +/** + * External dependencies + */ +import { h, Component } from 'preact'; +// NOTE: We only import the debounce package here for to reduced bundle size. +// Do not import the entire lodash library! +// eslint-disable-next-line lodash/import-scope +import get from 'lodash/get'; + +/** + * Internal dependencies + */ +import SearchFilterDates from './search-filter-dates'; +import SearchFilterTaxonomies from './search-filter-taxonomies'; +import SearchFilterPostTypes from './search-filter-post-types'; + +export default class SearchFiltersWidget extends Component { + renderFilterComponent( aggregations ) { + return filter => { + const results = aggregations ? aggregations[ filter.filter_id ] : null; + switch ( filter.type ) { + case 'date_histogram': + return ; + case 'taxonomy': + return ; + case 'post_type': + return ; + } + }; + } + + render() { + return ( +
+ { get( this.props.widget, 'filters' ).map( + this.renderFilterComponent( get( this.props.results, 'aggregations' ) ) + ) } +
+ ); + } +} diff --git a/modules/search/instant-search/components/search-filters-widget.scss b/modules/search/instant-search/components/search-filters-widget.scss new file mode 100644 index 0000000000000..d836499e7453a --- /dev/null +++ b/modules/search/instant-search/components/search-filters-widget.scss @@ -0,0 +1,5 @@ +.jetpack-search-filters-widget__filter-list { + label { + display: inline-block; + } +} diff --git a/modules/search/instant-search/components/search-widget.jsx b/modules/search/instant-search/components/search-widget.jsx index 7f50fad8bb808..c850a3d1a4d44 100644 --- a/modules/search/instant-search/components/search-widget.jsx +++ b/modules/search/instant-search/components/search-widget.jsx @@ -14,8 +14,10 @@ import debounce from 'lodash/debounce'; * Internal dependencies */ import SearchResults from './search-results'; -import { search } from './api'; +import SearchFiltersWidget from './search-filters-widget'; +import { search } from '../lib/api'; import { setSearchQuery } from '../lib/query-string'; +import { removeChildren } from '../lib/dom'; class SearchApp extends Component { constructor() { @@ -23,15 +25,20 @@ class SearchApp extends Component { this.requestId = 0; this.state = { query: this.props.initialValue, - results: [], + results: {}, }; this.getResults = debounce( this.getResults, 500 ); this.getResults( this.props.initialValue ); } + componentDidMount() { if ( this.props.grabFocus ) { this.input.focus(); } + + this.props.widgets.forEach( function( widget ) { + removeChildren( document.getElementById( widget.widget_id ) ); + } ); } bindInput = input => ( this.input = input ); @@ -47,7 +54,7 @@ class SearchApp extends Component { this.requestId++; const requestId = this.requestId; - search( this.props.siteId, query, this.props.widgets ) + search( this.props.siteId, query, this.props.aggregations ) .then( response => response.json() ) .then( json => { if ( this.requestId === requestId ) { @@ -62,15 +69,22 @@ class SearchApp extends Component { render() { const { query, results } = this.state; return ( -
-

+

); diff --git a/modules/search/instant-search/components/search-filter-taxonomies.jsx b/modules/search/instant-search/components/search-filter-taxonomies.jsx index 4b185d66fc26e..fbd93a7fcfdba 100644 --- a/modules/search/instant-search/components/search-filter-taxonomies.jsx +++ b/modules/search/instant-search/components/search-filter-taxonomies.jsx @@ -14,22 +14,19 @@ export default class SearchFilterTaxonomies extends Component {
    { this.props.aggregation && 'buckets' in this.props.aggregation && - this.props.aggregation.buckets - // TODO: Remove this filter; API should only be sending buckets with document counts. - .filter( bucket => !! bucket && bucket.doc_count > 0 ) - .map( bucket => ( -
    - - -
    - ) ) } + this.props.aggregation.buckets.map( bucket => ( +
    + + +
    + ) ) }
); From 5e1f56267ce95dbff0a0397c51d02c59fc1daa16 Mon Sep 17 00:00:00 2001 From: Jason Moon Date: Wed, 28 Aug 2019 14:20:16 -0600 Subject: [PATCH 08/13] Omit filter control if no aggregation value --- .../instant-search/components/search-filters-widget.jsx | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/modules/search/instant-search/components/search-filters-widget.jsx b/modules/search/instant-search/components/search-filters-widget.jsx index 83ff91d26c2cd..33c2d63cafc8e 100644 --- a/modules/search/instant-search/components/search-filters-widget.jsx +++ b/modules/search/instant-search/components/search-filters-widget.jsx @@ -22,11 +22,11 @@ export default class SearchFiltersWidget extends Component { const results = aggregations ? aggregations[ filter.filter_id ] : null; switch ( filter.type ) { case 'date_histogram': - return ; + return results && ; case 'taxonomy': - return ; + return results && ; case 'post_type': - return ; + return results && ; } }; } From a5d8d6009aba7a6ff1964e0be419cbd333c925f3 Mon Sep 17 00:00:00 2001 From: Jason Moon Date: Wed, 28 Aug 2019 14:21:04 -0600 Subject: [PATCH 09/13] Filter on key_as_string for date filter --- .../search/instant-search/components/search-filter-dates.jsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/modules/search/instant-search/components/search-filter-dates.jsx b/modules/search/instant-search/components/search-filter-dates.jsx index 7ea7d5363dfc9..2d8e3340fcaba 100644 --- a/modules/search/instant-search/components/search-filter-dates.jsx +++ b/modules/search/instant-search/components/search-filter-dates.jsx @@ -23,7 +23,7 @@ export default class SearchFilterDates extends Component {
{ strip( this.props.result.fields.title_html ) || 'Unknown Title' } @@ -23,12 +25,10 @@ class SearchResult extends Component { { strip( this.props.result.fields.date ).split( ' ' )[ 0 ] }
- { this.props.result.fields.excerpt_html && ( -
- { strip( this.props.result.fields.excerpt_html ) } -
- ) } -
+
+ { strip( this.props.result.fields.excerpt_html ) } +
+
{ sprintf( _n( '%d comment', '%d comments', this.props.result.fields.comment_count, 'jetpack' ), this.props.result.fields.comment_count diff --git a/modules/search/instant-search/components/search-result.scss b/modules/search/instant-search/components/search-result.scss index 79d5d754765f4..5bb1b9926d472 100644 --- a/modules/search/instant-search/components/search-result.scss +++ b/modules/search/instant-search/components/search-result.scss @@ -3,11 +3,6 @@ .jetpack-instant-search__result { padding: 0.125em 0; margin: 1em 0; - - &:first-child { - margin-top: 0; - } - a { box-shadow: inset 0 0 0 rgba( black, 0 ), 0 1px 0 rgba( black, 1 ); transition: color 80ms ease-in, box-shadow 130ms ease-in-out; @@ -19,7 +14,7 @@ } .jetpack-instant-search__result-author-and-date { - margin: 0.25em 0; + margin: 0.5em 0; display: flex; justify-content: space-between; } @@ -31,7 +26,3 @@ .jetpack-instant-search__result-excerpt { color: $gray; } - -.jetpack-instant-search__comment-count { - margin-top: 0.25em; -} From 2c6eec08ef073098f8f422510a924f37f3ede8f3 Mon Sep 17 00:00:00 2001 From: Jason Moon Date: Wed, 28 Aug 2019 16:04:41 -0600 Subject: [PATCH 11/13] Map registered post types for rendering --- modules/search/class.jetpack-search.php | 5 ++- .../components/search-filter-post-types.jsx | 30 +++++++------ .../components/search-filters-widget.jsx | 45 ++++++++++++------- .../components/search-widget.jsx | 6 ++- modules/search/instant-search/index.jsx | 2 + 5 files changed, 56 insertions(+), 32 deletions(-) diff --git a/modules/search/class.jetpack-search.php b/modules/search/class.jetpack-search.php index 6f8d38c09bc52..396bd4a62d32d 100644 --- a/modules/search/class.jetpack-search.php +++ b/modules/search/class.jetpack-search.php @@ -219,8 +219,9 @@ public function load_assets() { // This is probably a temporary filter for testing the prototype. $options = array( - 'siteId' => Jetpack::get_option( 'id' ), - 'widgets' => array_values( $widgets ), + 'postTypes' => get_post_types(), + 'siteId' => Jetpack::get_option( 'id' ), + 'widgets' => array_values( $widgets ), ); /** * Customize Instant Search Options. diff --git a/modules/search/instant-search/components/search-filter-post-types.jsx b/modules/search/instant-search/components/search-filter-post-types.jsx index 4370d856c4a6f..3ff2751426221 100644 --- a/modules/search/instant-search/components/search-filter-post-types.jsx +++ b/modules/search/instant-search/components/search-filter-post-types.jsx @@ -7,6 +7,22 @@ import { h, Component } from 'preact'; import strip from 'strip'; export default class SearchFilterPostTypes extends Component { + renderPostType = ( { key, doc_count: count } ) => { + const name = this.props.postTypes[ key ]; + return ( +
+ + +
+ ); + }; render() { return (
@@ -14,19 +30,7 @@ export default class SearchFilterPostTypes extends Component {
    { this.props.aggregation && 'buckets' in this.props.aggregation && - this.props.aggregation.buckets.map( bucket => ( -
    - - -
    - ) ) } + this.props.aggregation.buckets.map( this.renderPostType ) }
); diff --git a/modules/search/instant-search/components/search-filters-widget.jsx b/modules/search/instant-search/components/search-filters-widget.jsx index 33c2d63cafc8e..e14e10fc2ce28 100644 --- a/modules/search/instant-search/components/search-filters-widget.jsx +++ b/modules/search/instant-search/components/search-filters-widget.jsx @@ -17,26 +17,39 @@ import SearchFilterTaxonomies from './search-filter-taxonomies'; import SearchFilterPostTypes from './search-filter-post-types'; export default class SearchFiltersWidget extends Component { - renderFilterComponent( aggregations ) { - return filter => { - const results = aggregations ? aggregations[ filter.filter_id ] : null; - switch ( filter.type ) { - case 'date_histogram': - return results && ; - case 'taxonomy': - return results && ; - case 'post_type': - return results && ; - } - }; - } + renderFilterComponent = ( { filter, results } ) => { + switch ( filter.type ) { + case 'date_histogram': + return results && ; + case 'taxonomy': + return results && ; + case 'post_type': + return ( + results && ( + + ) + ); + } + }; render() { + const aggregations = get( this.props.results, 'aggregations' ); return (
- { get( this.props.widget, 'filters' ).map( - this.renderFilterComponent( get( this.props.results, 'aggregations' ) ) - ) } + { get( this.props.widget, 'filters' ) + .map( filter => + aggregations ? { filter, results: aggregations[ filter.filter_id ] } : null + ) + .filter( data => !! data ) + .filter( + ( { results } ) => + !! results && Array.isArray( results.buckets ) && results.buckets.length > 0 + ) + .map( this.renderFilterComponent ) }
); } diff --git a/modules/search/instant-search/components/search-widget.jsx b/modules/search/instant-search/components/search-widget.jsx index c850a3d1a4d44..af18760274d08 100644 --- a/modules/search/instant-search/components/search-widget.jsx +++ b/modules/search/instant-search/components/search-widget.jsx @@ -81,7 +81,11 @@ class SearchApp extends Component { { this.props.widgets.map( widget => ( - + ) ) } diff --git a/modules/search/instant-search/index.jsx b/modules/search/instant-search/index.jsx index e900c419d5907..3b63f6eccb986 100644 --- a/modules/search/instant-search/index.jsx +++ b/modules/search/instant-search/index.jsx @@ -26,6 +26,7 @@ const injectSearchWidget = ( initialValue, target, grabFocus ) => { aggregations={ buildFilterAggregations( window.JetpackInstantSearchOptions.widgets ) } grabFocus={ grabFocus } initialValue={ initialValue } + postTypes={ window.JetpackInstantSearchOptions.postTypes } siteId={ window.JetpackInstantSearchOptions.siteId } widgets={ window.JetpackInstantSearchOptions.widgets } />, @@ -36,6 +37,7 @@ const injectSearchWidget = ( initialValue, target, grabFocus ) => { document.addEventListener( 'DOMContentLoaded', function() { if ( !! window.JetpackInstantSearchOptions && + 'postTypes' in window.JetpackInstantSearchOptions && 'siteId' in window.JetpackInstantSearchOptions && 'widgets' in window.JetpackInstantSearchOptions && document.body && From 3b9cb078f8cbb1a5133dc012d12a5ba6816750e3 Mon Sep 17 00:00:00 2001 From: Jason Moon Date: Wed, 28 Aug 2019 16:46:37 -0600 Subject: [PATCH 12/13] Simplify injection by using Portals-only component --- .../components/search-filters-widget.jsx | 2 +- .../components/search-widget.jsx | 54 +++++++++++-------- modules/search/instant-search/index.jsx | 23 ++------ modules/search/instant-search/lib/dom.js | 7 +++ 4 files changed, 45 insertions(+), 41 deletions(-) diff --git a/modules/search/instant-search/components/search-filters-widget.jsx b/modules/search/instant-search/components/search-filters-widget.jsx index e14e10fc2ce28..efbefd835cb9a 100644 --- a/modules/search/instant-search/components/search-filters-widget.jsx +++ b/modules/search/instant-search/components/search-filters-widget.jsx @@ -39,7 +39,7 @@ export default class SearchFiltersWidget extends Component { render() { const aggregations = get( this.props.results, 'aggregations' ); return ( -
+
{ get( this.props.widget, 'filters' ) .map( filter => aggregations ? { filter, results: aggregations[ filter.filter_id ] } : null diff --git a/modules/search/instant-search/components/search-widget.jsx b/modules/search/instant-search/components/search-widget.jsx index af18760274d08..656af2aaa51b6 100644 --- a/modules/search/instant-search/components/search-widget.jsx +++ b/modules/search/instant-search/components/search-widget.jsx @@ -3,7 +3,7 @@ /** * External dependencies */ -import { h, Component } from 'preact'; +import Preact, { h, Component } from 'preact'; import Portal from 'preact-portal'; // NOTE: We only import the debounce package here for to reduced bundle size. // Do not import the entire lodash library! @@ -17,11 +17,12 @@ import SearchResults from './search-results'; import SearchFiltersWidget from './search-filters-widget'; import { search } from '../lib/api'; import { setSearchQuery } from '../lib/query-string'; -import { removeChildren } from '../lib/dom'; +import { removeChildren, hideSearchHeader } from '../lib/dom'; class SearchApp extends Component { constructor() { super( ...arguments ); + this.input = Preact.createRef(); this.requestId = 0; this.state = { query: this.props.initialValue, @@ -33,15 +34,16 @@ class SearchApp extends Component { componentDidMount() { if ( this.props.grabFocus ) { - this.input.focus(); + this.input.current.focus(); } + hideSearchHeader(); + removeChildren( document.querySelector( 'main' ) ); this.props.widgets.forEach( function( widget ) { removeChildren( document.getElementById( widget.widget_id ) ); } ); } - bindInput = input => ( this.input = input ); onChangeQuery = event => { const query = event.target.value; this.setState( { query } ); @@ -69,30 +71,40 @@ class SearchApp extends Component { render() { const { query, results } = this.state; return ( -