diff --git a/crates/zensical/src/compat/mkdocs/plugin/blog.rs b/crates/zensical/src/compat/mkdocs/plugin/blog.rs index d0b72fc..1648c2a 100644 --- a/crates/zensical/src/compat/mkdocs/plugin/blog.rs +++ b/crates/zensical/src/compat/mkdocs/plugin/blog.rs @@ -103,7 +103,7 @@ pub struct Patch { pub navigation_url: Option, /// Explicit hidden-page siblings, when the page isn't a visible item. pub siblings: Option<(Option, Option)>, - /// View template applied after revision-complete view classification. + /// Default view template used only when page metadata does not choose one. pub template: Option, /// View table of contents after optional excerpt integration. pub toc: Option>, @@ -1197,7 +1197,8 @@ impl Blog { } _ => BTreeMap::new(), }; - meta.insert("template".into(), Dynamic::String("blog.html".into())); + meta.entry("template".into()) + .or_insert_with(|| Dynamic::String("blog.html".into())); let document = DocumentHeader::new(source.clone(), body, meta); let route = PageRoute::from_source(&self.config, source)?; Ok(PageDescriptor::generated( diff --git a/crates/zensical/src/structure/page.rs b/crates/zensical/src/structure/page.rs index fc7bf45..1fed62a 100644 --- a/crates/zensical/src/structure/page.rs +++ b/crates/zensical/src/structure/page.rs @@ -530,11 +530,13 @@ impl Page { self.navigation_siblings = Some((previous, next)); } - /// Applies a module-selected page template after view classification. - pub(crate) fn apply_template(&mut self, template: String) { - Arc::make_mut(&mut self.data) - .markdown - .insert_meta("template".into(), Dynamic::String(template)); + /// Applies a view template only when page metadata does not choose one. + pub(crate) fn apply_default_template(&mut self, template: String) { + if !self.meta.contains_key("template") { + Arc::make_mut(&mut self.data) + .markdown + .insert_meta("template".into(), Dynamic::String(template)); + } } /// Applies the title assigned to this page by navigation. diff --git a/crates/zensical/src/workflow.rs b/crates/zensical/src/workflow.rs index 6741dc2..af72caf 100644 --- a/crates/zensical/src/workflow.rs +++ b/crates/zensical/src/workflow.rs @@ -454,7 +454,7 @@ fn apply_blog( ); } if let Some(template) = &patch.template { - rendered.page.apply_template(template.clone()); + rendered.page.apply_default_template(template.clone()); } if patch.content.is_some() || patch.toc.is_some() { rendered.page.apply_derived( diff --git a/python/tests/integration/test_blog.py b/python/tests/integration/test_blog.py index 33f21ba..c2dcef4 100644 --- a/python/tests/integration/test_blog.py +++ b/python/tests/integration/test_blog.py @@ -289,6 +289,33 @@ def test_paginated_blog_pages_are_generated_without_source_files( assert "|PREV=blog/2026/09/01/one/|NEXT=" in two +def test_blog_entrypoint_template_applies_to_paginated_pages( + tmp_path: Path, +) -> None: + config = _project(tmp_path, per_page=1, archive=True) + (tmp_path / "docs/blog/index.md").write_text( + "---\ntitle: Journal\ntemplate: landing.html\n---\n# Journal\n", + encoding="utf-8", + ) + (tmp_path / "overrides/landing.html").write_text( + "LANDING|{{ page.title }}|{{ page.url }}", + encoding="utf-8", + ) + _post(tmp_path, "one.md", "One", "2026-09-01") + _post(tmp_path, "two.md", "Two", "2026-09-02") + + zensical.build(str(config), _BUILD_OPTIONS) + + site = tmp_path / "site/blog" + assert "LANDING|Journal|blog/" in (site / "index.html").read_text("utf-8") + assert "LANDING|Journal|blog/page/2/" in ( + site / "page/2/index.html" + ).read_text("utf-8") + assert "BLOG|2026|" in ( + site / "archive/2026/index.html" + ).read_text("utf-8") + + def test_single_page_keeps_empty_pagination_context(tmp_path: Path) -> None: config = _project(tmp_path) _post(tmp_path, "one.md", "One", "2026-09-01")