Skip to content

Commit 850ff33

Browse files
Merge pull request #247 from datazip-inc/canonical-changes
Ensure canonical URLs include trailing slash
2 parents 78da8cf + 6051703 commit 850ff33

File tree

7 files changed

+131
-21
lines changed

7 files changed

+131
-21
lines changed

src/pages/community/contributor-program/index.tsx

Lines changed: 18 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -25,11 +25,27 @@ import FeatureCard from '../../../components/community/improved/FeatureCard'
2525
// import StatCard from '../../../components/community/improved/StatCard'
2626
import SectionLayout from '../../../components/community/SectionLayout'
2727

28+
const stripTrailingSlash = (value?: string) => {
29+
if (!value) {
30+
return ''
31+
}
32+
33+
return value.endsWith('/') ? value.slice(0, -1) : value
34+
}
35+
36+
const ensureTrailingSlash = (value: string) => {
37+
if (!value) {
38+
return '/'
39+
}
40+
41+
return value.endsWith('/') ? value : `${value}/`
42+
}
43+
2844
const ContributorProgramPage = () => {
2945
const { siteConfig } = useDocusaurusContext()
3046
const location = useLocation()
31-
const siteUrl = siteConfig?.url || 'https://olake.io'
32-
const canonicalUrl = `${siteUrl}${location.pathname}`
47+
const siteUrl = stripTrailingSlash(siteConfig?.url || 'https://olake.io')
48+
const canonicalUrl = ensureTrailingSlash(`${siteUrl}${location.pathname || '/'}`)
3349

3450
const contributionTypes = [
3551
{

src/pages/community/contributors/index.tsx

Lines changed: 18 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -24,11 +24,27 @@ import PageHeader from '../../../components/community/improved/PageHeader'
2424
import SectionHeader from '../../../components/community/improved/SectionHeader'
2525

2626
import clsx from 'clsx'
27+
28+
const stripTrailingSlash = (value?: string) => {
29+
if (!value) {
30+
return ''
31+
}
32+
33+
return value.endsWith('/') ? value.slice(0, -1) : value
34+
}
35+
36+
const ensureTrailingSlash = (value: string) => {
37+
if (!value) {
38+
return '/'
39+
}
40+
41+
return value.endsWith('/') ? value : `${value}/`
42+
}
2743
const ContributorsPage = () => {
2844
const { siteConfig } = useDocusaurusContext()
2945
const location = useLocation()
30-
const siteUrl = siteConfig?.url || 'https://olake.io'
31-
const canonicalUrl = `${siteUrl}${location.pathname}`
46+
const siteUrl = stripTrailingSlash(siteConfig?.url || 'https://olake.io')
47+
const canonicalUrl = ensureTrailingSlash(`${siteUrl}${location.pathname || '/'}`)
3248
const [contributors, setContributors] = useState<ContributorProps[]>([])
3349

3450

src/pages/community/index.tsx

Lines changed: 18 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -30,11 +30,27 @@ import LazyComponent from '../../components/LazyComponent'
3030
import SectionLayout from '../../components/community/SectionLayout'
3131
import StatCard from '@site/src/components/community/improved/StatCard'
3232

33+
const stripTrailingSlash = (value?: string) => {
34+
if (!value) {
35+
return ''
36+
}
37+
38+
return value.endsWith('/') ? value.slice(0, -1) : value
39+
}
40+
41+
const ensureTrailingSlash = (value: string) => {
42+
if (!value) {
43+
return '/'
44+
}
45+
46+
return value.endsWith('/') ? value : `${value}/`
47+
}
48+
3349
const CommunityPage = () => {
3450
const { siteConfig } = useDocusaurusContext()
3551
const location = useLocation()
36-
const siteUrl = siteConfig?.url || 'https://olake.io'
37-
const canonicalUrl = `${siteUrl}${location.pathname}`
52+
const siteUrl = stripTrailingSlash(siteConfig?.url || 'https://olake.io')
53+
const canonicalUrl = ensureTrailingSlash(`${siteUrl}${location.pathname || '/'}`)
3854

3955
const communityMeets = [
4056
{

src/pages/index.jsx

Lines changed: 18 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -10,11 +10,27 @@ import WorkflowSection from '../components/site/WorkflowSection'
1010
import Footer from '@theme/DocItem/Footer'
1111
import LazyComponent from '../components/LazyComponent'
1212

13+
const stripTrailingSlash = (value) => {
14+
if (!value) {
15+
return ''
16+
}
17+
18+
return value.endsWith('/') ? value.slice(0, -1) : value
19+
}
20+
21+
const ensureTrailingSlash = (value) => {
22+
if (!value) {
23+
return '/'
24+
}
25+
26+
return value.endsWith('/') ? value : `${value}/`
27+
}
28+
1329
export default function New3Page() {
1430
const { siteConfig } = useDocusaurusContext()
1531
const location = useLocation()
16-
const siteUrl = siteConfig?.url || 'https://olake.io'
17-
const canonicalUrl = `${siteUrl}${location.pathname || '/'}`
32+
const siteUrl = stripTrailingSlash(siteConfig?.url || 'https://olake.io')
33+
const canonicalUrl = ensureTrailingSlash(`${siteUrl}${location.pathname || '/'}`)
1834
const ogTitle = 'Fastest Open Source Data Replication Tool'
1935
const ogDescription = 'Fastest open-source tool for replicating Databases to Data Lake in Open Table Formats like Apache Iceberg. Efficient, quick and scalable data ingestion for real-time analytics. Supporting Postgres, MongoDB, MySQL, Oracle and Kafka with 5-500x faster than alternatives.'
2036
const ogImage = 'https://olake.io/img/logo/olake-blue.webp'

src/pages/webinar/index.tsx

Lines changed: 18 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,22 @@ import LazyComponent from '../../components/LazyComponent'
88
import WebinarGrid from '../../components/webinars/WebinarGrid';
99
import { FaFileVideo, FaVideo, FaPlay, FaUsers, FaCalendarAlt, FaBroadcastTower } from 'react-icons/fa';
1010

11+
const stripTrailingSlash = (value?: string) => {
12+
if (!value) {
13+
return '';
14+
}
15+
16+
return value.endsWith('/') ? value.slice(0, -1) : value;
17+
};
18+
19+
const ensureTrailingSlash = (value: string) => {
20+
if (!value) {
21+
return '/';
22+
}
23+
24+
return value.endsWith('/') ? value : `${value}/`;
25+
};
26+
1127
// Custom hook for dynamic iframe height
1228
const useDynamicIframeHeight = (src) => {
1329
const [height, setHeight] = useState(200);
@@ -81,8 +97,8 @@ const useDynamicIframeHeight = (src) => {
8197
const WebinarsPage = () => {
8298
const { siteConfig } = useDocusaurusContext()
8399
const location = useLocation()
84-
const siteUrl = siteConfig?.url || 'https://olake.io'
85-
const canonicalUrl = `${siteUrl}${location.pathname}`
100+
const siteUrl = stripTrailingSlash(siteConfig?.url || 'https://olake.io')
101+
const canonicalUrl = ensureTrailingSlash(`${siteUrl}${location.pathname || '/'}`)
86102
// Use the dynamic iframe height hook
87103
const { height: iframeHeight, iframeRef } = useDynamicIframeHeight('https://app.livestorm.co/datazip-inc/upcoming?limit=2');
88104

src/theme/BlogPostPage/index.js

Lines changed: 21 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,22 @@ import BlogPostPage from '@theme-original/BlogPostPage';
33
import Head from '@docusaurus/Head';
44
import useDocusaurusContext from '@docusaurus/useDocusaurusContext';
55

6+
const ensureTrailingSlash = (value) => {
7+
if (!value) {
8+
return value;
9+
}
10+
11+
return value.endsWith('/') ? value : `${value}/`;
12+
};
13+
14+
const stripTrailingSlash = (value) => {
15+
if (!value) {
16+
return value;
17+
}
18+
19+
return value.endsWith('/') ? value.slice(0, -1) : value;
20+
};
21+
622
export default function BlogPostPageWrapper(props) {
723
const { content: BlogPostContent } = props;
824
const { metadata } = BlogPostContent;
@@ -11,17 +27,16 @@ export default function BlogPostPageWrapper(props) {
1127
// Extract author name and reading time
1228
const authorName = metadata.authors?.[0]?.name || 'OLake Team';
1329
const readingTime = metadata.readingTime || '5 minutes';
14-
15-
// Strip trailing slashes from permalink for canonical URL
16-
const cleanPermalink = metadata.permalink?.replace(/\/$/, '') || metadata.permalink;
17-
const canonicalUrl = cleanPermalink ? `${siteConfig.url}${cleanPermalink}` : null;
30+
31+
const baseUrl = stripTrailingSlash(siteConfig?.url || 'https://olake.io');
32+
const permalink = metadata.permalink || '';
33+
const canonicalUrl = permalink ? ensureTrailingSlash(`${baseUrl}${permalink}`) : null;
1834

1935
return (
2036
<>
2137
<Head>
22-
{/* Fix canonical URL to not have trailing slash */}
2338
{canonicalUrl && <link rel="canonical" href={canonicalUrl} />}
24-
{cleanPermalink && <meta property="og:url" content={canonicalUrl} />}
39+
{canonicalUrl && <meta property="og:url" content={canonicalUrl} />}
2540

2641
{/* Enhanced Open Graph for Blog Posts */}
2742
<meta property="og:image:type" content="image/webp" />

src/theme/DocItem/DocContent.js

Lines changed: 20 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,22 @@ import DocsRating from "./DocsRating";
1717
import DocBreadcrumbs from "@theme/DocBreadcrumbs";
1818
import DocsFooter from "../../../docs/shared/DocsFooter.mdx";
1919

20+
const stripTrailingSlash = (value) => {
21+
if (!value) {
22+
return value;
23+
}
24+
25+
return value.endsWith("/") ? value.slice(0, -1) : value;
26+
};
27+
28+
const ensureTrailingSlash = (value) => {
29+
if (!value) {
30+
return value;
31+
}
32+
33+
return value.endsWith("/") ? value : `${value}/`;
34+
};
35+
2036
export const DocContent = ({ Content, contentRef, readingTimeInWords }) => {
2137
const { siteConfig } = useDocusaurusContext();
2238
const { pluginId } = useActivePlugin({ failfast: true });
@@ -31,7 +47,7 @@ export const DocContent = ({ Content, contentRef, readingTimeInWords }) => {
3147
toc,
3248
} = useDoc();
3349

34-
const { url: siteUrl } = siteConfig;
50+
const baseUrl = stripTrailingSlash(siteConfig?.url || "https://olake.io");
3551
const versionMetadata = useDocsVersion();
3652
const { description, title, permalink, editUrl, lastUpdatedAt, lastUpdatedBy, unversionedId } =
3753
metadata;
@@ -44,9 +60,8 @@ export const DocContent = ({ Content, contentRef, readingTimeInWords }) => {
4460
absolute: true,
4561
});
4662

47-
// Strip trailing slashes from permalink for canonical URL
48-
const cleanPermalink = permalink?.replace(/\/$/, '') || permalink;
49-
const canonicalUrl = cleanPermalink ? siteUrl + cleanPermalink : null;
63+
const canonicalPath = ensureTrailingSlash(permalink);
64+
const canonicalUrl = canonicalPath ? `${baseUrl}${canonicalPath}` : null;
5065

5166
return (
5267
<>
@@ -60,7 +75,7 @@ export const DocContent = ({ Content, contentRef, readingTimeInWords }) => {
6075
{metaImage && <meta property="og:image" content={metaImageUrl} />}
6176
{metaImage && <meta name="twitter:image" content={metaImageUrl} />}
6277
{metaImage && <meta name="twitter:image:alt" content={`Image for ${title}`} />}
63-
{cleanPermalink && <meta property="og:url" content={canonicalUrl} />}
78+
{canonicalUrl && <meta property="og:url" content={canonicalUrl} />}
6479
<meta property="og:site_name" content="OLake" />
6580
<meta property="og:locale" content="en_US" />
6681
{canonicalUrl && <link rel="canonical" href={canonicalUrl} />}

0 commit comments

Comments
 (0)