Add lang, taxonomy and term to feed template

Also a FIXME on the rebuilding part, because it’s presently very wrong.
This commit is contained in:
Chris Morgan 2020-04-03 13:06:30 +05:30
parent eb7751955a
commit 4653e68715
7 changed files with 89 additions and 12 deletions

View file

@ -16,6 +16,8 @@
### Other ### Other
- Add `updated` front-matter field for pages, which sitemap templates will use for the `SitemapEntry.date` field instead of the `date` front-matter field, and which the default Atom feed template will use - Add `updated` front-matter field for pages, which sitemap templates will use for the `SitemapEntry.date` field instead of the `date` front-matter field, and which the default Atom feed template will use
- Add `lang` to the feed template context
- Add `taxonomy` and `term` to the feed template context for taxonomy feeds
## 0.10.2 (unreleased) ## 0.10.2 (unreleased)

View file

@ -396,7 +396,15 @@ pub fn after_template_change(site: &mut Site, path: &Path) -> Result<()> {
match filename { match filename {
"sitemap.xml" => site.render_sitemap(), "sitemap.xml" => site.render_sitemap(),
filename if filename == site.config.feed_filename => { filename if filename == site.config.feed_filename => {
site.render_feed(site.library.read().unwrap().pages_values(), None) // FIXME: this is insufficient; for multilingual sites, its rendering the wrong
// content into the root feed, and its not regenerating any of the other feeds (other
// languages or taxonomies with feed enabled).
site.render_feed(
site.library.read().unwrap().pages_values(),
None,
&site.config.default_language,
None,
)
} }
"split_sitemap_index.xml" => site.render_sitemap(), "split_sitemap_index.xml" => site.render_sitemap(),
"robots.txt" => site.render_robots(), "robots.txt" => site.render_robots(),

View file

@ -40,7 +40,14 @@ fn bench_render_feed(b: &mut test::Bencher) {
let tmp_dir = tempdir().expect("create temp dir"); let tmp_dir = tempdir().expect("create temp dir");
let public = &tmp_dir.path().join("public"); let public = &tmp_dir.path().join("public");
site.set_output_path(&public); site.set_output_path(&public);
b.iter(|| site.render_feed(site.library.read().unwrap().pages_values(), None).unwrap()); b.iter(|| {
site.render_feed(
site.library.read().unwrap().pages_values(),
None,
&site.config.default_language,
None,
).unwrap();
});
} }
#[bench] #[bench]

View file

@ -8,13 +8,15 @@ use std::sync::{Arc, Mutex, RwLock};
use glob::glob; use glob::glob;
use rayon::prelude::*; use rayon::prelude::*;
use sass_rs::{compile_file, Options as SassOptions, OutputStyle}; use sass_rs::{compile_file, Options as SassOptions, OutputStyle};
use serde_derive::Serialize;
use tera::{Context, Tera}; use tera::{Context, Tera};
use config::{get_config, Config}; use config::{get_config, Config, Taxonomy as TaxonomyConfig};
use errors::{bail, Error, ErrorKind, Result}; use errors::{bail, Error, ErrorKind, Result};
use front_matter::InsertAnchor; use front_matter::InsertAnchor;
use library::{ use library::{
find_taxonomies, sort_actual_pages_by_date, Library, Page, Paginator, Section, Taxonomy, find_taxonomies, sort_actual_pages_by_date, Library, Page, Paginator, Section, Taxonomy,
TaxonomyItem,
}; };
use link_checker::check_url; use link_checker::check_url;
use templates::{global_fns, render_redirect_template, ZOLA_TERA}; use templates::{global_fns, render_redirect_template, ZOLA_TERA};
@ -45,6 +47,23 @@ pub struct Site {
include_drafts: bool, include_drafts: bool,
} }
#[derive(Debug, Clone, PartialEq, Serialize)]
struct SerializedTaxonomyItem<'a> {
name: &'a str,
slug: &'a str,
permalink: &'a str,
}
impl<'a> SerializedTaxonomyItem<'a> {
pub fn from_item(item: &'a TaxonomyItem) -> Self {
SerializedTaxonomyItem {
name: &item.name,
slug: &item.slug,
permalink: &item.permalink,
}
}
}
impl Site { impl Site {
/// Parse a site at the given path. Defaults to the current dir /// Parse a site at the given path. Defaults to the current dir
/// Passing in a path is used in tests and when --root argument is passed /// Passing in a path is used in tests and when --root argument is passed
@ -746,7 +765,8 @@ impl Site {
let library = self.library.read().unwrap(); let library = self.library.read().unwrap();
if self.config.generate_feed { if self.config.generate_feed {
let pages = if self.config.is_multilingual() { let is_multilingual = self.config.is_multilingual();
let pages = if is_multilingual {
library library
.pages_values() .pages_values()
.iter() .iter()
@ -756,7 +776,12 @@ impl Site {
} else { } else {
library.pages_values() library.pages_values()
}; };
self.render_feed(pages, None)?; self.render_feed(
pages,
None,
&self.config.default_language,
None,
)?;
} }
for lang in &self.config.languages { for lang in &self.config.languages {
@ -765,7 +790,12 @@ impl Site {
} }
let pages = let pages =
library.pages_values().iter().filter(|p| p.lang == lang.code).cloned().collect(); library.pages_values().iter().filter(|p| p.lang == lang.code).cloned().collect();
self.render_feed(pages, Some(&PathBuf::from(lang.code.clone())))?; self.render_feed(
pages,
Some(&PathBuf::from(lang.code.clone())),
&lang.code,
None,
)?;
} }
self.render_404()?; self.render_404()?;
@ -987,6 +1017,12 @@ impl Site {
self.render_feed( self.render_feed(
item.pages.iter().map(|p| library.get_page_by_key(*p)).collect(), item.pages.iter().map(|p| library.get_page_by_key(*p)).collect(),
Some(&PathBuf::from(format!("{}/{}", taxonomy.kind.name, item.slug))), Some(&PathBuf::from(format!("{}/{}", taxonomy.kind.name, item.slug))),
if self.config.is_multilingual() && !taxonomy.kind.lang.is_empty() {
&taxonomy.kind.lang
} else {
&self.config.default_language
},
Some((&taxonomy.kind, &item)),
) )
} else { } else {
Ok(()) Ok(())
@ -1052,6 +1088,8 @@ impl Site {
&self, &self,
all_pages: Vec<&Page>, all_pages: Vec<&Page>,
base_path: Option<&PathBuf>, base_path: Option<&PathBuf>,
lang: &str,
taxonomy_and_item: Option<(&TaxonomyConfig, &TaxonomyItem)>,
) -> Result<()> { ) -> Result<()> {
ensure_directory_exists(&self.output_path)?; ensure_directory_exists(&self.output_path)?;
@ -1084,6 +1122,7 @@ impl Site {
context.insert("pages", &p); context.insert("pages", &p);
context.insert("config", &self.config); context.insert("config", &self.config);
context.insert("lang", lang);
let feed_filename = &self.config.feed_filename; let feed_filename = &self.config.feed_filename;
let feed_url = if let Some(ref base) = base_path { let feed_url = if let Some(ref base) = base_path {
@ -1099,6 +1138,11 @@ impl Site {
context.insert("feed_url", &feed_url); context.insert("feed_url", &feed_url);
if let Some((taxonomy, item)) = taxonomy_and_item {
context.insert("taxonomy", taxonomy);
context.insert("term", &SerializedTaxonomyItem::from_item(item));
}
let feed = &render_template(feed_filename, &self.tera, context, &self.config.theme)?; let feed = &render_template(feed_filename, &self.tera, context, &self.config.theme)?;
if let Some(ref base) = base_path { if let Some(ref base) = base_path {

View file

@ -119,9 +119,11 @@ fn can_build_multilingual_site() {
assert!(file_exists!(public, "atom.xml")); assert!(file_exists!(public, "atom.xml"));
assert!(file_contains!(public, "atom.xml", "https://example.com/blog/something-else/")); assert!(file_contains!(public, "atom.xml", "https://example.com/blog/something-else/"));
assert!(!file_contains!(public, "atom.xml", "https://example.com/fr/blog/something-else/")); assert!(!file_contains!(public, "atom.xml", "https://example.com/fr/blog/something-else/"));
assert!(file_contains!(public, "atom.xml", r#"<feed xmlns="http://www.w3.org/2005/Atom" xml:lang="en">"#));
assert!(file_exists!(public, "fr/atom.xml")); assert!(file_exists!(public, "fr/atom.xml"));
assert!(!file_contains!(public, "fr/atom.xml", "https://example.com/blog/something-else/")); assert!(!file_contains!(public, "fr/atom.xml", "https://example.com/blog/something-else/"));
assert!(file_contains!(public, "fr/atom.xml", "https://example.com/fr/blog/something-else/")); assert!(file_contains!(public, "fr/atom.xml", "https://example.com/fr/blog/something-else/"));
assert!(file_contains!(public, "fr/atom.xml", r#"<feed xmlns="http://www.w3.org/2005/Atom" xml:lang="fr">"#));
// Italian doesn't have feed enabled // Italian doesn't have feed enabled
assert!(!file_exists!(public, "it/atom.xml")); assert!(!file_exists!(public, "it/atom.xml"));
@ -132,6 +134,8 @@ fn can_build_multilingual_site() {
assert!(!file_contains!(public, "authors/index.html", "Vincent")); assert!(!file_contains!(public, "authors/index.html", "Vincent"));
assert!(!file_exists!(public, "auteurs/index.html")); assert!(!file_exists!(public, "auteurs/index.html"));
assert!(file_exists!(public, "authors/queen-elizabeth/atom.xml")); assert!(file_exists!(public, "authors/queen-elizabeth/atom.xml"));
assert!(file_contains!(public, "authors/queen-elizabeth/atom.xml", r#"<feed xmlns="http://www.w3.org/2005/Atom" xml:lang="en">"#));
assert!(file_contains!(public, "authors/queen-elizabeth/atom.xml", r#"<title> - Queen Elizabeth</title>"#));
assert!(file_exists!(public, "tags/index.html")); assert!(file_exists!(public, "tags/index.html"));
assert!(file_contains!(public, "tags/index.html", "hello")); assert!(file_contains!(public, "tags/index.html", "hello"));

View file

@ -1,6 +1,9 @@
<?xml version="1.0" encoding="UTF-8"?> <?xml version="1.0" encoding="UTF-8"?>
<feed xmlns="http://www.w3.org/2005/Atom" xml:lang="{{ config.default_language }}"> <feed xmlns="http://www.w3.org/2005/Atom" xml:lang="{{ lang }}">
<title>{{ config.title }}</title> <title>{{ config.title }}
{%- if term %} - {{ term.name }}
{%- endif -%}
</title>
{%- if config.description %} {%- if config.description %}
<subtitle>{{ config.description }}</subtitle> <subtitle>{{ config.description }}</subtitle>
{%- endif %} {%- endif %}
@ -11,7 +14,7 @@
<id>{{ feed_url | safe }}</id> <id>{{ feed_url | safe }}</id>
{%- for page in pages %} {%- for page in pages %}
<entry <entry
{%- if page.lang != config.default_language %} xml:lang="{{ page.lang }}"{% endif -%} {%- if page.lang != lang %} xml:lang="{{ page.lang }}"{% endif -%}
> >
<title>{{ page.title }}</title> <title>{{ page.title }}</title>
<published>{{ page.date | date(format="%+") }}</published> <published>{{ page.date | date(format="%+") }}</published>

View file

@ -17,9 +17,18 @@ need to provide a template yourself.
**Only pages with a date will be available.** **Only pages with a date will be available.**
The feed template gets three variables in addition to `config`: The feed template gets five variables:
- `config`: the site config
- `feed_url`: the full url to that specific feed - `feed_url`: the full url to that specific feed
- `last_updated`: the most recent `updated` or `date` field of any post - `last_updated`: the most recent `updated` or `date` field of any post
- `pages`: see [page variables](@/documentation/templates/pages-sections.md#page-variables) for - `pages`: see [page variables](@/documentation/templates/pages-sections.md#page-variables)
a detailed description of what this contains for a detailed description of what this contains
- `lang`: the language code that applies to all of the pages in the feed,
if the site is multilingual, or `config.default_language` if it is not
Feeds for taxonomy terms get two more variables, using types from the
[taxonomies templates](@/documentation/templates/taxonomies.md):
- `taxonomy`: of type `TaxonomyConfig`
- `term`: of type `TaxonomyTerm`, but without `term.pages` (use `pages` instead)