Skip to content

Commit 9a51e9c

Browse files
authored
feat(seo): add Learning Center, hreflang, OG tags, and high-value content pages (#2024)
1 parent 5ab8cfc commit 9a51e9c

File tree

7 files changed

+363
-21
lines changed

7 files changed

+363
-21
lines changed

config/hreflang.js

Lines changed: 82 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,82 @@
1+
const SITE_URL = 'https://apisix.apache.org';
2+
3+
/**
4+
* Docusaurus plugin that injects hreflang <link> tags and canonical URLs
5+
* into every HTML page during the post-build phase.
6+
*
7+
* For each page, it generates:
8+
* <link rel="alternate" hreflang="en" href="https://apisix.apache.org/..." />
9+
* <link rel="alternate" hreflang="zh" href="https://apisix.apache.org/zh/..." />
10+
* <link rel="alternate" hreflang="x-default" href="https://apisix.apache.org/..." />
11+
* <link rel="canonical" href="..." /> (if not already present)
12+
*/
13+
module.exports = function hreflangPlugin() {
14+
return {
15+
name: 'hreflang',
16+
17+
async postBuild({ outDir }) {
18+
const fs = require('fs');
19+
const path = require('path');
20+
21+
function findHtmlFiles(dir) {
22+
const results = [];
23+
const entries = fs.readdirSync(dir, { withFileTypes: true });
24+
for (const entry of entries) {
25+
const fullPath = path.join(dir, entry.name);
26+
if (entry.isDirectory()) {
27+
results.push(...findHtmlFiles(fullPath));
28+
} else if (entry.name.endsWith('.html')) {
29+
results.push(fullPath);
30+
}
31+
}
32+
return results;
33+
}
34+
35+
const htmlFiles = findHtmlFiles(outDir);
36+
37+
for (const filePath of htmlFiles) {
38+
let html = fs.readFileSync(filePath, 'utf-8');
39+
40+
// Determine relative path from outDir
41+
const relativePath = path.relative(outDir, filePath);
42+
43+
// Determine the current locale based on file path
44+
const isZh = relativePath.startsWith('zh' + path.sep);
45+
46+
// Compute the path without locale prefix
47+
const pathWithoutLocale = isZh
48+
? relativePath.slice(3) // remove "zh/"
49+
: relativePath;
50+
51+
// Normalize path separators for URL
52+
const urlPath = pathWithoutLocale.split(path.sep).join('/');
53+
54+
// Build URLs
55+
const enUrl = `${SITE_URL}/${urlPath}`.replace(/\/index\.html$/, '/');
56+
const zhUrl = `${SITE_URL}/zh/${urlPath}`.replace(/\/index\.html$/, '/');
57+
const currentUrl = isZh ? zhUrl : enUrl;
58+
59+
// Build hreflang tags
60+
const hreflangTags = [
61+
`<link rel="alternate" hreflang="en" href="${enUrl}" />`,
62+
`<link rel="alternate" hreflang="zh" href="${zhUrl}" />`,
63+
`<link rel="alternate" hreflang="x-default" href="${enUrl}" />`,
64+
].join('\n ');
65+
66+
// Add canonical tag if not already present
67+
const hasCanonical = html.includes('rel="canonical"');
68+
const canonicalTag = hasCanonical
69+
? ''
70+
: `<link rel="canonical" href="${currentUrl}" />`;
71+
72+
// Inject before </head>
73+
const injection = [hreflangTags, canonicalTag]
74+
.filter(Boolean)
75+
.join('\n ');
76+
html = html.replace('</head>', ` ${injection}\n </head>`);
77+
78+
fs.writeFileSync(filePath, html, 'utf-8');
79+
}
80+
},
81+
};
82+
};

config/navbar.js

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -52,6 +52,12 @@ module.exports = [
5252
},
5353
],
5454
},
55+
{
56+
to: '/learning-center',
57+
label: 'Learning Center',
58+
position: 'right',
59+
target: '_parent',
60+
},
5561
{
5662
to: '/blog',
5763
label: 'Blog',

website/docusaurus.config.js

Lines changed: 29 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -95,9 +95,21 @@ module.exports = {
9595
blogTitle: 'Article',
9696
},
9797
],
98+
[
99+
'@docusaurus/plugin-content-blog',
100+
{
101+
id: 'learning-center',
102+
routeBasePath: 'learning-center',
103+
path: 'learning-center',
104+
blogSidebarCount: 'ALL',
105+
blogSidebarTitle: 'Learning Center',
106+
blogTitle: 'Learning Center',
107+
showReadingTime: true,
108+
},
109+
],
98110
['docusaurus-plugin-sass', {}],
99111
require.resolve('../config/schema-org'),
100-
require.resolve('../config/breadcrumb'),
112+
require.resolve('../config/hreflang'),
101113
],
102114
themeConfig: {
103115
navbar: {
@@ -146,6 +158,22 @@ module.exports = {
146158
name: 'twitter:card',
147159
content: 'summary_large_image',
148160
},
161+
{
162+
name: 'twitter:site',
163+
content: '@apacheapisix',
164+
},
165+
{
166+
property: 'og:site_name',
167+
content: 'Apache APISIX',
168+
},
169+
{
170+
property: 'og:type',
171+
content: 'website',
172+
},
173+
{
174+
property: 'og:image',
175+
content: 'https://static.apiseven.com/202202/apache-apisix.png',
176+
},
149177
],
150178
},
151179
scripts: [

website/i18n/zh/code.json

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,8 @@
11
{
2+
"homepage.meta.title": {
3+
"message": "Apache APISIX - 开源云原生 API 网关与 AI 网关",
4+
"description": "Homepage title for Chinese locale"
5+
},
26
"common.punctuation.anEnd": {
37
"message": "",
48
"description": "."

0 commit comments

Comments
 (0)