Overview
π Heads up
If you are using Starter Kit, there's no need need to manually create the Sections and Components below.
All the code examples below are just an implementation suggestions. For brevity, the styles are omitted.
For this guide, we will be creating Sections and Components locally. Make sure you have your Local Development Environment ready.
π Remember to commit and push newly created Sections and Components to your remote repository to sync the changes with Shogun Frontend.
Shogun Frontend's solution for Site Search
uses Algolia, a third party AI-powered search and discovery platform. By integrating Algolia within Shogun Frontend's ecosystem, any CMS Content Group is searchable.
This documentation will provide an overview of how to create and integrate Search
into your store.
The outline below illustrates how the data flows from your store to Algolia:
Models: a representation of a CMS Content Group, for example: "products" or "blog." The Fields, such as "name" and "description," are the data of that model that will be used to be searched against when a customer submits their search query. Currently, only text fields can be configured as searchable fields.
Selected fields: data that Algolia will return to the Results page.
π To ensure that Algolia's Site Search is properly configured for your store, it's crucial to have your CMS Content Groups (models and selected fields) provided to Shogun.
The below use case will provide context on how to identify this required information:
π‘ "When my customers searches for 'tire', I want Shogun Frontend's Search to look into my store's products (model) > name (fields) and return a list of matches containing product's name, slug, media and price (selected fields)".
Use as few fields as possible, cause max total size of searchable data per CMS Content Groups is 100 KB.
Adding Search to your store
The client side of the Search
will be divided into two parts:
a text input where the customer will enter their search queries
a results page
1 - Creating SearchQueryInput component
It is most common to have an input for search in the Header
of your application.
To create an input component:
On your local environment, create a new folder inside
src/components
and name it asSearchQueryInput
.Create an
index.js
file inside theSearchQueryInput
folder.Create a styles.module.css file inside the
SearchQueryInput
folder.
The SearchQueryInput
will receive the search query from the customer, and after submission, navigate to the Search
section with the search query set as URL parameter.
// SearchQueryInput component
import * as React from 'react'
import {
Input,
InputGroup,
InputRightElement,
FormControl,
useMultiStyleConfig,
} from '@chakra-ui/react'
import Icon from 'Components/Icon'
import IconButton from 'Components/IconButton'
import { normalizePropValue } from 'Components/Utils'
const SearchQueryInput = React.forwardRef((props, ref) => {
let {
variant,
size,
initialValue = '',
disabled,
placeholder = 'Search',
icon = <Icon icon="SearchIcon" />,
onSearchSubmit,
} = props
size = normalizePropValue(size)
variant = normalizePropValue(variant)
const styles = useMultiStyleConfig('SearchQueryInput', { size, variant })
// Local state to handle the customer's search query
const [query, setQuery] = React.useState(initialValue)
return (
<form
onSubmit={e => {
e.preventDefault()
onSearchSubmit(query)
}}
>
<FormControl>
<InputGroup sx={styles.inputGroup} size={size}>
<Input
sx={styles.input}
ref={ref}
size={size}
aria-label="Search"
name="query"
value={query}
disabled={disabled}
placeholder={placeholder}
required
onChange={e => setQuery(e.target.value)}
/>
<InputRightElement sx={styles.inputRightElement} size={size}>
<IconButton
sx={styles.iconButton}
size="full"
type="submit"
aria-label="Submit search query"
disabled={query.length === 0 || disabled}
icon={icon}
/>
</InputRightElement>
</InputGroup>
</FormControl>
</form>
)
})
export default SearchQueryInput
The SearchQueryInput can now be added into the Header section:
import * as React from 'react'
import SearchQueryInput from 'Components/SearchQueryInput'
import { useRouter } from 'frontend-router'
const Header = () => {
const router = useRouter()
const handleSearchSubmit = React.useCallback(query => router.push(`/search?q=${query}`), [router])
return (
<Grid
as="header"
...
>
<SearchQueryInput onSearchSubmit={handleSearchSubmit} />
</Grid>
)
}
export default Header
2 - The results page
The search section will read the search query a customer has entered into the SearchQueryInput using the useSearch hook from the frontend-ui package and display the search results.
π It's important to note that typo tolerance enabled by default.
2.1 - useSearch
hook
The frontend-ui
package provides access to the useSearch
hook, allowing easy integration of Algolia search into our stores.
The useSearch
hooks accept a parameter to control how many items the result page will include.
useSearch({ hitsPerPage: 10 })
After calling it, useSearch will return an object containing the following keys:
name | type | description |
status | `'PRISTINE' | 'IDLE' |
statuses |
| Constants representing different search states |
errorMessage | `string | null` |
hits |
| Array of matching object IDs |
pagination |
| Current pagination state |
search |
| Callback to trigger search operation. Not passing the |
fetchMore |
| Callback to fetch next page of search results |
2.2 - Creating the Search section
The search section will read the search query a customer has entered into the SearchQueryInput
and display the search results.
Creating the Search Section:
On your local environment, create a new folder inside
src/sections
and name it asSearch
.Create an
index.js
file inside theSearch
folder.Create a styles.module.css file inside the
Search
folder.
// Search section
import * as React from 'react'
import Flex from 'Components/Flex'
import { useRouter } from 'frontend-router'
import { useSearch } from 'frontend-ui'
import ProductGrid from 'Components/ProductGrid'
import SearchQueryInput from 'Components/SearchQueryInput'
import Divider from 'Components/Divider'
import Container from 'Components/Container'
import Button from 'Components/Button'
import Text from 'Components/Text'
const HITS_PER_PAGE = process.env.NODE_ENV === 'development' ? 3 : 10
const Search = () => {
const router = useRouter()
const { q: searchQuery } = router.query
const {
status,
statuses: { ERRORED, LOADING, PRISTINE, FETCHING_MORE },
errorMessage,
hits,
search,
fetchMore,
pagination: { page, totalPages },
} = useSearch({
hitsPerPage: HITS_PER_PAGE,
})
React.useEffect(() => {
if (!searchQuery) return
search(searchQuery)
// eslint-disable-next-line react-hooks/exhaustive-deps
}, [searchQuery])
return (
<Container p={{ base: 2, md: 8 }}>
<Flex align="center" justify="center" my={10}>
<Container flexBasis={{ base: '90vw', md: 'md' }}>
<SearchQueryInput
initialValue={searchQuery}
disabled={status === LOADING || status === FETCHING_MORE}
onSearchSubmit={q => router.push(`/search?q=${q}`)}
/>
</Container>
</Flex>
<Divider />
<Container my={10}>
{hits.length === 0 && status === PRISTINE && <Text>Start searching to see results</Text>}
{hits.length === 0 && status !== PRISTINE && status !== LOADING && (
<Text>No results found for {searchQuery}</Text>
)}
{hits.length === 0 && status === LOADING && <Text>Loading</Text>}
{status === ERRORED && <Text>Error {errorMessage}</Text>}
{hits.length > 0 && (
<React.Fragment>
<ProductGrid
collection={{
name: 'Search results',
slug: 'search-results',
descriptionHtml: '',
products: hits,
}}
/>
{totalPages > page + 1 && (
<Container textAlign="center" my={10}>
<Button onClick={() => fetchMore()}>
{status === FETCHING_MORE ? '...' : 'Load more'}
</Button>
</Container>
)}
</React.Fragment>
)}
</Container>
</Container>
)
}
export default Search
This Section wonβt receive any props, so variables are not created.
2.3 - Search page
A new page must be created to display the search results.
To create a page:
Click on the
Pages
icon from the sidebar.Click
ADD PAGE
on the top right corner.Enter the PAGE NAME, "Search".
Click
SAVE PAGE
.
Next, add the Search section:
Navigate to the
Experience Manager (XM)
by clicking thePages
icon on the sidebar.Search for "Search".
Open the "Search" by clicking the title.
On the sidebar, click on the + (plus sign) where it says "Add sections to start building your page".
Search for and select
Search
from the list of allSections
shown.Ensure the page is marked
Ready to Publish
Your customers will now be able to search for any item in your store.