diff --git a/src/containers/SearchPage/SearchPage.helpers.js b/src/containers/SearchPage/SearchPage.helpers.js index 6009d20b..e0514233 100644 --- a/src/containers/SearchPage/SearchPage.helpers.js +++ b/src/containers/SearchPage/SearchPage.helpers.js @@ -1,5 +1,8 @@ import { intersection } from 'lodash'; import config from '../../config'; +import { createResourceLocatorString } from '../../util/routes'; +import { createSlug } from '../../util/urlHelpers'; +import routeConfiguration from '../../routeConfiguration'; // customURLParams export const validURLParamForExtendedData = (paramKey, urlParams, customConfigKeys) => { @@ -48,3 +51,48 @@ export const pickSearchParamsOnly = (params, customURLParams, customURLParamToCo ...customSearchParams, }; }; + +export const createSearchResultSchema = (listings, address, intl) => { + // Schema for search engines (helps them to understand what this page is about) + // http://schema.org + // We are using JSON-LD format + const siteTitle = config.siteTitle; + const searchAddress = address || intl.formatMessage({ id: 'SearchPage.schemaMapSearch' }); + const schemaDescription = intl.formatMessage({ id: 'SearchPage.schemaDescription' }); + const schemaTitle = intl.formatMessage( + { id: 'SearchPage.schemaTitle' }, + { searchAddress, siteTitle } + ); + + const schemaListings = listings.map((l, i) => { + const title = l.attributes.title; + const pathToItem = createResourceLocatorString('ListingPage', routeConfiguration(), { + id: l.id.uuid, + slug: createSlug(title), + }); + return { + '@type': 'ListItem', + position: i, + url: `${config.canonicalRootURL}${pathToItem}`, + name: title, + }; + }); + + const schemaMainEntity = JSON.stringify({ + '@type': 'ItemList', + name: searchAddress, + itemListOrder: 'http://schema.org/ItemListOrderAscending', + itemListElement: schemaListings, + }); + return { + title: schemaTitle, + description: schemaDescription, + schema: { + '@context': 'http://schema.org', + '@type': 'SearchResultsPage', + description: schemaDescription, + name: schemaTitle, + mainEntity: [schemaMainEntity], + }, + }; +}; diff --git a/src/containers/SearchPage/SearchPage.js b/src/containers/SearchPage/SearchPage.js index bc0a6345..e960ddd1 100644 --- a/src/containers/SearchPage/SearchPage.js +++ b/src/containers/SearchPage/SearchPage.js @@ -15,7 +15,7 @@ import { hasSameSDKBounds, } from '../../util/googleMaps'; import { createResourceLocatorString } from '../../util/routes'; -import { createSlug, parse, stringify } from '../../util/urlHelpers'; +import { parse, stringify } from '../../util/urlHelpers'; import { propTypes } from '../../util/types'; import { getListingsById } from '../../ducks/marketplaceData.duck'; import { manageDisableScrolling, isScrollingDisabled } from '../../ducks/UI.duck'; @@ -27,6 +27,7 @@ import { pickSearchParamsOnly, validURLParamForExtendedData, validURLParamsForExtendedData, + createSearchResultSchema, } from './SearchPage.helpers'; import MainPanel from './MainPanel'; import css from './SearchPage.css'; @@ -192,35 +193,6 @@ export class SearchPageComponent extends Component { ); const isWindowDefined = typeof window !== 'undefined'; - // Schema for search engines (helps them to understand what this page is about) - // http://schema.org - // We are using JSON-LD format - const siteTitle = config.siteTitle; - const searchAddress = address || intl.formatMessage({ id: 'SearchPage.schemaMapSearch' }); - const schemaTitle = intl.formatMessage( - { id: 'SearchPage.schemaTitle' }, - { searchAddress, siteTitle } - ); - const schemaDescription = intl.formatMessage({ id: 'SearchPage.schemaDescription' }); - const schemaListings = listings.map((l, i) => { - const title = l.attributes.title; - const pathToItem = createResourceLocatorString('ListingPage', routeConfiguration(), { - id: l.id.uuid, - slug: createSlug(title), - }); - return { - '@type': 'ListItem', - position: i, - url: `${config.canonicalRootURL}${pathToItem}`, - name: title, - }; - }); - const schemaMainEntity = JSON.stringify({ - '@type': 'ItemList', - name: searchAddress, - itemListOrder: 'http://schema.org/ItemListOrderAscending', - itemListElement: schemaListings, - }); const isMobileLayout = isWindowDefined && window.innerWidth < MODAL_BREAKPOINT; const shouldShowSearchMap = !isMobileLayout || (isMobileLayout && this.state.isSearchMapOpenOnMobile); @@ -232,6 +204,8 @@ export class SearchPageComponent extends Component { }; const { address, bounds, origin } = searchInURL || {}; + const { title, description, schema } = createSearchResultSchema(listings, address, intl); + // Set topbar class based on if a modal is open in // a child component const topbarClasses = this.state.isMobileModalOpen @@ -244,15 +218,9 @@ export class SearchPageComponent extends Component { return (