Skip to content

Commit 82bd2c7

Browse files
authored
fix: add canonical URL tag to default theme pages (#118)
1 parent 0f88355 commit 82bd2c7

2 files changed

Lines changed: 51 additions & 0 deletions

File tree

src/rockgarden/templates/components/meta.html

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -37,6 +37,7 @@
3737
{% else %}
3838
{% set _page_path = '/' + _slug + '.html' %}
3939
{% endif %}
40+
<link rel="canonical" href="{{ site.host_url }}{{ site.base_path }}{{ _page_path }}">
4041
<meta property="og:url" content="{{ site.host_url }}{{ site.base_path }}{{ _page_path }}">
4142
{% endif %}
4243

tests/test_urls.py

Lines changed: 50 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -350,6 +350,56 @@ def test_base_path_precedence_in_build_output(self, tmp_path):
350350
assert "/preview/_assets/rockgarden.css" in html
351351
assert "/production/_assets/" not in html
352352

353+
def test_canonical_and_og_url_explicit_base_path(self, tmp_path):
354+
source = tmp_path / "source"
355+
source.mkdir()
356+
(source / "about.md").write_text("# About\nHi")
357+
358+
output = tmp_path / "output"
359+
config = Config(
360+
site=SiteConfig(base_url="https://example.com", base_path="/2026")
361+
)
362+
363+
build_site(config, source, output)
364+
html = (output / "about" / "index.html").read_text()
365+
366+
expected = "https://example.com/2026/about/"
367+
assert f'<link rel="canonical" href="{expected}">' in html
368+
assert f'<meta property="og:url" content="{expected}">' in html
369+
370+
def test_canonical_and_og_url_path_in_base_url(self, tmp_path):
371+
# When the path is encoded in base_url and base_path is derived to
372+
# match, neither tag should double up the path.
373+
source = tmp_path / "source"
374+
source.mkdir()
375+
(source / "about.md").write_text("# About\nHi")
376+
377+
output = tmp_path / "output"
378+
config = Config(site=SiteConfig(base_url="https://example.com/docs"))
379+
380+
build_site(config, source, output)
381+
html = (output / "about" / "index.html").read_text()
382+
383+
expected = "https://example.com/docs/about/"
384+
assert f'<link rel="canonical" href="{expected}">' in html
385+
assert f'<meta property="og:url" content="{expected}">' in html
386+
assert "/docs/docs/" not in html
387+
388+
def test_canonical_and_og_url_no_base_url(self, tmp_path):
389+
# Without base_url there is no canonical absolute URL to emit.
390+
source = tmp_path / "source"
391+
source.mkdir()
392+
(source / "about.md").write_text("# About\nHi")
393+
394+
output = tmp_path / "output"
395+
config = Config()
396+
397+
build_site(config, source, output)
398+
html = (output / "about" / "index.html").read_text()
399+
400+
assert 'rel="canonical"' not in html
401+
assert 'property="og:url"' not in html
402+
353403
def test_base_path_rejects_single_quote(self):
354404
with pytest.raises(ValueError, match="invalid URL path characters"):
355405
SiteConfig(base_path="/my's-blog")

0 commit comments

Comments
 (0)