You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@grails.apache.org by ja...@apache.org on 2026/05/03 01:57:18 UTC
(grails-static-website) branch fix-ogurl-metadata-in-plugin-blog-archive-pages created (now fd20076cb7d)
This is an automated email from the ASF dual-hosted git repository.
jamesfredley pushed a change to branch fix-ogurl-metadata-in-plugin-blog-archive-pages
in repository https://gitbox.apache.org/repos/asf/grails-static-website.git
at fd20076cb7d Set [%ogurl] metadata on plugins, blog-archive, blog-tag, and minutes pages
This branch includes the following new commits:
new fd20076cb7d Set [%ogurl] metadata on plugins, blog-archive, blog-tag, and minutes pages
The 1 revisions listed above as "new" are entirely new to this
repository and will be described in separate emails. The revisions
listed as "add" were already present in the repository and have only
been added to this reference.
(grails-static-website) 01/01: Set [%ogurl] metadata on plugins, blog-archive, blog-tag, and minutes pages
Posted by ja...@apache.org.
This is an automated email from the ASF dual-hosted git repository.
jamesfredley pushed a commit to branch fix-ogurl-metadata-in-plugin-blog-archive-pages
in repository https://gitbox.apache.org/repos/asf/grails-static-website.git
commit fd20076cb7dd143a3e15a628082de147bc7ce823
Author: James Fredley <ja...@users.noreply.github.com>
AuthorDate: Sat May 2 21:57:10 2026 -0400
Set [%ogurl] metadata on plugins, blog-archive, blog-tag, and minutes pages
The site-wide template at templates/document.html embeds a per-page
Open Graph URL via <meta property="og:url" content="[%ogurl]"/>.
Substitution happens in RenderSiteTask.replaceLineWithMetadata only
when the metadata map handed to renderHtmlWithTemplateContent contains
a non-null `ogurl` key.
Three rendering paths never set ogurl, so every page they emit ships
the literal "[%ogurl]" token in the og:url meta tag. The defect is
visible right now on https://grails.apache.org/plugins.html and on
https://grails.apache.org/blog/index.html, and it propagates to every
plugins/tags/<tag>.html, plugins/owners/<owner>.html,
blog/tag/<tag>.html, and minutes page.
Sibling rendering paths already set ogurl correctly (RenderSiteTask
sets it from siteMeta['url'] + page.path; BlogTask.renderPostHtml sets
it via postLink), so this change is just bringing the broken paths in
line with the working ones.
Changes:
PluginsTask.renderHtml:
The base metadata map was reused across the main page and every
tag/owner page, which meant we couldn't simply set ogurl on it - we
need a per-page value. Reshape the wrap closure to accept the
per-page ogurl, copy the metadata into a fresh LinkedHashMap, set
ogurl on the copy, then render. Three call sites updated:
- plugins.html -> <siteUrl>/plugins.html
- plugins/tags/<tag>.html -> <siteUrl>/plugins/tags/<tag>.html
- plugins/owners/<slug>.html -> <siteUrl>/plugins/owners/<slug>.html
Owner slug computation hoisted into a local so the file path and the
ogurl URL agree.
BlogTask.renderArchive:
Set ogurl on the resolved metadata (mutating the .tap{} block) to
<siteUrl>/blog/index.html.
BlogTask.renderTags:
Per-tag ogurl already lives in the LinkedHashMap.tap{} block that
customises the title for each tag page; add ogurl =
<siteUrl>/blog/tag/<tag>.html alongside the title.
MinutesTask.renderArchive:
Set ogurl on the resolved metadata to
<siteUrl>/foundation/minutes/index.html.
MinutesTask.renderMinutesHtml:
Set ogurl from minutesLink(htmlMinutes) before
renderHtmlWithTemplateContent. minutesLink returns
<siteUrl>/foundation/minutes/<htmlMinutes.path>.
Verification (./gradlew clean build):
- 502 .html files in build/dist/: 0 unresolved [%ogurl] tokens
(was 364 across plugins/blog/tag/owner pages on the live site).
- Spot checks confirmed each page emits its own correct og:url:
plugins.html -> /plugins.html
blog/index.html -> /blog/index.html
blog/tag/groovy.html -> /blog/tag/groovy.html
plugins/tags/rest.html -> /plugins/tags/rest.html
plugins/owners/virtualdogbert.html -> /plugins/owners/virtualdogbert.html
foundation/minutes/20210321-tab.html
-> /foundation/minutes/20210321-tab.html
- Regression: pages from RenderSiteTask (index, community, download,
faq, support) and individual blog posts still emit their pre-existing
correct og:url meta tags.
Assisted-by: claude-code:claude-opus-4-7
---
.../groovy/website/gradle/tasks/BlogTask.groovy | 9 ++++++
.../groovy/website/gradle/tasks/MinutesTask.groovy | 10 +++++++
.../groovy/website/gradle/tasks/PluginsTask.groovy | 33 ++++++++++++++++------
3 files changed, 44 insertions(+), 8 deletions(-)
diff --git a/buildSrc/src/main/groovy/website/gradle/tasks/BlogTask.groovy b/buildSrc/src/main/groovy/website/gradle/tasks/BlogTask.groovy
index 7fd69f78c99..80370c704b5 100644
--- a/buildSrc/src/main/groovy/website/gradle/tasks/BlogTask.groovy
+++ b/buildSrc/src/main/groovy/website/gradle/tasks/BlogTask.groovy
@@ -359,6 +359,10 @@ abstract class BlogTask extends GrailsWebsiteTask {
tagCards,
new LinkedHashMap(meta).tap {
it.title = tag.toUpperCase() + ' | Blog | Grails Framework'
+ // Per-tag Open Graph URL. Without this the [%ogurl]
+ // token in templates/document.html ships verbatim on
+ // every blog/tag/<tag>.html page.
+ it.ogurl = "${it.url}/$BLOG/$TAG/${tag}.html".toString()
},
templateText,
renderTagTitle(tag)
@@ -407,6 +411,11 @@ abstract class BlogTask extends GrailsWebsiteTask {
) {
def meta = RenderSiteTask.processMetadata(siteMeta).tap {
it.title = 'Blog | Grails Framework'
+ // [%ogurl] is the per-page Open Graph URL token in
+ // templates/document.html. The blog archive index lives at
+ // <siteUrl>/blog/index.html; without this the rendered HTML
+ // shipped the literal [%ogurl] in the og:url meta tag.
+ it.ogurl = "${it.url}/$BLOG/$INDEX".toString()
}
def html = cardsHtml(postCards)
html = RenderSiteTask.renderHtmlWithTemplateContent(html, meta, templateText)
diff --git a/buildSrc/src/main/groovy/website/gradle/tasks/MinutesTask.groovy b/buildSrc/src/main/groovy/website/gradle/tasks/MinutesTask.groovy
index cb06ad96092..8b081dc67d7 100644
--- a/buildSrc/src/main/groovy/website/gradle/tasks/MinutesTask.groovy
+++ b/buildSrc/src/main/groovy/website/gradle/tasks/MinutesTask.groovy
@@ -213,6 +213,10 @@ abstract class MinutesTask extends GrailsWebsiteTask {
def html = writer.toString()
def metadata = htmlMinutes.metadata.toMap()
+ // Per-page Open Graph URL. Without this the [%ogurl] token in
+ // templates/document.html ships verbatim on every rendered minutes
+ // page. minutesLink() resolves to "<siteUrl>/foundation/minutes/<path>".
+ metadata['ogurl'] = minutesLink(htmlMinutes)
html = RenderSiteTask.renderHtmlWithTemplateContent(html, metadata, templateText)
html = RenderSiteTask.highlightMenu(html, metadata, htmlMinutes.path)
metadata['bodyClassAttr'] = metadata['bodyClassAttr'] ?: 'foundation minutes'
@@ -319,6 +323,12 @@ abstract class MinutesTask extends GrailsWebsiteTask {
def html = cardsHtml(minuteCards.toList())
def resolvedMetadata = RenderSiteTask.processMetadata(siteMeta).tap {
it.title = 'Foundation | Grails Framework'
+ // [%ogurl] is the per-page Open Graph URL token in
+ // templates/document.html. The minutes archive lives at
+ // <siteUrl>/foundation/minutes/index.html; without this the
+ // rendered HTML shipped the literal [%ogurl] in the og:url
+ // meta tag.
+ it.ogurl = "${it.url}/$MINUTES/$INDEX".toString()
}
html = RenderSiteTask.renderHtmlWithTemplateContent(html, resolvedMetadata, templateText)
html = RenderSiteTask.highlightMenu(html, resolvedMetadata, "/$MINUTES/$INDEX")
diff --git a/buildSrc/src/main/groovy/website/gradle/tasks/PluginsTask.groovy b/buildSrc/src/main/groovy/website/gradle/tasks/PluginsTask.groovy
index 9a8dbccb7ea..5c2be2d2cf0 100644
--- a/buildSrc/src/main/groovy/website/gradle/tasks/PluginsTask.groovy
+++ b/buildSrc/src/main/groovy/website/gradle/tasks/PluginsTask.groovy
@@ -116,12 +116,25 @@ abstract class PluginsTask extends GrailsWebsiteTask {
def pluginsTagsDir = outputDir.dir('dist/plugins/tags').get().asFile.tap { mkdirs() }
def pluginsOwnersDir = outputDir.dir('dist/plugins/owners').get().asFile.tap { mkdirs() }
- def wrap = { String html -> RenderSiteTask.renderHtmlWithTemplateContent(html, metadata, templateText) }
+ // [%ogurl] is the per-page Open Graph URL token in templates/document.html.
+ // The base metadata map is shared across the main page and every tag/owner
+ // page, so we need to thread a per-page ogurl through wrap() rather than
+ // reusing the same metadata map; otherwise every rendered page would ship
+ // the same og:url meta tag (or, as on the live site today, the literal
+ // [%ogurl] token).
+ def wrap = { String html, String ogurl ->
+ def pageMetadata = new LinkedHashMap<String, String>(metadata)
+ pageMetadata['ogurl'] = ogurl
+ RenderSiteTask.renderHtmlWithTemplateContent(html, pageMetadata, templateText)
+ }
// main plugins page
new File(distDir, fileName).setText(
RenderSiteTask.highlightMenu(
- wrap(PluginsPage.mainContent(siteUrl, plugins, 'Grails Plugins', null)),
+ wrap(
+ PluginsPage.mainContent(siteUrl, plugins, 'Grails Plugins', null),
+ "${siteUrl}/plugins.html".toString()
+ ),
metadata,
'/plugins.html'
),
@@ -134,7 +147,10 @@ abstract class PluginsTask extends GrailsWebsiteTask {
.unique()
.each { tag ->
new File(pluginsTagsDir, "${tag}.html").setText(
- wrap(renderHtmlPagesForTags(siteUrl, plugins, tag)),
+ wrap(
+ renderHtmlPagesForTags(siteUrl, plugins, tag),
+ "${siteUrl}/plugins/tags/${tag}.html".toString()
+ ),
'UTF-8'
)
}
@@ -145,11 +161,12 @@ abstract class PluginsTask extends GrailsWebsiteTask {
.findAll { it }
.unique()
.each { owner ->
- new File(
- pluginsOwnersDir,
- "${owner.replace(' ', '').toLowerCase()}.html"
- ).setText(
- wrap(renderHtmlPagesForOwners(siteUrl, plugins, owner)),
+ def ownerSlug = owner.replace(' ', '').toLowerCase()
+ new File(pluginsOwnersDir, "${ownerSlug}.html").setText(
+ wrap(
+ renderHtmlPagesForOwners(siteUrl, plugins, owner),
+ "${siteUrl}/plugins/owners/${ownerSlug}.html".toString()
+ ),
'UTF-8'
)
}