Merge pull request #476 from sharetribe/canonical-listing-url

Canonical listing page URL without slug
This commit is contained in:
Kimmo Puputti 2017-10-06 15:19:24 +03:00 committed by GitHub
commit 12ded4c18d
6 changed files with 51 additions and 8 deletions

View file

@ -37,6 +37,7 @@ describe('Application', () => {
'/': 'Book saunas everywhere | Saunatime',
'/s': 'Search results for map search | Saunatime',
'/l/listing-title-slug/1234': 'Loading listing…',
'/l/1234': 'Loading listing…',
'/u/1234': 'Profile page with display name: 1234',
'/login': 'Login',
'/signup': 'Sign up',

View file

@ -59,6 +59,7 @@ class PageComponent extends Component {
title,
twitterHandle,
twitterImages,
canonicalPath,
updated,
} = this.props;
@ -86,10 +87,20 @@ class PageComponent extends Component {
const metaTitle = title || schemaTitle;
const metaDescription = description || schemaDescription;
const facebookImgs = facebookImages || [
{ name: 'facebook', url: `${config.canonicalRootURL}${facebookImage}`, width: 1200, height: 630 },
{
name: 'facebook',
url: `${config.canonicalRootURL}${facebookImage}`,
width: 1200,
height: 630,
},
];
const twitterImgs = twitterImages || [
{ name: 'twitter', url: `${config.canonicalRootURL}${twitterImage}`, width: 600, height: 314 },
{
name: 'twitter',
url: `${config.canonicalRootURL}${twitterImage}`,
width: 600,
height: 314,
},
];
const metaToHead = metaTagProps({
@ -129,7 +140,7 @@ class PageComponent extends Component {
}}
>
<title>{title}</title>
<link rel="canonical" href={canonicalURL(pathWithSearch)} />
<link rel="canonical" href={canonicalURL(canonicalPath || pathWithSearch)} />
<meta httpEquiv="Content-Type" content="text/html; charset=UTF-8" />
<meta httpEquiv="Content-Language" content={intl.locale} />
{metaTags}
@ -170,6 +181,7 @@ PageComponent.defaultProps = {
description: null,
facebookImages: null,
twitterImages: null,
canonicalPath: null,
published: null,
schema: null,
tags: null,
@ -209,6 +221,7 @@ PageComponent.propTypes = {
title: string.isRequired, // page title
twitterHandle: string, // twitter handle
updated: string, // article:modified_time
canonicalPath: string, // link rel=canonical
// from withRouter
history: shape({

View file

@ -115,7 +115,8 @@ export class ListingPageComponent extends Component {
handleSubmit(values) {
const { flattenedRoutes, history, getListing, params, useInitialValues } = this.props;
const listing = getListing(new UUID(params.id));
const listingId = new UUID(params.id);
const listing = getListing(listingId);
this.setState({ isBookingModalOpenOnMobile: false });
@ -166,8 +167,11 @@ export class ListingPageComponent extends Component {
sendVerificationEmailInProgress,
sendVerificationEmailError,
onResendVerificationEmail,
flattenedRoutes,
} = this.props;
const currentListing = ensureListing(getListing(new UUID(params.id)));
const listingId = new UUID(params.id);
const currentListing = ensureListing(getListing(listingId));
const listingSlug = params.slug || createSlug(currentListing.attributes.title || '');
const {
address = '',
description = '',
@ -299,7 +303,7 @@ export class ListingPageComponent extends Component {
}
};
const editParams = { ...params, type: 'edit', tab: 'description' };
const editParams = { id: listingId.uuid, slug: listingSlug, type: 'edit', tab: 'description' };
const listingClasses = classNames(css.pageRoot);
@ -341,6 +345,10 @@ export class ListingPageComponent extends Component {
{ title, price: formattedPrice, siteTitle }
);
const canonicalPath = createResourceLocatorString('ListingPageCanonical', flattenedRoutes, {
id: listingId.uuid,
});
return (
<Page
authInfoError={authInfoError}
@ -352,6 +360,7 @@ export class ListingPageComponent extends Component {
description={description}
facebookImages={facebookImages}
twitterImages={twitterImages}
canonicalPath={canonicalPath}
schema={
`
{
@ -513,7 +522,7 @@ ListingPageComponent.propTypes = {
intl: intlShape.isRequired,
params: shape({
id: string.isRequired,
slug: string.isRequired,
slug: string,
}).isRequired,
authInfoError: instanceOf(Error),
authInProgress: bool.isRequired,

View file

@ -17,7 +17,16 @@ describe('ListingPage', () => {
const listing1 = createListing('listing1', {}, { author: createUser('user-1') });
const getListing = () => listing1;
const props = {
flattenedRoutes: [],
flattenedRoutes: [
// Fake route since a circular dependency prevents using the
// full routesConfiguration here
{
path: '/l/:id',
exact: true,
name: 'ListingPageCanonical',
component: noop,
},
],
location: { search: '' },
history: {
push: () => console.log('HistoryPush called'),

View file

@ -2,6 +2,7 @@ exports[`ListingPage matches snapshot 1`] = `
<Page
authInfoError={null}
author="user-1 display name"
canonicalPath="/l/listing1"
contentType="website"
description="listing1 description"
facebookImages={Array []}

View file

@ -112,6 +112,16 @@ const routesConfiguration = [
component: props => <EditListingPage {...props} />,
loadData: (params, search) => EditListingPage.loadData(params, search),
},
// Canonical path should be after the `/l/new` path since they
// conflict and `new` is not a valid listing UUID.
{
path: '/l/:id',
exact: true,
name: 'ListingPageCanonical',
loadData: (params, search) => ListingPage.loadData(params, search),
component: props => <ListingPage {...props} tab="listing" />,
},
],
},
{