This is an automated email from the ASF dual-hosted git repository.
davidarthur pushed a commit to branch markdown
in repository https://gitbox.apache.org/repos/asf/kafka-site.git
The following commit(s) were added to refs/heads/markdown by this push:
new c6d1a8143 KAFKA-20006 Fix broken links and updates to README (#761)
c6d1a8143 is described below
commit c6d1a8143b84f7db71351d271496918b729c34fc
Author: Harish Vishwanath <[email protected]>
AuthorDate: Thu Dec 18 14:20:29 2025 -0800
KAFKA-20006 Fix broken links and updates to README (#761)
* KAFKA-20006: Implement permalinks and redirects to continue to support
older links.
* KAFKA-20008: Update README with instructions on adding a new blog post
* fix link for /design
Reviewers: David Arthur <[email protected]>
---
README.md | 102 +++++++++++++++++++--------
content/en/_index.md | 4 +-
content/en/community/_index.md | 3 +
content/en/community/books_and_papers.md | 5 +-
content/en/community/committers.md | 3 +
content/en/community/contact.md | 3 +
content/en/community/cve-list.md | 3 +
content/en/community/developer.md | 7 ++
content/en/community/downloads.md | 5 +-
content/en/community/events.md | 3 +
content/en/community/podcasts.md | 3 +
content/en/community/project_security.md | 3 +
content/en/community/videos.md | 3 +
content/en/design.md | 9 +++
content/en/documentation/_index.md | 7 ++
content/en/documentation/streams.md | 9 +++
content/en/intro.md | 11 +++
content/en/protocol.md | 9 +++
content/en/quickstart.md | 11 +++
content/en/testimonials/_index.md | 4 ++
content/en/uses.md | 9 +++
hugo.yaml | 101 +++++++++++++-------------
layouts/partials/hooks/body-end.html | 6 +-
layouts/shortcodes/doc-redirect.html | 117 +++++++++++++++++++++++++++++++
layouts/shortcodes/include-latest.html | 8 +++
layouts/shortcodes/version-redirect.html | 11 +++
layouts/simple/single.html | 31 ++++++++
scripts/verify_redirects.py | 103 +++++++++++++++++++++++++++
28 files changed, 508 insertions(+), 85 deletions(-)
diff --git a/README.md b/README.md
index bd704ef6c..61831be46 100644
--- a/README.md
+++ b/README.md
@@ -50,7 +50,7 @@ Each version directory contains the complete documentation
for that specific Kaf
## Updating the Documentation Website
-### Adding a New Version
+### Adding documentation for a new release
When releasing a new documentation version (e.g., version 4.2 / "42"), follow
these steps:
@@ -58,35 +58,39 @@ When releasing a new documentation version (e.g., version
4.2 / "42"), follow th
Create a new directory in `content/en/` for the new version (e.g., `42/` for
version 4.2)
#### 2. Update Version Parameters in `hugo.yaml`
-
-**Update the centralized version parameters (Lines 142-144):**
-```yaml
-params:
- # Latest documentation version - UPDATE THIS WHEN RELEASING NEW VERSION
- latest_version: "42" # Change from "41" to "42"
- latest_version_number: "4.2" # Change from "4.1" to "4.2"
-```
-
-**Update the version parameter (Line ~180):**
-```yaml
- version: 4.2 # Change from 4.1 to 4.2
-```
-
-**Update the latest version URL (Line ~283):**
-```yaml
- url_latest_version: /42/ # Change from /41/ to /42/
-```
-
-**Add new version to versions list and mark previous as archived (Line ~184):**
-```yaml
- versions:
- - version: "4.2"
- url: /42/
- - version: "4.1"
- url: /41/
- archived_version: true # Mark previous version as archived
- # ... other versions ...
-```
+
+ Locate the **Version Configuration** block at the top of the `params` section
(around line 245). Update the following fields:
+
+ 1. `latest_version`: Set to the new version string (e.g., "42").
+ 2. `latest_version_number`: Set to the new version number (e.g., "4.2").
+ 3. `version`: Update to the new version (e.g., 4.2).
+ 4. `url_latest_version`: Update the link (e.g., `/42/`).
+ 5. `versions`:
+ - Add the new version to the top of the list.
+ - Mark the previous version as `archived_version: true`.
+
+ ```yaml
+ # Latest documentation version - UPDATE THIS WHEN RELEASING NEW VERSION
+ latest_version: "42"
+ latest_version_number: "4.2"
+
+ # ...
+
+ version: 4.2
+
+ # ...
+
+ url_latest_version: /42/
+
+ # ...
+
+ versions:
+ - version: "4.2"
+ url: /42/
+ - version: "4.1"
+ url: /41/
+ archived_version: true
+ ```
#### What Updates Automatically
@@ -145,6 +149,44 @@ The website uses Hugo's data templates to automatically
generate the testimonial
2. For common content (e.g., landing page, community docs):
- Edit files directly in `content/en/`
+### Front Matter Guide
+
+Detailed information about the Front Matter fields used in this site:
+
+- `title`: The title of the page or post.
+- `linkTitle`: (Optional) Short title used in sidebars and menus.
+- `date`: Publication date (YYYY-MM-DD).
+- `author`: Author name (often with GitHub handle). Typically used for blogs.
+- `weight`: (Optional) Controls ordering in lists/menus (lower numbers appear
first).
+- `description`: (Optional) Brief summary for SEO and previews.
+- `type`: Used to specify the layout type (e.g., `type: docs` for
documentation pages).
+- `aliases`: (Optional) List of old URLs that should redirect to this page.
+- `url`: (Optional) Overrides the default URL path constructed from the
filename.
+
+For more details, see the [Hugo Front Matter
Documentation](https://gohugo.io/content-management/front-matter/).
+
+### Adding a New Blog Post
+
+Blog posts are located in `content/en/blog/`. The most common use case is
adding a release announcement.
+
+#### Adding a Release Blog Post
+
+1. Create a new markdown file in `content/en/blog/releases/` using kebab-case
for the filename (e.g., `ak-4.3.0.md`).
+2. Add the required Front Matter. See the [Front Matter
Guide](#front-matter-guide) for details on fields.
+
+**Example Front Matter for a Release Post:**
+
+```yaml
+---
+date: 2025-01-01
+title: "Apache Kafka 4.3.0 Release Announcement"
+linkTitle: "AK 4.3.0"
+author: "Author Name (@github_handle)"
+---
+```
+
+3. Write your content below the Front Matter.
+
## Build and Test
### Prerequisites
diff --git a/content/en/_index.md b/content/en/_index.md
index 4990262b8..637cdd091 100644
--- a/content/en/_index.md
+++ b/content/en/_index.md
@@ -7,7 +7,7 @@ title: Apache Kafka
<a class="btn btn-lg btn-primary me-3 mb-4" href="{{< param
"url_latest_version" >}}">
Learn More <i class="fas fa-arrow-alt-circle-right ms-2"></i>
</a>
-<a class="btn btn-lg btn-secondary me-3 mb-4" href="/community/downloads/">
+<a class="btn btn-lg btn-secondary me-3 mb-4" href="/downloads/">
Download <i class="fa-solid fa-download ms-2 "></i>
</a>
<p class="lead mt-5"><i>More than 80% of all Fortune 100 companies trust, and
use Apache Kafka.</i></p>
@@ -56,7 +56,7 @@ Apache Kafka is an open-source distributed event streaming
platform used by thou
Above is a snapshot of the number of top-ten largest companies using Kafka,
per-industry.
<br/>
<br/>
- <a href="/testimonials/" class="btn btn-lg btn-primary">See full list <i
class="fas fa-arrow-alt-circle-right ms-2"></i></a>
+ <a href="/powered-by/" class="btn btn-lg btn-primary">See full list <i
class="fas fa-arrow-alt-circle-right ms-2"></i></a>
</p>
{{< /blocks/section >}}
diff --git a/content/en/community/_index.md b/content/en/community/_index.md
index d0361a87b..d4e7d0cd8 100644
--- a/content/en/community/_index.md
+++ b/content/en/community/_index.md
@@ -1,6 +1,9 @@
---
title: Community
type: docs
+aliases:
+ - "/project"
+ - "/project.html"
# Add blocks of content here to add more sections to the community page
---
diff --git a/content/en/community/books_and_papers.md
b/content/en/community/books_and_papers.md
index 549f541f6..93a13936a 100644
--- a/content/en/community/books_and_papers.md
+++ b/content/en/community/books_and_papers.md
@@ -1,5 +1,8 @@
---
-title: "Books And Papers"
+title: Books and Papers
+aliases:
+ - "/books-and-papers"
+ - "/books-and-papers.html"
type: docs
---
diff --git a/content/en/community/committers.md
b/content/en/community/committers.md
index 1e98dbdbc..fbf05f045 100644
--- a/content/en/community/committers.md
+++ b/content/en/community/committers.md
@@ -1,6 +1,9 @@
---
title: "The Committers"
type: docs
+aliases:
+ - "/committers"
+ - "/committers.html"
---
{{< about/committers >}}
diff --git a/content/en/community/contact.md b/content/en/community/contact.md
index abbefc17b..c41cc21a4 100644
--- a/content/en/community/contact.md
+++ b/content/en/community/contact.md
@@ -1,6 +1,9 @@
---
title: Contact
type: docs
+aliases:
+ - "/contact"
+ - "/contact.html"
---
## Mailing Lists
diff --git a/content/en/community/cve-list.md b/content/en/community/cve-list.md
index e69b0d5d7..01787da63 100644
--- a/content/en/community/cve-list.md
+++ b/content/en/community/cve-list.md
@@ -1,6 +1,9 @@
---
title: CVE List
type: docs
+aliases:
+ - "/cve-list"
+ - "/cve-list.html"
---
## Apache Kafka Security Vulnerabilities
diff --git a/content/en/community/developer.md
b/content/en/community/developer.md
index 6bfaddfb9..6f837c033 100644
--- a/content/en/community/developer.md
+++ b/content/en/community/developer.md
@@ -1,6 +1,13 @@
---
title: Developer Guide
type: docs
+aliases:
+ - "/contributing"
+ - "/contributing.html"
+ - "/coding-guide"
+ - "/coding-guide.html"
+ - "/code"
+ - "/code.html"
---
## Getting the code
diff --git a/content/en/community/downloads.md
b/content/en/community/downloads.md
index 3a88fddd7..5bf4199c7 100644
--- a/content/en/community/downloads.md
+++ b/content/en/community/downloads.md
@@ -1,10 +1,11 @@
---
title: "Downloads"
type: docs
+aliases:
+ - "/downloads"
+ - "/downloads.html"
---
-
-
The project goal is to have 3 releases a year, which means a release every 4
months. Bugfix releases are made as needed for supported releases only. It is
possible to verify every download by following these
[procedures](https://www.apache.org/info/verification.html) and using these
[KEYS](https://downloads.apache.org/kafka/KEYS).
## Supported releases
diff --git a/content/en/community/events.md b/content/en/community/events.md
index ab9904e42..3907f1442 100644
--- a/content/en/community/events.md
+++ b/content/en/community/events.md
@@ -1,6 +1,9 @@
---
title: "Events"
type: docs
+aliases:
+ - "/events"
+ - "/events.html"
---
diff --git a/content/en/community/podcasts.md b/content/en/community/podcasts.md
index aed025b14..6df026615 100644
--- a/content/en/community/podcasts.md
+++ b/content/en/community/podcasts.md
@@ -1,6 +1,9 @@
---
title: "Podcasts"
type: docs
+aliases:
+ - "/podcasts"
+ - "/podcasts.html"
---
diff --git a/content/en/community/project_security.md
b/content/en/community/project_security.md
index c5460e82a..28024fc69 100644
--- a/content/en/community/project_security.md
+++ b/content/en/community/project_security.md
@@ -1,6 +1,9 @@
---
title: "Project Security"
type: docs
+aliases:
+ - "/project-security"
+ - "/project-security.html"
---
# Kafka security
diff --git a/content/en/community/videos.md b/content/en/community/videos.md
index e529d096e..b4845fefe 100644
--- a/content/en/community/videos.md
+++ b/content/en/community/videos.md
@@ -1,6 +1,9 @@
---
title: "Videos"
type: docs
+aliases:
+ - "/videos"
+ - "/videos.html"
---
# Best Kafka Summit Videos
diff --git a/content/en/design.md b/content/en/design.md
new file mode 100644
index 000000000..4a8c25bda
--- /dev/null
+++ b/content/en/design.md
@@ -0,0 +1,9 @@
+---
+title: "Design"
+url: "/design"
+aliases:
+ - "/design.html"
+type: simple
+---
+
+{{< version-redirect path="design/design" >}}
diff --git a/content/en/documentation/_index.md
b/content/en/documentation/_index.md
new file mode 100644
index 000000000..680e9c095
--- /dev/null
+++ b/content/en/documentation/_index.md
@@ -0,0 +1,7 @@
+---
+title: "Documentation Redirect"
+url: "/documentation"
+robots: "noindex"
+---
+
+{{< doc-redirect >}}
diff --git a/content/en/documentation/streams.md
b/content/en/documentation/streams.md
new file mode 100644
index 000000000..88cc0d64c
--- /dev/null
+++ b/content/en/documentation/streams.md
@@ -0,0 +1,9 @@
+---
+title: "Kafka Streams"
+url: "/documentation/streams"
+aliases:
+ - "/documentation/streams.html"
+type: simple
+---
+
+{{< version-redirect path="streams/introduction" >}}
diff --git a/content/en/intro.md b/content/en/intro.md
new file mode 100644
index 000000000..3d3dda5be
--- /dev/null
+++ b/content/en/intro.md
@@ -0,0 +1,11 @@
+---
+title: "Introduction"
+url: "/intro"
+aliases:
+ - "/intro.html"
+type: simple
+---
+
+{{< youtube vHbvbwSEYGo >}}
+
+{{< include-latest path="getting-started/introduction" >}}
diff --git a/content/en/protocol.md b/content/en/protocol.md
new file mode 100644
index 000000000..3a6c8758a
--- /dev/null
+++ b/content/en/protocol.md
@@ -0,0 +1,9 @@
+---
+title: "Protocol"
+url: "/protocol"
+aliases:
+ - "/protocol.html"
+type: simple
+---
+
+{{< version-redirect path="design/protocol" >}}
diff --git a/content/en/quickstart.md b/content/en/quickstart.md
new file mode 100644
index 000000000..3c3c0a28c
--- /dev/null
+++ b/content/en/quickstart.md
@@ -0,0 +1,11 @@
+---
+title: "Quickstart"
+url: "/quickstart"
+aliases:
+ - "/quickstart.html"
+type: simple
+---
+
+{{< youtube vHbvbwSEYGo >}}
+
+{{< include-latest path="getting-started/quickstart" >}}
diff --git a/content/en/testimonials/_index.md
b/content/en/testimonials/_index.md
index a29e32d05..8931df789 100644
--- a/content/en/testimonials/_index.md
+++ b/content/en/testimonials/_index.md
@@ -1,6 +1,10 @@
---
title: Powered By
+url: "/powered-by"
body_class: testimonials-page
+aliases:
+ - "/powered-by.html"
+ - "/testimonials"
---
{{% blocks/cover title="Powered By" image_anchor="bottom" height="auto"
align="left" %}}
diff --git a/content/en/uses.md b/content/en/uses.md
new file mode 100644
index 000000000..544c86582
--- /dev/null
+++ b/content/en/uses.md
@@ -0,0 +1,9 @@
+---
+title: "Uses"
+url: "/uses"
+aliases:
+ - "/uses.html"
+type: simple
+---
+
+{{< include-latest path="getting-started/uses" >}}
diff --git a/hugo.yaml b/hugo.yaml
index 12b907c75..e52cf9a9e 100644
--- a/hugo.yaml
+++ b/hugo.yaml
@@ -98,73 +98,78 @@ menu:
weight: 10
- name: "Introduction"
parent: "Get Started"
- url: "{{VERSION}}/getting-started/introduction/"
+ url: "/intro"
weight: 11
- name: "Quickstart"
parent: "Get Started"
- url: "{{VERSION}}/getting-started/quickstart/"
+ url: "/quickstart"
weight: 12
- name: "Use Cases"
parent: "Get Started"
- url: "{{VERSION}}/getting-started/uses/"
+ url: "/uses"
weight: 13
- name: "Books and Papers"
parent: "Get Started"
- url: "/community/books_and_papers/"
+ url: "/books-and-papers"
weight: 14
- name: "Videos"
parent: "Get Started"
- url: "/community/videos/"
+ url: "/videos"
weight: 15
- name: "Podcasts"
parent: "Get Started"
- url: "/community/podcasts/"
+ url: "/podcasts"
weight: 16
# Docs menu
- name: "Docs"
- url: "{{VERSION}}"
+ url: "/documentation"
weight: 20
- name: "Key Concepts"
parent: "Docs"
- url: "{{VERSION}}/getting-started/"
+ url: "/documentation#gettingStarted"
weight: 21
- name: "APIs"
parent: "Docs"
- url: "{{VERSION}}/apis/"
+ url: "/documentation#api"
weight: 22
- name: "Configuration"
parent: "Docs"
- url: "{{VERSION}}/configuration/"
+ url: "/documentation#configuration"
weight: 23
- name: "Design"
parent: "Docs"
- url: "{{VERSION}}/design/"
+ url: "/documentation#design"
weight: 24
- name: "Implementation"
parent: "Docs"
- url: "{{VERSION}}/implementation/"
+ url: "/documentation#implementation"
weight: 25
- name: "Operations"
parent: "Docs"
- url: "{{VERSION}}/operations/"
+ url: "/documentation#operations"
weight: 26
- name: "Security"
+ identifier: "docs_security"
parent: "Docs"
- url: "{{VERSION}}/security/"
+ url: "/documentation#security"
weight: 27
- - name: "Kafka Connect"
+ - name: "Clients"
parent: "Docs"
- url: "{{VERSION}}/kafka-connect/"
+ url: "https://cwiki.apache.org/confluence/display/KAFKA/Clients"
weight: 28
- - name: "Kafka Streams"
+ - name: "Kafka Connect"
parent: "Docs"
- url: "{{VERSION}}/streams/"
+ url: "/documentation#connect"
weight: 29
+ - name: "Kafka Streams"
+ parent: "Docs"
+ url: "/documentation/streams"
+ weight: 30
# Powered By menu item
- name: "Powered By"
- url: "/testimonials/"
+ url: "/powered-by/"
weight: 35
# Community menu
@@ -181,7 +186,7 @@ menu:
weight: 42
- name: "Project Info"
parent: "Community"
- url: "/community/"
+ url: "/project/"
weight: 43
- name: "Trademark"
parent: "Community"
@@ -221,6 +226,7 @@ menu:
url: "https://www.apache.org/foundation/thanks.html"
weight: 54
- name: "Security"
+ identifier: "apache_security"
parent: "Apache"
url: "https://www.apache.org/security/"
weight: 55
@@ -240,25 +246,16 @@ params:
latest_version: "41"
latest_version_number: "4.1"
- # Favicon configuration
- favicon: /images/apache.png
-
- print:
- disable_toc: false
- taxonomy:
- # set taxonomyCloud = [] to hide taxonomy clouds
- taxonomyCloud: [tags, categories]
-
- # If used, must have same length as taxonomyCloud
- taxonomyCloudTitle: [Tag Cloud, Categories]
-
- # set taxonomyPageHeader = [] to hide taxonomies on the page headers
- taxonomyPageHeader: [tags, categories]
-
- privacy_policy:
https://privacy.apache.org/policies/privacy-policy-public.html
+ # The version number for the version of the docs represented in this doc set.
+ # Used in the "version-banner" partial to display a version number for the
+ # current doc set.
+ # NOTE: This is automatically set from latest_version_number parameter above
+ version: 4.1
- # First one is picked as the Twitter card image if not set on page.
- # images: [images/project-illustration.png]
+ # A link to latest version of the docs. Used in the "version-banner" partial
to
+ # point people to the main doc site.
+ # NOTE: When updating to version 42, change this to /42/
+ url_latest_version: /41/
# Menu title if your navbar has a versions selector to access old versions
of your site.
# This menu appears only if you have at least one [params.versions] set.
@@ -269,11 +266,6 @@ params:
# Set this flag to "true" if you want to display the banner.
archived_version: true
- # The version number for the version of the docs represented in this doc set.
- # Used in the "version-banner" partial to display a version number for the
- # current doc set.
- # NOTE: This is automatically set from latest_version_number parameter above
- version: 4.1
versions:
# NOTE: When adding version 42, update params.latest_version to "42"
# and params.latest_version_number to "4.2" at the top
@@ -372,11 +364,26 @@ params:
- version: "0.7"
url: /07/
archived_version: true
+
+ # Favicon configuration
+ favicon: /images/apache.png
+
+ print:
+ disable_toc: false
+ taxonomy:
+ # set taxonomyCloud = [] to hide taxonomy clouds
+ taxonomyCloud: [tags, categories]
- # A link to latest version of the docs. Used in the "version-banner" partial
to
- # point people to the main doc site.
- # NOTE: When updating to version 42, change this to /42/
- url_latest_version: /41/
+ # If used, must have same length as taxonomyCloud
+ taxonomyCloudTitle: [Tag Cloud, Categories]
+
+ # set taxonomyPageHeader = [] to hide taxonomies on the page headers
+ taxonomyPageHeader: [tags, categories]
+
+ privacy_policy:
https://privacy.apache.org/policies/privacy-policy-public.html
+
+ # First one is picked as the Twitter card image if not set on page.
+ # images: [images/project-illustration.png]
# Repository configuration (URLs for in-page links to opening issues and
suggesting changes)
github_repo: https://github.com/apache/kafka-site/
diff --git a/layouts/partials/hooks/body-end.html
b/layouts/partials/hooks/body-end.html
index ad3c4546f..db82fc8e3 100644
--- a/layouts/partials/hooks/body-end.html
+++ b/layouts/partials/hooks/body-end.html
@@ -8,15 +8,15 @@
{{ $stickySmart := resources.Get "js/sticky-smart.js" }}
{{ if $stickySmart }}
-<script src="{{ $stickySmart.Permalink }}"></script>
+<script src="{{ $stickySmart.RelPermalink }}"></script>
{{ end }}
{{ $sidebarToggle := resources.Get "js/sidebar-toggle.js" }}
{{ if $sidebarToggle }}
-<script src="{{ $sidebarToggle.Permalink }}"></script>
+<script src="{{ $sidebarToggle.RelPermalink }}"></script>
{{ end }}
{{ $tocScrollspy := resources.Get "js/toc-scrollspy.js" }}
{{ if $tocScrollspy }}
-<script src="{{ $tocScrollspy.Permalink }}"></script>
+<script src="{{ $tocScrollspy.RelPermalink }}"></script>
{{ end }}
\ No newline at end of file
diff --git a/layouts/shortcodes/doc-redirect.html
b/layouts/shortcodes/doc-redirect.html
new file mode 100644
index 000000000..eadd699b1
--- /dev/null
+++ b/layouts/shortcodes/doc-redirect.html
@@ -0,0 +1,117 @@
+<script>
+ (function () {
+ // 1. Get version from Hugo config
+ var latestVersion = "{{ .Site.Params.latest_version }}";
+
+ // 2. Define the Mapping
+ var hashIncludedMap = {
+ //Getting Started menu
+ "#gettingStarted": "getting-started",
+ "#introduction": "getting-started/introduction",
+ "#uses": "getting-started/uses",
+ "#quickstart": "getting-started/quickstart",
+ "#ecosystem": "getting-started/ecosystem",
+ "#upgrade": "getting-started/upgrade",
+ "#zk2kraft-summary": "getting-started/zk2kraft",
+ "#compatibility-summary": "getting-started/compatibility",
+ "#docker": "getting-started/docker",
+
+ //APIs menu
+ "#api": "apis",
+ "#producerapi": "apis/#producer-api",
+ "#consumerapi": "apis/#consumer-api",
+ "#shareconsumerapi": "apis/#share-consumer-api",
+ "#streamsapi": "apis/#streams-api",
+ "#connectapi": "apis/#connect-api",
+ "#adminapi": "apis/#admin-api",
+
+ //Configuration menu
+ "#configuration": "configuration",
+ "#brokerconfigs": "configuration/broker-configs/",
+ "#topicconfigs": "configuration/topic-configs/",
+ "#groupconfigs": "configuration/group-configs/",
+ "#producerconfigs": "configuration/producer-configs/",
+ "#consumerconfigs": "configuration/consumer-configs/",
+ "#connectconfigs": "configuration/kafka-connect-configs/",
+ "#sourceconnectconfigs":
"configuration/kafka-connect-configs/#source-connector-configs",
+ "#sinkconnectconfigs":
"configuration/kafka-connect-configs/#sink-connector-configs",
+ "#streamsconfigs": "configuration/kafka-streams-configs/",
+ "#adminclientconfigs": "configuration/admin-configs/",
+ "#mirrormakerconfigs": "configuration/mirrormaker-configs/",
+ "#systemproperties": "configuration/system-properties/",
+ "#tieredstorageconfigs": "configuration/tiered-storage-configs/",
+ "#config_providers": "configuration/configuration-providers/",
+
+ //Design menu
+ "#design": "design/design/",
+ "#majordesignelements": "design/design/#motivation",
+ "#persistence": "design/design/#persistence",
+ "#maximizingefficiency": "design/design/#efficiency",
+ "#theproducer": "design/design/#the-producer",
+ "#theconsumer": "design/design/#the-consumer",
+ "#semantics": "design/design/#message-delivery-semantics",
+ "#usingtransactions": "design/design/#using-transactions",
+ "#sharegroups": "design/design/#share-groups",
+ "#replication": "design/design/#replication",
+ "#compaction": "design/design/#log-compaction",
+ "#design_quotas": "design/design/#quotas",
+
+ //Implementation menu
+ "#implementation": "implementation",
+ "#networklayer": "implementation/network-layer/",
+ "#messages": "implementation/messages/",
+ "#messageformat": "implementation/message-format/",
+ "#log": "implementation/log/",
+ "#distributionimpl": "implementation/distribution/",
+
+ //Operations menu
+ "#operations": "operations",
+ "#basic_ops": "operations/basic-kafka-operations/",
+ "#datacenters": "operations/datacenters/",
+ "#georeplication":
"operations/geo-replication-cross-cluster-data-mirroring/",
+ "#multitenancy": "operations/multi-tenancy/",
+ "#java": "operations/java-version/",
+ "#hwandos": "operations/hardware-and-os/",
+ "#monitoring": "operations/monitoring/",
+ "#kraft": "operations/kraft/",
+ "#tiered_storage": "operations/tiered-storage/",
+ "#consumer_rebalance_protocol":
"operations/consumer-rebalance-protocol/",
+ "#transaction_protocol": "operations/transaction-protocol/",
+ "#eligible_leader_replicas":
"operations/eligible-leader-replicas/",
+
+ //Security menu
+ "#security": "security",
+ "#security_overview": "security/security-overview/",
+ "#listener_configuration": "security/listener-configuration/",
+ "#security_ssl":
"security/encryption-and-authentication-using-ssl/",
+ "#security_sasl": "security/authentication-using-sasl/",
+ "#security_authz": "security/authorization-and-acls/",
+ "#security_rolling_upgrade":
"security/incorporating-security-features-in-a-running-cluster/",
+
+ //Connect menu
+ "#connect": "kafka-connect",
+ "#connect_overview": "kafka-connect/overview/",
+ "#connect_user": "kafka-connect/user-guide/",
+ "#connect_development":
"kafka-connect/connector-development-guide/",
+ "#connect_administration": "kafka-connect/administration/",
+
+ //Streams menu
+ "#streams": "streams"
+
+ };
+
+ var currentHash = window.location.hash;
+
+ // 3. Logic:
+ // IF hash matches map -> Go to Deep Link
+ // ELSE -> Go to legitimate Docs Homepage
+
+ if (currentHash && hashIncludedMap[currentHash]) {
+ window.location.replace("/" + latestVersion + "/" +
hashIncludedMap[currentHash]);
+ } else {
+ // Default Fallback
+ window.location.replace("/" + latestVersion +
"/getting-started/introduction");
+ }
+ })();
+</script>
+<p>Redirecting...</p>
\ No newline at end of file
diff --git a/layouts/shortcodes/include-latest.html
b/layouts/shortcodes/include-latest.html
new file mode 100644
index 000000000..4a7b87b2f
--- /dev/null
+++ b/layouts/shortcodes/include-latest.html
@@ -0,0 +1,8 @@
+{{- $path := .Get "path" -}}
+{{- $latestVersion := site.Params.latest_version -}}
+{{- $fullPath := printf "/%s/%s" $latestVersion $path -}}
+{{- with site.GetPage $fullPath -}}
+{{ .Content }}
+{{- else -}}
+{{ errorf "Unable to find page at %q" $fullPath }}
+{{- end -}}
\ No newline at end of file
diff --git a/layouts/shortcodes/version-redirect.html
b/layouts/shortcodes/version-redirect.html
new file mode 100644
index 000000000..377419d68
--- /dev/null
+++ b/layouts/shortcodes/version-redirect.html
@@ -0,0 +1,11 @@
+{{/*
+Shortcode: version-redirect
+Description: Redirects to a path prefixed with the site's latest_version
parameter.
+Usage: {{< version-redirect path="design/protocol">}}
+ */}}
+ {{ $latest := site.Params.latest_version }}
+ {{ $path := .Get "path" }}
+ <script>
+ window.location.href = "\/" + "{{ $latest }}" + "\/" + "{{ $path }}";
+ </script>
+ <p>Redirecting to <a href="/{{ $latest }}/{{ $path }}">/{{ $latest }}/{{
$path }}</a>...</p>
\ No newline at end of file
diff --git a/layouts/simple/single.html b/layouts/simple/single.html
new file mode 100644
index 000000000..e9433a943
--- /dev/null
+++ b/layouts/simple/single.html
@@ -0,0 +1,31 @@
+{{ define "main" }}
+<section class="section">
+ <div class="container py-4" style="margin-top: 1rem;">
+ <div class="row justify-content-center">
+ <div class="col-lg-10">
+ <h1 class="mb-4">{{ .Title }}</h1>
+ <div class="td-content">
+ <style>
+ /* Force content to take full width of container */
+ .td-content {
+ max-width: 100%;
+ }
+
+ /* Force all children (paragraphs, headers) to fill
the container */
+ .td-content>* {
+ max-width: 100% !important;
+ }
+
+ /* Responsive images */
+ .td-content img {
+ max-width: 100%;
+ height: auto;
+ }
+ </style>
+ {{ .Content }}
+ </div>
+ </div>
+ </div>
+ </div>
+</section>
+{{ end }}
\ No newline at end of file
diff --git a/scripts/verify_redirects.py b/scripts/verify_redirects.py
new file mode 100644
index 000000000..b279783ee
--- /dev/null
+++ b/scripts/verify_redirects.py
@@ -0,0 +1,103 @@
+import re
+import sys
+import argparse
+from urllib.request import urlopen
+from urllib.error import HTTPError, URLError
+from urllib.parse import urljoin
+
+REDIRECT_FILE = '../layouts/shortcodes/doc-redirect.html'
+BASE_URL = 'http://localhost:1313/41/'
+
+def parse_redirects(file_path):
+ """Parses the JS object map from the shortcode file."""
+ try:
+ with open(file_path, 'r') as f:
+ content = f.read()
+ except FileNotFoundError:
+ print(f"Error: File {file_path} not found.")
+ sys.exit(1)
+
+ match = re.search(r'var hashIncludedMap = \{([\s\S]*?)\};', content)
+ if not match:
+ print(f"Error: Could not find hashIncludedMap in {file_path}")
+ return {}
+
+ map_content = match.group(1)
+ redirects = {}
+
+ # Regex to find key-value pairs: "#key": "value"
+ pattern = re.compile(r'"(#[^"]+)":\s*"([^"]+)"')
+
+ for line in map_content.splitlines():
+ m = pattern.search(line)
+ if m:
+ redirects[m.group(1)] = m.group(2)
+
+ return redirects
+
+def check_url(target_path):
+ """
+ Checks if the target path exists on the server using urllib.
+ Returns (status_code, anchor_found, error_msg)
+ """
+ path_part = target_path
+ anchor = None
+ if '#' in target_path:
+ path_part, anchor = target_path.split('#', 1)
+
+ url = urljoin(BASE_URL, path_part)
+
+ try:
+ with urlopen(url, timeout=2) as response:
+ status = response.getcode()
+ content = response.read().decode('utf-8', errors='ignore')
+
+ if anchor:
+ # Naive check for anchor in HTML
+ if f'id="{anchor}"' in content or f'name="{anchor}"' in
content:
+ return status, True, None
+ else:
+ return status, False, f"Anchor #{anchor} not found in page"
+
+ return status, True, None
+
+ except HTTPError as e:
+ return e.code, False, f"HTTP {e.code}"
+ except URLError as e:
+ return 0, False, f"Connection Failed: {e.reason}"
+ except Exception as e:
+ return 0, False, str(e)
+
+def main():
+ print(f"Parsing {REDIRECT_FILE}...")
+ redirects = parse_redirects(REDIRECT_FILE)
+ print(f"Found {len(redirects)} redirects.")
+
+ print(f"Checking against {BASE_URL}...")
+
+ success_count = 0
+ fail_count = 0
+ warning_count = 0
+
+ for key, target in redirects.items():
+ status, anchor_ok, msg = check_url(target)
+
+ if status == 200:
+ if anchor_ok:
+ print(f"[PASS] {key} -> {target}")
+ success_count += 1
+ else:
+ print(f"[WARN] {key} -> {target} (Page OK, {msg})")
+ warning_count += 1
+ else:
+ print(f"[FAIL] {key} -> {target} ({msg})")
+ fail_count += 1
+
+ print("-" * 30)
+ print(f"Summary: PASS={success_count}, WARN={warning_count},
FAIL={fail_count}")
+
+ if fail_count > 0:
+ sys.exit(1)
+
+if __name__ == "__main__":
+ main()