From 3fa4e09fe640a8fd0f7ea85a69b2bf3ef66aebb4 Mon Sep 17 00:00:00 2001 From: gregsadetsky Date: Fri, 10 Oct 2025 18:40:19 -0400 Subject: [PATCH 1/2] take article_url into account for articles and translated articles; fixes #32 --- .gitignore | 1 + pelican/plugins/sitemap/sitemap.py | 13 ++- .../plugins/sitemap/test_data/translated.md | 7 ++ .../sitemap/test_data/translated_fr.md | 7 ++ pelican/plugins/sitemap/test_sitemap.py | 79 +++++++++++++++++++ 5 files changed, 104 insertions(+), 3 deletions(-) create mode 100644 pelican/plugins/sitemap/test_data/translated.md create mode 100644 pelican/plugins/sitemap/test_data/translated_fr.md diff --git a/.gitignore b/.gitignore index 12568d5..b39e00a 100644 --- a/.gitignore +++ b/.gitignore @@ -1,2 +1,3 @@ .pdm-python pdm.lock +__pycache__/ diff --git a/pelican/plugins/sitemap/sitemap.py b/pelican/plugins/sitemap/sitemap.py index 01cdf8b..5324279 100644 --- a/pelican/plugins/sitemap/sitemap.py +++ b/pelican/plugins/sitemap/sitemap.py @@ -130,7 +130,14 @@ def is_excluded(item): or any(re.search(pattern, url) for pattern in excluded) ) - page_queue = [(clean_url(to_url(path)), obj) for path, obj in self.page_queue] + # Use obj.url for articles/pages to respect custom URL settings + # (e.g., ARTICLE_URL). Fall back to to_url(path) for index pages + # (archives, tags, etc.) which don't have a .url property as they're + # not Article or Page objects. + page_queue = [ + (clean_url(obj.url if obj else to_url(path)), obj) + for path, obj in self.page_queue + ] page_queue = [page for page in page_queue if not is_excluded(page)] page_queue.sort(key=lambda i: i[0]) @@ -174,12 +181,12 @@ def is_excluded(item): ) priority = priorities[content_type] + # Use trans.url to respect custom URL settings for translations too translations = "".join( XML_TRANSLATION.format( trans.lang, siteurl, - # save_as path is already output-relative - clean_url(pathname2url(trans.save_as)), + clean_url(trans.url), ) for trans in getattr(obj, "translations", ()) ) diff --git a/pelican/plugins/sitemap/test_data/translated.md b/pelican/plugins/sitemap/test_data/translated.md new file mode 100644 index 0000000..3ae2f39 --- /dev/null +++ b/pelican/plugins/sitemap/test_data/translated.md @@ -0,0 +1,7 @@ +Title: Translated Post +Date: 2023-07-12 13:00:00 +Category: test +Lang: en +Slug: translated-post + +This is an English article with a French translation. diff --git a/pelican/plugins/sitemap/test_data/translated_fr.md b/pelican/plugins/sitemap/test_data/translated_fr.md new file mode 100644 index 0000000..adef691 --- /dev/null +++ b/pelican/plugins/sitemap/test_data/translated_fr.md @@ -0,0 +1,7 @@ +Title: Article Traduit +Date: 2023-07-12 13:00:00 +Category: test +Lang: fr +Slug: translated-post + +Ceci est un article français. diff --git a/pelican/plugins/sitemap/test_sitemap.py b/pelican/plugins/sitemap/test_sitemap.py index 09f84fd..3380ac0 100644 --- a/pelican/plugins/sitemap/test_sitemap.py +++ b/pelican/plugins/sitemap/test_sitemap.py @@ -54,6 +54,8 @@ def test_txt(self): http://localhost/tags.html http://localhost/test-post-daily.html http://localhost/test-post.html +http://localhost/translated-post-fr.html +http://localhost/translated-post.html """ self.assertEqual(expected, contents) @@ -80,3 +82,80 @@ def test_xml(self): """ self.assertIn(needle, contents) + + def test_custom_article_url(self): + """Test that custom ARTICLE_URL settings are respected in sitemap.""" + settings = read_settings( + override={ + "PATH": TEST_DATA, + "CACHE_CONTENT": False, + "SITEURL": "http://localhost", + "OUTPUT_PATH": self.output_path, + "PLUGINS": [sitemap], + "SITEMAP": { + "format": "txt", + }, + # Custom URL settings like a user might have + "ARTICLE_URL": "blog/{slug}/", + "ARTICLE_SAVE_AS": "{slug}/index.html", + } + ) + pelican = Pelican(settings=settings) + pelican.run() + + with open(Path(self.output_path) / "sitemap.txt") as fd: + contents = fd.read() + + # Articles should use ARTICLE_URL (blog/{slug}/), + # not ARTICLE_SAVE_AS ({slug}/index.html) + self.assertIn("http://localhost/blog/test-post/", contents) + self.assertIn("http://localhost/blog/test-post-daily/", contents) + # Should NOT contain the filesystem paths + self.assertNotIn("http://localhost/test-post/", contents) + self.assertNotIn("http://localhost/test-post-daily/", contents) + + def test_translations_in_sitemap(self): + """Test that translation links use trans.url and appear in sitemap.""" + self._run_pelican(sitemap_format="xml") + with open(Path(self.output_path) / "sitemap.xml") as fd: + contents = fd.read() + + # Verify translation alternate links exist + self.assertIn(' Date: Fri, 10 Oct 2025 18:47:47 -0400 Subject: [PATCH 2/2] add test for pages respecting page_url --- .../plugins/sitemap/test_data/pages/about.md | 4 +++ pelican/plugins/sitemap/test_sitemap.py | 34 +++++++++++++++++-- 2 files changed, 35 insertions(+), 3 deletions(-) create mode 100644 pelican/plugins/sitemap/test_data/pages/about.md diff --git a/pelican/plugins/sitemap/test_data/pages/about.md b/pelican/plugins/sitemap/test_data/pages/about.md new file mode 100644 index 0000000..98ecca4 --- /dev/null +++ b/pelican/plugins/sitemap/test_data/pages/about.md @@ -0,0 +1,4 @@ +Title: About Us +Status: published + +This is a test page for the about section. diff --git a/pelican/plugins/sitemap/test_sitemap.py b/pelican/plugins/sitemap/test_sitemap.py index 3380ac0..c0653e4 100644 --- a/pelican/plugins/sitemap/test_sitemap.py +++ b/pelican/plugins/sitemap/test_sitemap.py @@ -48,6 +48,7 @@ def test_txt(self): http://localhost/authors.html http://localhost/categories.html http://localhost/category/test.html +http://localhost/pages/about-us.html http://localhost/tag/bar.html http://localhost/tag/foo.html http://localhost/tag/foobar.html @@ -153,9 +154,36 @@ def test_translations_with_custom_article_url(self): contents = fd.read() # Verify translation link for English uses custom ARTICLE_URL - self.assertIn( - 'ref="http://localhost/blog/translated-post/"', contents - ) + self.assertIn('ref="http://localhost/blog/translated-post/"', contents) # Verify the French translation is also in sitemap # (French uses ARTICLE_LANG_URL which defaults differently) self.assertIn("translated-post-fr", contents) + + def test_custom_page_url(self): + """Test that custom PAGE_URL settings are respected in sitemap.""" + settings = read_settings( + override={ + "PATH": TEST_DATA, + "CACHE_CONTENT": False, + "SITEURL": "http://localhost", + "OUTPUT_PATH": self.output_path, + "PLUGINS": [sitemap], + "SITEMAP": { + "format": "txt", + }, + # Custom URL settings for pages + "PAGE_URL": "pages/{slug}/", + "PAGE_SAVE_AS": "p/{slug}/index.html", + } + ) + pelican = Pelican(settings=settings) + pelican.run() + + with open(Path(self.output_path) / "sitemap.txt") as fd: + contents = fd.read() + + # Pages should use PAGE_URL (pages/{slug}/), + # not PAGE_SAVE_AS (p/{slug}/index.html) + self.assertIn("http://localhost/pages/about-us/", contents) + # Should NOT contain the filesystem path + self.assertNotIn("http://localhost/p/about-us/", contents)