diff --git a/src/app/components/cards/PostFull.jsx b/src/app/components/cards/PostFull.jsx index caadfe97f2..3e81deb123 100644 --- a/src/app/components/cards/PostFull.jsx +++ b/src/app/components/cards/PostFull.jsx @@ -28,8 +28,8 @@ import userIllegalContent from 'app/utils/userIllegalContent'; import ImageUserBlockList from 'app/utils/ImageUserBlockList'; import LoadingIndicator from 'app/components/elements/LoadingIndicator'; import { allowDelete } from 'app/utils/StateFunctions'; -import ContentEditedWrapper from '../elements/ContentEditedWrapper'; import { Role } from 'app/utils/Community'; +import ContentEditedWrapper from '../elements/ContentEditedWrapper'; function TimeAuthorCategory({ post }) { return ( @@ -268,6 +268,51 @@ class PostFull extends React.Component { if (process.env.BROWSER && title) document.title = title + ' — ' + APP_NAME; + if (process.env.BROWSER) { + const canonicalLink = document.getElementById('canonicalUrlID'); + if (!canonicalLink) { + const newCanonicalUrlID = document.createElement('link'); + newCanonicalUrlID.rel = 'canonical'; + newCanonicalUrlID.key = 'canonical'; + newCanonicalUrlID.id = 'canonicalUrlID'; + document.head.appendChild(newCanonicalUrlID); + } + if (canonicalLink) { + let tempCategory = category || ''; + const tags = content.json_metadata.tags || []; + + // Leave Options 1 and 2 uncommented for a combination of both approaches + // Option 1: Replace hive-xxxxxx in the URL with the community name. This doesn't impact non-community posts + const communityTitle = + content.community_title || `#${tempCategory}` || ''; + const sanitizedTitle = communityTitle + .replace(/[^a-zA-Z0-9 ]/g, '') + .trim(); + const urlFriendlyTitle = sanitizedTitle + .replace(/\s+/g, '-') + .toLowerCase(); + if (urlFriendlyTitle) { + tempCategory = urlFriendlyTitle; + } + + // Option 2: Replace hive-xxxxxx in the URL with the first tag of a post + if (tempCategory.startsWith('hive-') && tags.length > 0) { + const firstTag = tags[0].startsWith('#') + ? tags[0].substring(1) + : tags[0]; + tempCategory = + firstTag.startsWith('hive-') && tags.length > 1 + ? tags[1] + : firstTag; // Sometimes the first tag is still the community & need to check if there's a second tag + tempCategory = tempCategory.startsWith('#') + ? tempCategory.substring(1) + : tempCategory; + } + const canonicalURL = `/${tempCategory}/@${author}/${permlink}`; + canonicalLink.href = 'https://' + APP_DOMAIN + canonicalURL; + } + } + let content_body = post.get('body'); const bDMCAStop = DMCAList.includes(link); const bIllegalContentUser = userIllegalContent.includes(author); diff --git a/src/app/components/cards/PostSummary.jsx b/src/app/components/cards/PostSummary.jsx index b31be86e2f..9b9823734f 100644 --- a/src/app/components/cards/PostSummary.jsx +++ b/src/app/components/cards/PostSummary.jsx @@ -97,7 +97,39 @@ class PostSummary extends React.Component { const author = post.get('author'); const permlink = post.get('permlink'); const category = post.get('category'); - const post_url = `/${category}/@${author}/${permlink}`; + + let tempCategory = category || ''; + const tags = post.getIn(['json_metadata', 'tags']) || []; + + // Leave Options 1 and 2 uncommented for a combination of both approaches + // Option 1: Replace hive-xxxxxx in the URL with the community name. This doesn't impact non-community posts + const communityTitle = + post.get('community_title', '#' + tempCategory) || ''; + const sanitizedTitle = communityTitle + .replace(/[^a-zA-Z0-9 ]/g, '') + .trim(); + const urlFriendlyTitle = sanitizedTitle + .replace(/\s+/g, '-') + .toLowerCase(); + if (urlFriendlyTitle) { + tempCategory = urlFriendlyTitle; + } + + // Option 2: Replace hive-xxxxxx in the URL with the first tag of a post + if (tempCategory.startsWith('hive-') && tags && tags.size > 0) { + const firstTag = tags.get(0).startsWith('#') + ? tags.get(0).substring(1) + : tags.get(0); + tempCategory = + firstTag.startsWith('hive-') && tags.size > 1 + ? tags.get(1) + : firstTag; // Sometimes the first tag is still the community & need to check if there's a second tag + tempCategory = tempCategory.startsWith('#') + ? tempCategory.substring(1) + : tempCategory; + } + + const post_url = `/${tempCategory}/@${author}/${permlink}`; const summary = extractBodySummary(post.get('body'), isReply); const keyWord = process.env.BROWSER diff --git a/src/app/components/modules/Header/index.jsx b/src/app/components/modules/Header/index.jsx index 8e8f525d28..a1d2630e0c 100644 --- a/src/app/components/modules/Header/index.jsx +++ b/src/app/components/modules/Header/index.jsx @@ -14,7 +14,7 @@ import { parseJsonTags } from 'app/utils/StateFunctions'; import Headroom from 'react-headroom'; import resolveRoute from 'app/ResolveRoute'; import tt from 'counterpart'; -import { APP_NAME } from 'app/client_config'; +import { APP_NAME, APP_DOMAIN } from 'app/client_config'; import ElasticSearchInput from 'app/components/elements/ElasticSearchInput'; import IconButton from 'app/components/elements/IconButton'; import DropdownMenu from 'app/components/elements/DropdownMenu'; @@ -250,6 +250,20 @@ class Header extends React.Component { ) document.title = page_title + ' — ' + APP_NAME; + if (process.env.BROWSER && route.page !== 'Post') { + const canonicalLink = document.getElementById('canonicalUrlID'); + if (canonicalLink) { + canonicalLink.href = 'https://' + APP_DOMAIN + pathname; + } else { + const newCanonicalUrlID = document.createElement('link'); + newCanonicalUrlID.rel = 'canonical'; + newCanonicalUrlID.key = 'canonical'; + newCanonicalUrlID.id = 'canonicalUrlID'; + newCanonicalUrlID.href = 'https://' + APP_DOMAIN + pathname; + document.head.appendChild(newCanonicalUrlID); + } + } + //const _feed = current_account_name && `/@${current_account_name}/feed`; //const logo_link = _feed && pathname != _feed ? _feed : '/'; const logo_link = '/'; diff --git a/src/app/utils/CanonicalLinker.js b/src/app/utils/CanonicalLinker.js index bebbd65ae3..d6265a98da 100644 --- a/src/app/utils/CanonicalLinker.js +++ b/src/app/utils/CanonicalLinker.js @@ -21,9 +21,36 @@ function read_md_canonical(metadata) { function build_scheme(scheme, post) { // https://github.com/bonustrack/steemscript/blob/master/apps.json + let tempCategory = post.category || ''; + + const tags = post.json_metadata.tags || []; + + // Leave Options 1 and 2 uncommented for a combination of both approaches + // Option 1: Replace hive-xxxxxx in the URL with the community name. This doesn't impact non-community posts + const communityTitle = post.community_title || `#${tempCategory}` || ''; + const sanitizedTitle = communityTitle.replace(/[^a-zA-Z0-9 ]/g, '').trim(); + const urlFriendlyTitle = sanitizedTitle.replace(/\s+/g, '-').toLowerCase(); + if (urlFriendlyTitle) { + tempCategory = urlFriendlyTitle; + } + + // Option 2: Replace hive-xxxxxx in the URL with the first tag of a post + if (tempCategory.startsWith('hive-') && tags.length > 0) { + const firstTag = tags[0].startsWith('#') + ? tags[0].substring(1) + : tags[0]; + tempCategory = + firstTag.startsWith('hive-') && tags.length > 1 + ? tags[1] + : firstTag; // Sometimes the first tag is still the community & need to check if there's a second tag + tempCategory = tempCategory.startsWith('#') + ? tempCategory.substring(1) + : tempCategory; + } + return scheme .split('{category}') - .join(post.category) + .join(tempCategory) .split('{username}') .join(post.author) .split('{permlink}') diff --git a/src/server/server-html.jsx b/src/server/server-html.jsx index 9f6d4f5d52..8cd485eb99 100644 --- a/src/server/server-html.jsx +++ b/src/server/server-html.jsx @@ -53,6 +53,7 @@ export default function ServerHTML({ key="canonical" rel="canonical" href={m.canonical} + id="canonicalUrlID" /> ); if (m.name && m.content)