Merge pull request #994 from chris-morgan/misc
Chris Morgan’s whole bunch of miscellaneous work for landing
This commit is contained in:
commit
0ac70cb242
21
CHANGELOG.md
21
CHANGELOG.md
|
@ -1,5 +1,24 @@
|
||||||
# Changelog
|
# Changelog
|
||||||
|
|
||||||
|
## 0.11.0 (unreleased)
|
||||||
|
|
||||||
|
### Breaking
|
||||||
|
- RSS feed support has been altered to allow, *and default to*, Atom feeds, Atom being technically superior and just as widely-supported in normal use cases.
|
||||||
|
- New config value `feed_filename`, defaulting to `atom.xml` (change to `rss.xml` to reinstate the old behaviour)
|
||||||
|
- Config value `rss_limit` is renamed to `feed_limit`
|
||||||
|
- Config value `languages.*.rss` is renamed to `languages.*.feed`
|
||||||
|
- Config value `generate_rss` is renamed to `generate_feed`
|
||||||
|
|
||||||
|
Users with existing feeds should either set `feed_filename = "rss.xml"` in config.toml to keep things the same, or set up a 3xx redirect from rss.xml to atom.xml so that existing feed consumers aren’t broken.
|
||||||
|
|
||||||
|
- The feed template variable `last_build_date` is renamed to `last_updated` to more accurately reflect its semantics
|
||||||
|
- The sitemap template’s `SitemapEntry` type’s `date` field has been renamed to `updated` to reflect that it will use the `updated` front-matter field if available, rather than `date`
|
||||||
|
|
||||||
|
### 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 `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)
|
||||||
|
|
||||||
- Fix link checker not looking for anchor with capital id/name
|
- Fix link checker not looking for anchor with capital id/name
|
||||||
|
@ -17,8 +36,6 @@
|
||||||
### Breaking
|
### Breaking
|
||||||
- Remove `toc` variable in section/page context and pass it to `page.toc` and `section.toc` instead so they are
|
- Remove `toc` variable in section/page context and pass it to `page.toc` and `section.toc` instead so they are
|
||||||
accessible everywhere
|
accessible everywhere
|
||||||
- [Slugification](https://en.wikipedia.org/wiki/Slug_(web_publishing)#Slug) of paths, taxonomies and anchors is now configurable. By default, everything will still be slugified like in previous versions.
|
|
||||||
See documentation for information on how to disable it.
|
|
||||||
|
|
||||||
### Other
|
### Other
|
||||||
- Add zenburn syntax highlighting theme
|
- Add zenburn syntax highlighting theme
|
||||||
|
|
|
@ -47,15 +47,15 @@ impl Default for Slugify {
|
||||||
pub struct Language {
|
pub struct Language {
|
||||||
/// The language code
|
/// The language code
|
||||||
pub code: String,
|
pub code: String,
|
||||||
/// Whether to generate a RSS feed for that language, defaults to `false`
|
/// Whether to generate a feed for that language, defaults to `false`
|
||||||
pub rss: bool,
|
pub feed: bool,
|
||||||
/// Whether to generate search index for that language, defaults to `false`
|
/// Whether to generate search index for that language, defaults to `false`
|
||||||
pub search: bool,
|
pub search: bool,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Default for Language {
|
impl Default for Language {
|
||||||
fn default() -> Self {
|
fn default() -> Self {
|
||||||
Language { code: String::new(), rss: false, search: false }
|
Language { code: String::new(), feed: false, search: false }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -68,8 +68,8 @@ pub struct Taxonomy {
|
||||||
/// by this much
|
/// by this much
|
||||||
pub paginate_by: Option<usize>,
|
pub paginate_by: Option<usize>,
|
||||||
pub paginate_path: Option<String>,
|
pub paginate_path: Option<String>,
|
||||||
/// Whether to generate a RSS feed only for each taxonomy term, defaults to false
|
/// Whether to generate a feed only for each taxonomy term, defaults to false
|
||||||
pub rss: bool,
|
pub feed: bool,
|
||||||
/// The language for that taxonomy, only used in multilingual sites.
|
/// The language for that taxonomy, only used in multilingual sites.
|
||||||
/// Defaults to the config `default_language` if not set
|
/// Defaults to the config `default_language` if not set
|
||||||
pub lang: String,
|
pub lang: String,
|
||||||
|
@ -99,7 +99,7 @@ impl Default for Taxonomy {
|
||||||
name: String::new(),
|
name: String::new(),
|
||||||
paginate_by: None,
|
paginate_by: None,
|
||||||
paginate_path: None,
|
paginate_path: None,
|
||||||
rss: false,
|
feed: false,
|
||||||
lang: String::new(),
|
lang: String::new(),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -155,10 +155,13 @@ pub struct Config {
|
||||||
/// Defaults to "base16-ocean-dark"
|
/// Defaults to "base16-ocean-dark"
|
||||||
pub highlight_theme: String,
|
pub highlight_theme: String,
|
||||||
|
|
||||||
/// Whether to generate RSS. Defaults to false
|
/// Whether to generate a feed. Defaults to false.
|
||||||
pub generate_rss: bool,
|
pub generate_feed: bool,
|
||||||
/// The number of articles to include in the RSS feed. Defaults to including all items.
|
/// The number of articles to include in the feed. Defaults to including all items.
|
||||||
pub rss_limit: Option<usize>,
|
pub feed_limit: Option<usize>,
|
||||||
|
/// The filename to use for feeds. Used to find the template, too.
|
||||||
|
/// Defaults to "atom.xml", with "rss.xml" also having a template provided out of the box.
|
||||||
|
pub feed_filename: String,
|
||||||
/// If set, files from static/ will be hardlinked instead of copied to the output dir.
|
/// If set, files from static/ will be hardlinked instead of copied to the output dir.
|
||||||
pub hard_link_static: bool,
|
pub hard_link_static: bool,
|
||||||
|
|
||||||
|
@ -276,7 +279,8 @@ impl Config {
|
||||||
|
|
||||||
/// Makes a url, taking into account that the base url might have a trailing slash
|
/// Makes a url, taking into account that the base url might have a trailing slash
|
||||||
pub fn make_permalink(&self, path: &str) -> String {
|
pub fn make_permalink(&self, path: &str) -> String {
|
||||||
let trailing_bit = if path.ends_with('/') || path.ends_with("rss.xml") || path.is_empty() {
|
let trailing_bit =
|
||||||
|
if path.ends_with('/') || path.ends_with(&self.feed_filename) || path.is_empty() {
|
||||||
""
|
""
|
||||||
} else {
|
} else {
|
||||||
"/"
|
"/"
|
||||||
|
@ -384,8 +388,9 @@ impl Default for Config {
|
||||||
highlight_theme: "base16-ocean-dark".to_string(),
|
highlight_theme: "base16-ocean-dark".to_string(),
|
||||||
default_language: "en".to_string(),
|
default_language: "en".to_string(),
|
||||||
languages: Vec::new(),
|
languages: Vec::new(),
|
||||||
generate_rss: false,
|
generate_feed: false,
|
||||||
rss_limit: None,
|
feed_limit: None,
|
||||||
|
feed_filename: "atom.xml".to_string(),
|
||||||
hard_link_static: false,
|
hard_link_static: false,
|
||||||
taxonomies: Vec::new(),
|
taxonomies: Vec::new(),
|
||||||
compile_sass: false,
|
compile_sass: false,
|
||||||
|
@ -493,10 +498,10 @@ hello = "world"
|
||||||
|
|
||||||
// https://github.com/Keats/gutenberg/issues/486
|
// https://github.com/Keats/gutenberg/issues/486
|
||||||
#[test]
|
#[test]
|
||||||
fn doesnt_add_trailing_slash_to_rss() {
|
fn doesnt_add_trailing_slash_to_feed() {
|
||||||
let mut config = Config::default();
|
let mut config = Config::default();
|
||||||
config.base_url = "http://vincent.is/".to_string();
|
config.base_url = "http://vincent.is/".to_string();
|
||||||
assert_eq!(config.make_permalink("rss.xml"), "http://vincent.is/rss.xml");
|
assert_eq!(config.make_permalink("atom.xml"), "http://vincent.is/atom.xml");
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
|
|
0
components/errors/src/lib.rs
Executable file → Normal file
0
components/errors/src/lib.rs
Executable file → Normal file
|
@ -16,6 +16,9 @@ pub struct PageFrontMatter {
|
||||||
pub title: Option<String>,
|
pub title: Option<String>,
|
||||||
/// Description in <meta> that appears when linked, e.g. on twitter
|
/// Description in <meta> that appears when linked, e.g. on twitter
|
||||||
pub description: Option<String>,
|
pub description: Option<String>,
|
||||||
|
/// Updated date
|
||||||
|
#[serde(default, deserialize_with = "from_toml_datetime")]
|
||||||
|
pub updated: Option<String>,
|
||||||
/// Date if we want to order pages (ie blog post)
|
/// Date if we want to order pages (ie blog post)
|
||||||
#[serde(default, deserialize_with = "from_toml_datetime")]
|
#[serde(default, deserialize_with = "from_toml_datetime")]
|
||||||
pub date: Option<String>,
|
pub date: Option<String>,
|
||||||
|
@ -117,6 +120,7 @@ impl Default for PageFrontMatter {
|
||||||
PageFrontMatter {
|
PageFrontMatter {
|
||||||
title: None,
|
title: None,
|
||||||
description: None,
|
description: None,
|
||||||
|
updated: None,
|
||||||
date: None,
|
date: None,
|
||||||
datetime: None,
|
datetime: None,
|
||||||
datetime_tuple: None,
|
datetime_tuple: None,
|
||||||
|
|
|
@ -195,7 +195,7 @@ mod tests {
|
||||||
#[test]
|
#[test]
|
||||||
fn can_find_valid_language_in_page() {
|
fn can_find_valid_language_in_page() {
|
||||||
let mut config = Config::default();
|
let mut config = Config::default();
|
||||||
config.languages.push(Language { code: String::from("fr"), rss: false, search: false });
|
config.languages.push(Language { code: String::from("fr"), feed: false, search: false });
|
||||||
let mut file = FileInfo::new_page(
|
let mut file = FileInfo::new_page(
|
||||||
&Path::new("/home/vincent/code/site/content/posts/tutorials/python.fr.md"),
|
&Path::new("/home/vincent/code/site/content/posts/tutorials/python.fr.md"),
|
||||||
&PathBuf::new(),
|
&PathBuf::new(),
|
||||||
|
@ -208,7 +208,7 @@ mod tests {
|
||||||
#[test]
|
#[test]
|
||||||
fn can_find_valid_language_in_page_with_assets() {
|
fn can_find_valid_language_in_page_with_assets() {
|
||||||
let mut config = Config::default();
|
let mut config = Config::default();
|
||||||
config.languages.push(Language { code: String::from("fr"), rss: false, search: false });
|
config.languages.push(Language { code: String::from("fr"), feed: false, search: false });
|
||||||
let mut file = FileInfo::new_page(
|
let mut file = FileInfo::new_page(
|
||||||
&Path::new("/home/vincent/code/site/content/posts/tutorials/python/index.fr.md"),
|
&Path::new("/home/vincent/code/site/content/posts/tutorials/python/index.fr.md"),
|
||||||
&PathBuf::new(),
|
&PathBuf::new(),
|
||||||
|
@ -234,7 +234,7 @@ mod tests {
|
||||||
#[test]
|
#[test]
|
||||||
fn errors_on_unknown_language_in_page_with_i18n_on() {
|
fn errors_on_unknown_language_in_page_with_i18n_on() {
|
||||||
let mut config = Config::default();
|
let mut config = Config::default();
|
||||||
config.languages.push(Language { code: String::from("it"), rss: false, search: false });
|
config.languages.push(Language { code: String::from("it"), feed: false, search: false });
|
||||||
let mut file = FileInfo::new_page(
|
let mut file = FileInfo::new_page(
|
||||||
&Path::new("/home/vincent/code/site/content/posts/tutorials/python.fr.md"),
|
&Path::new("/home/vincent/code/site/content/posts/tutorials/python.fr.md"),
|
||||||
&PathBuf::new(),
|
&PathBuf::new(),
|
||||||
|
@ -246,7 +246,7 @@ mod tests {
|
||||||
#[test]
|
#[test]
|
||||||
fn can_find_valid_language_in_section() {
|
fn can_find_valid_language_in_section() {
|
||||||
let mut config = Config::default();
|
let mut config = Config::default();
|
||||||
config.languages.push(Language { code: String::from("fr"), rss: false, search: false });
|
config.languages.push(Language { code: String::from("fr"), feed: false, search: false });
|
||||||
let mut file = FileInfo::new_section(
|
let mut file = FileInfo::new_section(
|
||||||
&Path::new("/home/vincent/code/site/content/posts/tutorials/_index.fr.md"),
|
&Path::new("/home/vincent/code/site/content/posts/tutorials/_index.fr.md"),
|
||||||
&PathBuf::new(),
|
&PathBuf::new(),
|
||||||
|
@ -273,7 +273,7 @@ mod tests {
|
||||||
#[test]
|
#[test]
|
||||||
fn correct_canonical_after_find_language() {
|
fn correct_canonical_after_find_language() {
|
||||||
let mut config = Config::default();
|
let mut config = Config::default();
|
||||||
config.languages.push(Language { code: String::from("fr"), rss: false, search: false });
|
config.languages.push(Language { code: String::from("fr"), feed: false, search: false });
|
||||||
let mut file = FileInfo::new_page(
|
let mut file = FileInfo::new_page(
|
||||||
&Path::new("/home/vincent/code/site/content/posts/tutorials/python/index.fr.md"),
|
&Path::new("/home/vincent/code/site/content/posts/tutorials/python/index.fr.md"),
|
||||||
&PathBuf::new(),
|
&PathBuf::new(),
|
||||||
|
|
|
@ -770,7 +770,7 @@ Hello world
|
||||||
#[test]
|
#[test]
|
||||||
fn can_specify_language_in_filename() {
|
fn can_specify_language_in_filename() {
|
||||||
let mut config = Config::default();
|
let mut config = Config::default();
|
||||||
config.languages.push(Language { code: String::from("fr"), rss: false, search: false });
|
config.languages.push(Language { code: String::from("fr"), feed: false, search: false });
|
||||||
let content = r#"
|
let content = r#"
|
||||||
+++
|
+++
|
||||||
+++
|
+++
|
||||||
|
@ -787,7 +787,7 @@ Bonjour le monde"#
|
||||||
#[test]
|
#[test]
|
||||||
fn can_specify_language_in_filename_with_date() {
|
fn can_specify_language_in_filename_with_date() {
|
||||||
let mut config = Config::default();
|
let mut config = Config::default();
|
||||||
config.languages.push(Language { code: String::from("fr"), rss: false, search: false });
|
config.languages.push(Language { code: String::from("fr"), feed: false, search: false });
|
||||||
let content = r#"
|
let content = r#"
|
||||||
+++
|
+++
|
||||||
+++
|
+++
|
||||||
|
@ -806,7 +806,7 @@ Bonjour le monde"#
|
||||||
#[test]
|
#[test]
|
||||||
fn i18n_frontmatter_path_overrides_default_permalink() {
|
fn i18n_frontmatter_path_overrides_default_permalink() {
|
||||||
let mut config = Config::default();
|
let mut config = Config::default();
|
||||||
config.languages.push(Language { code: String::from("fr"), rss: false, search: false });
|
config.languages.push(Language { code: String::from("fr"), feed: false, search: false });
|
||||||
let content = r#"
|
let content = r#"
|
||||||
+++
|
+++
|
||||||
path = "bonjour"
|
path = "bonjour"
|
||||||
|
|
|
@ -350,7 +350,7 @@ mod tests {
|
||||||
#[test]
|
#[test]
|
||||||
fn can_specify_language_in_filename() {
|
fn can_specify_language_in_filename() {
|
||||||
let mut config = Config::default();
|
let mut config = Config::default();
|
||||||
config.languages.push(Language { code: String::from("fr"), rss: false, search: false });
|
config.languages.push(Language { code: String::from("fr"), feed: false, search: false });
|
||||||
let content = r#"
|
let content = r#"
|
||||||
+++
|
+++
|
||||||
+++
|
+++
|
||||||
|
@ -372,7 +372,7 @@ Bonjour le monde"#
|
||||||
#[test]
|
#[test]
|
||||||
fn can_make_links_to_translated_sections_without_double_trailing_slash() {
|
fn can_make_links_to_translated_sections_without_double_trailing_slash() {
|
||||||
let mut config = Config::default();
|
let mut config = Config::default();
|
||||||
config.languages.push(Language { code: String::from("fr"), rss: false, search: false });
|
config.languages.push(Language { code: String::from("fr"), feed: false, search: false });
|
||||||
let content = r#"
|
let content = r#"
|
||||||
+++
|
+++
|
||||||
+++
|
+++
|
||||||
|
@ -389,7 +389,7 @@ Bonjour le monde"#
|
||||||
#[test]
|
#[test]
|
||||||
fn can_make_links_to_translated_subsections_with_trailing_slash() {
|
fn can_make_links_to_translated_subsections_with_trailing_slash() {
|
||||||
let mut config = Config::default();
|
let mut config = Config::default();
|
||||||
config.languages.push(Language { code: String::from("fr"), rss: false, search: false });
|
config.languages.push(Language { code: String::from("fr"), feed: false, search: false });
|
||||||
let content = r#"
|
let content = r#"
|
||||||
+++
|
+++
|
||||||
+++
|
+++
|
||||||
|
|
|
@ -63,6 +63,7 @@ pub struct SerializingPage<'a> {
|
||||||
ancestors: Vec<String>,
|
ancestors: Vec<String>,
|
||||||
title: &'a Option<String>,
|
title: &'a Option<String>,
|
||||||
description: &'a Option<String>,
|
description: &'a Option<String>,
|
||||||
|
updated: &'a Option<String>,
|
||||||
date: &'a Option<String>,
|
date: &'a Option<String>,
|
||||||
year: Option<i32>,
|
year: Option<i32>,
|
||||||
month: Option<u32>,
|
month: Option<u32>,
|
||||||
|
@ -126,6 +127,7 @@ impl<'a> SerializingPage<'a> {
|
||||||
title: &page.meta.title,
|
title: &page.meta.title,
|
||||||
description: &page.meta.description,
|
description: &page.meta.description,
|
||||||
extra: &page.meta.extra,
|
extra: &page.meta.extra,
|
||||||
|
updated: &page.meta.updated,
|
||||||
date: &page.meta.date,
|
date: &page.meta.date,
|
||||||
year,
|
year,
|
||||||
month,
|
month,
|
||||||
|
@ -182,6 +184,7 @@ impl<'a> SerializingPage<'a> {
|
||||||
title: &page.meta.title,
|
title: &page.meta.title,
|
||||||
description: &page.meta.description,
|
description: &page.meta.description,
|
||||||
extra: &page.meta.extra,
|
extra: &page.meta.extra,
|
||||||
|
updated: &page.meta.updated,
|
||||||
date: &page.meta.date,
|
date: &page.meta.date,
|
||||||
year,
|
year,
|
||||||
month,
|
month,
|
||||||
|
|
|
@ -6,7 +6,7 @@ use slotmap::DefaultKey;
|
||||||
|
|
||||||
use crate::content::Page;
|
use crate::content::Page;
|
||||||
|
|
||||||
/// Used by the RSS feed
|
/// Used by the feed
|
||||||
/// There to not have to import sorting stuff in the site crate
|
/// There to not have to import sorting stuff in the site crate
|
||||||
#[allow(clippy::trivially_copy_pass_by_ref)]
|
#[allow(clippy::trivially_copy_pass_by_ref)]
|
||||||
pub fn sort_actual_pages_by_date(a: &&Page, b: &&Page) -> Ordering {
|
pub fn sort_actual_pages_by_date(a: &&Page, b: &&Page) -> Ordering {
|
||||||
|
|
|
@ -458,7 +458,7 @@ mod tests {
|
||||||
#[test]
|
#[test]
|
||||||
fn can_make_taxonomies_in_multiple_languages() {
|
fn can_make_taxonomies_in_multiple_languages() {
|
||||||
let mut config = Config::default();
|
let mut config = Config::default();
|
||||||
config.languages.push(Language { rss: false, code: "fr".to_string(), search: false });
|
config.languages.push(Language { feed: false, code: "fr".to_string(), search: false });
|
||||||
let mut library = Library::new(2, 0, true);
|
let mut library = Library::new(2, 0, true);
|
||||||
|
|
||||||
config.taxonomies = vec![
|
config.taxonomies = vec![
|
||||||
|
@ -569,7 +569,7 @@ mod tests {
|
||||||
let mut config = Config::default();
|
let mut config = Config::default();
|
||||||
config.slugify.taxonomies = SlugifyStrategy::Safe;
|
config.slugify.taxonomies = SlugifyStrategy::Safe;
|
||||||
config.languages.push(Language {
|
config.languages.push(Language {
|
||||||
rss: false,
|
feed: false,
|
||||||
code: "fr".to_string(),
|
code: "fr".to_string(),
|
||||||
..Language::default()
|
..Language::default()
|
||||||
});
|
});
|
||||||
|
@ -602,7 +602,7 @@ mod tests {
|
||||||
let mut config = Config::default();
|
let mut config = Config::default();
|
||||||
config.slugify.taxonomies = SlugifyStrategy::On;
|
config.slugify.taxonomies = SlugifyStrategy::On;
|
||||||
config.languages.push(Language {
|
config.languages.push(Language {
|
||||||
rss: false,
|
feed: false,
|
||||||
code: "fr".to_string(),
|
code: "fr".to_string(),
|
||||||
..Language::default()
|
..Language::default()
|
||||||
});
|
});
|
||||||
|
|
|
@ -395,7 +395,17 @@ 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(),
|
||||||
"rss.xml" => site.render_rss_feed(site.library.read().unwrap().pages_values(), None),
|
filename if filename == site.config.feed_filename => {
|
||||||
|
// FIXME: this is insufficient; for multilingual sites, it’s rendering the wrong
|
||||||
|
// content into the root feed, and it’s 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(),
|
||||||
"single.html" | "list.html" => site.render_taxonomies(),
|
"single.html" | "list.html" => site.render_taxonomies(),
|
||||||
|
|
|
@ -108,7 +108,7 @@ base_url = "https://replace-this-with-your-url.com"
|
||||||
theme = "sample"
|
theme = "sample"
|
||||||
|
|
||||||
taxonomies = [
|
taxonomies = [
|
||||||
{name = "tags", rss = true},
|
{name = "tags", feed = true},
|
||||||
{name = "categories"}
|
{name = "categories"}
|
||||||
]
|
]
|
||||||
|
|
||||||
|
|
|
@ -35,12 +35,19 @@ fn bench_render_sitemap(b: &mut test::Bencher) {
|
||||||
}
|
}
|
||||||
|
|
||||||
#[bench]
|
#[bench]
|
||||||
fn bench_render_rss_feed(b: &mut test::Bencher) {
|
fn bench_render_feed(b: &mut test::Bencher) {
|
||||||
let mut site = setup_site("big-blog");
|
let mut site = setup_site("big-blog");
|
||||||
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_rss_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]
|
||||||
|
|
|
@ -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
|
||||||
|
@ -626,15 +645,17 @@ impl Site {
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Inject live reload script tag if in live reload mode
|
/// Inject live reload script tag if in live reload mode
|
||||||
fn inject_livereload(&self, html: String) -> String {
|
fn inject_livereload(&self, mut html: String) -> String {
|
||||||
if let Some(port) = self.live_reload {
|
if let Some(port) = self.live_reload {
|
||||||
return html.replace(
|
let script = format!(
|
||||||
"</body>",
|
r#"<script src="/livereload.js?port={}&mindelay=10"></script>"#,
|
||||||
&format!(
|
port,
|
||||||
r#"<script src="/livereload.js?port={}&mindelay=10"></script></body>"#,
|
|
||||||
port
|
|
||||||
),
|
|
||||||
);
|
);
|
||||||
|
if let Some(index) = html.rfind("</body>") {
|
||||||
|
html.insert_str(index, &script);
|
||||||
|
} else {
|
||||||
|
html.push_str(&script);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
html
|
html
|
||||||
|
@ -743,8 +764,9 @@ impl Site {
|
||||||
self.render_sitemap()?;
|
self.render_sitemap()?;
|
||||||
|
|
||||||
let library = self.library.read().unwrap();
|
let library = self.library.read().unwrap();
|
||||||
if self.config.generate_rss {
|
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()
|
||||||
|
@ -754,16 +776,26 @@ impl Site {
|
||||||
} else {
|
} else {
|
||||||
library.pages_values()
|
library.pages_values()
|
||||||
};
|
};
|
||||||
self.render_rss_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 {
|
||||||
if !lang.rss {
|
if !lang.feed {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
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_rss_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()?;
|
||||||
|
@ -981,10 +1013,16 @@ impl Site {
|
||||||
create_file(&path.join("index.html"), &self.inject_livereload(single_output))?;
|
create_file(&path.join("index.html"), &self.inject_livereload(single_output))?;
|
||||||
}
|
}
|
||||||
|
|
||||||
if taxonomy.kind.rss {
|
if taxonomy.kind.feed {
|
||||||
self.render_rss_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(())
|
||||||
|
@ -1043,30 +1081,39 @@ impl Site {
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Renders a RSS feed for the given path and at the given path
|
/// Renders a feed for the given path and at the given path
|
||||||
/// If both arguments are `None`, it will render only the RSS feed for the whole
|
/// If both arguments are `None`, it will render only the feed for the whole
|
||||||
/// site at the root folder.
|
/// site at the root folder.
|
||||||
pub fn render_rss_feed(
|
pub fn render_feed(
|
||||||
&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)?;
|
||||||
|
|
||||||
let mut context = Context::new();
|
let mut context = Context::new();
|
||||||
let mut pages = all_pages.into_iter().filter(|p| p.meta.date.is_some()).collect::<Vec<_>>();
|
let mut pages = all_pages.into_iter().filter(|p| p.meta.date.is_some()).collect::<Vec<_>>();
|
||||||
|
|
||||||
// Don't generate a RSS feed if none of the pages has a date
|
// Don't generate a feed if none of the pages has a date
|
||||||
if pages.is_empty() {
|
if pages.is_empty() {
|
||||||
return Ok(());
|
return Ok(());
|
||||||
}
|
}
|
||||||
|
|
||||||
pages.par_sort_unstable_by(sort_actual_pages_by_date);
|
pages.par_sort_unstable_by(sort_actual_pages_by_date);
|
||||||
|
|
||||||
context.insert("last_build_date", &pages[0].meta.date.clone());
|
context.insert(
|
||||||
|
"last_updated",
|
||||||
|
pages.iter()
|
||||||
|
.filter_map(|page| page.meta.updated.as_ref())
|
||||||
|
.chain(pages[0].meta.date.as_ref())
|
||||||
|
.max() // I love lexicographically sorted date strings
|
||||||
|
.unwrap(), // Guaranteed because of pages[0].meta.date
|
||||||
|
);
|
||||||
let library = self.library.read().unwrap();
|
let library = self.library.read().unwrap();
|
||||||
// limit to the last n elements if the limit is set; otherwise use all.
|
// limit to the last n elements if the limit is set; otherwise use all.
|
||||||
let num_entries = self.config.rss_limit.unwrap_or_else(|| pages.len());
|
let num_entries = self.config.feed_limit.unwrap_or_else(|| pages.len());
|
||||||
let p = pages
|
let p = pages
|
||||||
.iter()
|
.iter()
|
||||||
.take(num_entries)
|
.take(num_entries)
|
||||||
|
@ -1075,16 +1122,28 @@ 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 rss_feed_url = if let Some(ref base) = base_path {
|
let feed_filename = &self.config.feed_filename;
|
||||||
self.config.make_permalink(&base.join("rss.xml").to_string_lossy().replace('\\', "/"))
|
let feed_url = if let Some(ref base) = base_path {
|
||||||
|
self.config.make_permalink(
|
||||||
|
&base
|
||||||
|
.join(feed_filename)
|
||||||
|
.to_string_lossy()
|
||||||
|
.replace('\\', "/"),
|
||||||
|
)
|
||||||
} else {
|
} else {
|
||||||
self.config.make_permalink("rss.xml")
|
self.config.make_permalink(feed_filename)
|
||||||
};
|
};
|
||||||
|
|
||||||
context.insert("feed_url", &rss_feed_url);
|
context.insert("feed_url", &feed_url);
|
||||||
|
|
||||||
let feed = &render_template("rss.xml", &self.tera, context, &self.config.theme)?;
|
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)?;
|
||||||
|
|
||||||
if let Some(ref base) = base_path {
|
if let Some(ref base) = base_path {
|
||||||
let mut output_path = self.output_path.clone();
|
let mut output_path = self.output_path.clone();
|
||||||
|
@ -1094,9 +1153,9 @@ impl Site {
|
||||||
create_directory(&output_path)?;
|
create_directory(&output_path)?;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
create_file(&output_path.join("rss.xml"), feed)?;
|
create_file(&output_path.join(feed_filename), feed)?;
|
||||||
} else {
|
} else {
|
||||||
create_file(&self.output_path.join("rss.xml"), feed)?;
|
create_file(&self.output_path.join(feed_filename), feed)?;
|
||||||
}
|
}
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
|
@ -14,7 +14,7 @@ use tera::{Map, Value};
|
||||||
#[derive(Debug, Serialize)]
|
#[derive(Debug, Serialize)]
|
||||||
pub struct SitemapEntry<'a> {
|
pub struct SitemapEntry<'a> {
|
||||||
pub permalink: Cow<'a, str>,
|
pub permalink: Cow<'a, str>,
|
||||||
pub date: Option<String>,
|
pub updated: Option<String>,
|
||||||
pub extra: Option<&'a Map<String, Value>>,
|
pub extra: Option<&'a Map<String, Value>>,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -33,8 +33,8 @@ impl<'a> PartialEq for SitemapEntry<'a> {
|
||||||
impl<'a> Eq for SitemapEntry<'a> {}
|
impl<'a> Eq for SitemapEntry<'a> {}
|
||||||
|
|
||||||
impl<'a> SitemapEntry<'a> {
|
impl<'a> SitemapEntry<'a> {
|
||||||
pub fn new(permalink: Cow<'a, str>, date: Option<String>) -> Self {
|
pub fn new(permalink: Cow<'a, str>, updated: Option<String>) -> Self {
|
||||||
SitemapEntry { permalink, date, extra: None }
|
SitemapEntry { permalink, updated, extra: None }
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn add_extra(&mut self, extra: &'a Map<String, Value>) {
|
pub fn add_extra(&mut self, extra: &'a Map<String, Value>) {
|
||||||
|
@ -65,11 +65,10 @@ pub fn find_entries<'a>(
|
||||||
.pages_values()
|
.pages_values()
|
||||||
.iter()
|
.iter()
|
||||||
.map(|p| {
|
.map(|p| {
|
||||||
let date = match p.meta.date {
|
let mut entry = SitemapEntry::new(
|
||||||
Some(ref d) => Some(d.to_string()),
|
Cow::Borrowed(&p.permalink),
|
||||||
None => None,
|
p.meta.updated.clone().or_else(|| p.meta.date.clone()),
|
||||||
};
|
);
|
||||||
let mut entry = SitemapEntry::new(Cow::Borrowed(&p.permalink), date);
|
|
||||||
entry.add_extra(&p.meta.extra);
|
entry.add_extra(&p.meta.extra);
|
||||||
entry
|
entry
|
||||||
})
|
})
|
||||||
|
|
|
@ -152,7 +152,7 @@ fn can_build_site_without_live_reload() {
|
||||||
// We do have categories
|
// We do have categories
|
||||||
assert_eq!(file_exists!(public, "categories/index.html"), true);
|
assert_eq!(file_exists!(public, "categories/index.html"), true);
|
||||||
assert_eq!(file_exists!(public, "categories/a-category/index.html"), true);
|
assert_eq!(file_exists!(public, "categories/a-category/index.html"), true);
|
||||||
assert_eq!(file_exists!(public, "categories/a-category/rss.xml"), true);
|
assert_eq!(file_exists!(public, "categories/a-category/atom.xml"), true);
|
||||||
// But no tags
|
// But no tags
|
||||||
assert_eq!(file_exists!(public, "tags/index.html"), false);
|
assert_eq!(file_exists!(public, "tags/index.html"), false);
|
||||||
|
|
||||||
|
@ -232,7 +232,7 @@ fn can_build_site_with_live_reload_and_drafts() {
|
||||||
// We do have categories
|
// We do have categories
|
||||||
assert_eq!(file_exists!(public, "categories/index.html"), true);
|
assert_eq!(file_exists!(public, "categories/index.html"), true);
|
||||||
assert_eq!(file_exists!(public, "categories/a-category/index.html"), true);
|
assert_eq!(file_exists!(public, "categories/a-category/index.html"), true);
|
||||||
assert_eq!(file_exists!(public, "categories/a-category/rss.xml"), true);
|
assert_eq!(file_exists!(public, "categories/a-category/atom.xml"), true);
|
||||||
// But no tags
|
// But no tags
|
||||||
assert_eq!(file_exists!(public, "tags/index.html"), false);
|
assert_eq!(file_exists!(public, "tags/index.html"), false);
|
||||||
|
|
||||||
|
@ -294,11 +294,11 @@ fn can_build_site_with_taxonomies() {
|
||||||
assert!(file_exists!(public, "categories/index.html"));
|
assert!(file_exists!(public, "categories/index.html"));
|
||||||
assert!(file_exists!(public, "categories/a/index.html"));
|
assert!(file_exists!(public, "categories/a/index.html"));
|
||||||
assert!(file_exists!(public, "categories/b/index.html"));
|
assert!(file_exists!(public, "categories/b/index.html"));
|
||||||
assert!(file_exists!(public, "categories/a/rss.xml"));
|
assert!(file_exists!(public, "categories/a/atom.xml"));
|
||||||
assert!(file_contains!(
|
assert!(file_contains!(
|
||||||
public,
|
public,
|
||||||
"categories/a/rss.xml",
|
"categories/a/atom.xml",
|
||||||
"https://replace-this-with-your-url.com/categories/a/rss.xml"
|
"https://replace-this-with-your-url.com/categories/a/atom.xml"
|
||||||
));
|
));
|
||||||
// Extending from a theme works
|
// Extending from a theme works
|
||||||
assert!(file_contains!(public, "categories/a/index.html", "EXTENDED"));
|
assert!(file_contains!(public, "categories/a/index.html", "EXTENDED"));
|
||||||
|
@ -513,7 +513,7 @@ fn can_build_site_with_pagination_for_taxonomy() {
|
||||||
name: "tags".to_string(),
|
name: "tags".to_string(),
|
||||||
paginate_by: Some(2),
|
paginate_by: Some(2),
|
||||||
paginate_path: None,
|
paginate_path: None,
|
||||||
rss: true,
|
feed: true,
|
||||||
lang: site.config.default_language.clone(),
|
lang: site.config.default_language.clone(),
|
||||||
});
|
});
|
||||||
site.load().unwrap();
|
site.load().unwrap();
|
||||||
|
@ -547,9 +547,9 @@ fn can_build_site_with_pagination_for_taxonomy() {
|
||||||
|
|
||||||
// Tags
|
// Tags
|
||||||
assert!(file_exists!(public, "tags/index.html"));
|
assert!(file_exists!(public, "tags/index.html"));
|
||||||
// With RSS
|
// With Atom
|
||||||
assert!(file_exists!(public, "tags/a/rss.xml"));
|
assert!(file_exists!(public, "tags/a/atom.xml"));
|
||||||
assert!(file_exists!(public, "tags/b/rss.xml"));
|
assert!(file_exists!(public, "tags/b/atom.xml"));
|
||||||
// And pagination!
|
// And pagination!
|
||||||
assert!(file_exists!(public, "tags/a/page/1/index.html"));
|
assert!(file_exists!(public, "tags/a/page/1/index.html"));
|
||||||
assert!(file_exists!(public, "tags/b/page/1/index.html"));
|
assert!(file_exists!(public, "tags/b/page/1/index.html"));
|
||||||
|
@ -588,15 +588,15 @@ fn can_build_site_with_pagination_for_taxonomy() {
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn can_build_rss_feed() {
|
fn can_build_feed() {
|
||||||
let (_, _tmp_dir, public) = build_site("test_site");
|
let (_, _tmp_dir, public) = build_site("test_site");
|
||||||
|
|
||||||
assert!(&public.exists());
|
assert!(&public.exists());
|
||||||
assert!(file_exists!(public, "rss.xml"));
|
assert!(file_exists!(public, "atom.xml"));
|
||||||
// latest article is posts/extra-syntax.md
|
// latest article is posts/extra-syntax.md
|
||||||
assert!(file_contains!(public, "rss.xml", "Extra Syntax"));
|
assert!(file_contains!(public, "atom.xml", "Extra Syntax"));
|
||||||
// Next is posts/simple.md
|
// Next is posts/simple.md
|
||||||
assert!(file_contains!(public, "rss.xml", "Simple article with shortcodes"));
|
assert!(file_contains!(public, "atom.xml", "Simple article with shortcodes"));
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
|
|
|
@ -115,15 +115,17 @@ fn can_build_multilingual_site() {
|
||||||
assert!(file_contains!(public, "sitemap.xml", "https://example.com/fr/blog/something-else/"));
|
assert!(file_contains!(public, "sitemap.xml", "https://example.com/fr/blog/something-else/"));
|
||||||
assert!(file_contains!(public, "sitemap.xml", "https://example.com/it/blog/something-else/"));
|
assert!(file_contains!(public, "sitemap.xml", "https://example.com/it/blog/something-else/"));
|
||||||
|
|
||||||
// one rss per language
|
// one feed per language
|
||||||
assert!(file_exists!(public, "rss.xml"));
|
assert!(file_exists!(public, "atom.xml"));
|
||||||
assert!(file_contains!(public, "rss.xml", "https://example.com/blog/something-else/"));
|
assert!(file_contains!(public, "atom.xml", "https://example.com/blog/something-else/"));
|
||||||
assert!(!file_contains!(public, "rss.xml", "https://example.com/fr/blog/something-else/"));
|
assert!(!file_contains!(public, "atom.xml", "https://example.com/fr/blog/something-else/"));
|
||||||
assert!(file_exists!(public, "fr/rss.xml"));
|
assert!(file_contains!(public, "atom.xml", r#"<feed xmlns="http://www.w3.org/2005/Atom" xml:lang="en">"#));
|
||||||
assert!(!file_contains!(public, "fr/rss.xml", "https://example.com/blog/something-else/"));
|
assert!(file_exists!(public, "fr/atom.xml"));
|
||||||
assert!(file_contains!(public, "fr/rss.xml", "https://example.com/fr/blog/something-else/"));
|
assert!(!file_contains!(public, "fr/atom.xml", "https://example.com/blog/something-else/"));
|
||||||
// Italian doesn't have RSS enabled
|
assert!(file_contains!(public, "fr/atom.xml", "https://example.com/fr/blog/something-else/"));
|
||||||
assert!(!file_exists!(public, "it/rss.xml"));
|
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
|
||||||
|
assert!(!file_exists!(public, "it/atom.xml"));
|
||||||
|
|
||||||
// Taxonomies are per-language
|
// Taxonomies are per-language
|
||||||
// English
|
// English
|
||||||
|
@ -131,7 +133,9 @@ fn can_build_multilingual_site() {
|
||||||
assert!(file_contains!(public, "authors/index.html", "Queen"));
|
assert!(file_contains!(public, "authors/index.html", "Queen"));
|
||||||
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/rss.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"));
|
||||||
|
@ -142,7 +146,7 @@ fn can_build_multilingual_site() {
|
||||||
assert!(file_exists!(public, "fr/auteurs/index.html"));
|
assert!(file_exists!(public, "fr/auteurs/index.html"));
|
||||||
assert!(!file_contains!(public, "fr/auteurs/index.html", "Queen"));
|
assert!(!file_contains!(public, "fr/auteurs/index.html", "Queen"));
|
||||||
assert!(file_contains!(public, "fr/auteurs/index.html", "Vincent"));
|
assert!(file_contains!(public, "fr/auteurs/index.html", "Vincent"));
|
||||||
assert!(!file_exists!(public, "fr/auteurs/vincent-prouillet/rss.xml"));
|
assert!(!file_exists!(public, "fr/auteurs/vincent-prouillet/atom.xml"));
|
||||||
|
|
||||||
assert!(file_exists!(public, "fr/tags/index.html"));
|
assert!(file_exists!(public, "fr/tags/index.html"));
|
||||||
assert!(file_contains!(public, "fr/tags/index.html", "bonjour"));
|
assert!(file_contains!(public, "fr/tags/index.html", "bonjour"));
|
||||||
|
|
|
@ -1,10 +1,3 @@
|
||||||
<!doctype html>
|
<!doctype html>
|
||||||
<html>
|
<title>404 Not Found</title>
|
||||||
<head>
|
<h1>404 Not Found</h1>
|
||||||
<title>File Not Found: 404.</title>
|
|
||||||
</head>
|
|
||||||
<body>
|
|
||||||
<h1>Oops!</h1>
|
|
||||||
<h2>File Not Found: 404.</h2>
|
|
||||||
</body>
|
|
||||||
</html>
|
|
||||||
|
|
27
components/templates/src/builtins/atom.xml
Normal file
27
components/templates/src/builtins/atom.xml
Normal file
|
@ -0,0 +1,27 @@
|
||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<feed xmlns="http://www.w3.org/2005/Atom" xml:lang="{{ lang }}">
|
||||||
|
<title>{{ config.title }}
|
||||||
|
{%- if term %} - {{ term.name }}
|
||||||
|
{%- endif -%}
|
||||||
|
</title>
|
||||||
|
{%- if config.description %}
|
||||||
|
<subtitle>{{ config.description }}</subtitle>
|
||||||
|
{%- endif %}
|
||||||
|
<link href="{{ feed_url | safe }}" rel="self" type="application/atom+xml"/>
|
||||||
|
<link href="{{ config.base_url | safe }}"/>
|
||||||
|
<generator uri="https://www.getzola.org/">Zola</generator>
|
||||||
|
<updated>{{ last_updated | date(format="%+") }}</updated>
|
||||||
|
<id>{{ feed_url | safe }}</id>
|
||||||
|
{%- for page in pages %}
|
||||||
|
<entry
|
||||||
|
{%- if page.lang != lang %} xml:lang="{{ page.lang }}"{% endif -%}
|
||||||
|
>
|
||||||
|
<title>{{ page.title }}</title>
|
||||||
|
<published>{{ page.date | date(format="%+") }}</published>
|
||||||
|
<updated>{{ page.updated | default(value=page.date) | date(format="%+") }}</updated>
|
||||||
|
<link href="{{ page.permalink | safe }}" type="text/html"/>
|
||||||
|
<id>{{ page.permalink | safe }}</id>
|
||||||
|
<content type="html">{{ page.content }}</description>
|
||||||
|
</item>
|
||||||
|
{%- endfor %}
|
||||||
|
</feed>
|
|
@ -1,12 +1,6 @@
|
||||||
<!DOCTYPE html>
|
<!doctype html>
|
||||||
<html>
|
<meta charset="utf-8">
|
||||||
<head>
|
<link rel="canonical" href="{{ url | safe }}">
|
||||||
|
<meta http-equiv="refresh" content="0;url={{ url | safe }}">
|
||||||
<title>Redirect</title>
|
<title>Redirect</title>
|
||||||
<link rel="canonical" href="{{ url | safe }}" />
|
|
||||||
<meta http-equiv="content-type" content="text/html; charset=utf-8" />
|
|
||||||
<meta http-equiv="refresh" content="0;url={{ url | safe }}" />
|
|
||||||
</head>
|
|
||||||
<body>
|
|
||||||
<p><a href="{{ url | safe }}">Click here</a> to be redirected.</p>
|
<p><a href="{{ url | safe }}">Click here</a> to be redirected.</p>
|
||||||
</body>
|
|
||||||
</html>
|
|
||||||
|
|
|
@ -7,8 +7,8 @@
|
||||||
<generator>Zola</generator>
|
<generator>Zola</generator>
|
||||||
<language>{{ config.default_language }}</language>
|
<language>{{ config.default_language }}</language>
|
||||||
<atom:link href="{{ feed_url | safe }}" rel="self" type="application/rss+xml"/>
|
<atom:link href="{{ feed_url | safe }}" rel="self" type="application/rss+xml"/>
|
||||||
<lastBuildDate>{{ last_build_date | date(format="%a, %d %b %Y %H:%M:%S %z") }}</lastBuildDate>
|
<lastBuildDate>{{ last_updated | date(format="%a, %d %b %Y %H:%M:%S %z") }}</lastBuildDate>
|
||||||
{% for page in pages %}
|
{%- for page in pages %}
|
||||||
<item>
|
<item>
|
||||||
<title>{{ page.title }}</title>
|
<title>{{ page.title }}</title>
|
||||||
<pubDate>{{ page.date | date(format="%a, %d %b %Y %H:%M:%S %z") }}</pubDate>
|
<pubDate>{{ page.date | date(format="%a, %d %b %Y %H:%M:%S %z") }}</pubDate>
|
||||||
|
@ -16,6 +16,6 @@
|
||||||
<guid>{{ page.permalink | escape_xml | safe }}</guid>
|
<guid>{{ page.permalink | escape_xml | safe }}</guid>
|
||||||
<description>{% if page.summary %}{{ page.summary }}{% else %}{{ page.content }}{% endif %}</description>
|
<description>{% if page.summary %}{{ page.summary }}{% else %}{{ page.content }}{% endif %}</description>
|
||||||
</item>
|
</item>
|
||||||
{% endfor %}
|
{%- endfor %}
|
||||||
</channel>
|
</channel>
|
||||||
</rss>
|
</rss>
|
||||||
|
|
|
@ -1,7 +1,3 @@
|
||||||
<div {% if class %}class="{{class}}"{% endif %}>
|
<div {% if class %}class="{{class}}"{% endif %}>
|
||||||
<iframe src="https://www.streamable.com/e/{{id}}"
|
<iframe src="https://www.streamable.com/e/{{id}}" scrolling="no" frameborder="0" allowfullscreen mozallowfullscreen webkitallowfullscreen></iframe>
|
||||||
scrolling="no"
|
|
||||||
frameborder="0"
|
|
||||||
allowfullscreen mozallowfullscreen webkitallowfullscreen>
|
|
||||||
</iframe>
|
|
||||||
</div>
|
</div>
|
||||||
|
|
|
@ -1,4 +1,3 @@
|
||||||
<div {% if class %}class="{{class}}"{% endif %}>
|
<div {% if class %}class="{{class}}"{% endif %}>
|
||||||
<iframe src="//player.vimeo.com/video/{{id}}" webkitallowfullscreen mozallowfullscreen allowfullscreen>
|
<iframe src="//player.vimeo.com/video/{{id}}" webkitallowfullscreen mozallowfullscreen allowfullscreen></iframe>
|
||||||
</iframe>
|
|
||||||
</div>
|
</div>
|
||||||
|
|
|
@ -1,4 +1,3 @@
|
||||||
<div {% if class %}class="{{class}}"{% endif %}>
|
<div {% if class %}class="{{class}}"{% endif %}>
|
||||||
<iframe src="https://www.youtube.com/embed/{{id}}{% if autoplay %}?autoplay=1{% endif %}" webkitallowfullscreen mozallowfullscreen allowfullscreen>
|
<iframe src="https://www.youtube.com/embed/{{id}}{% if autoplay %}?autoplay=1{% endif %}" webkitallowfullscreen mozallowfullscreen allowfullscreen></iframe>
|
||||||
</iframe>
|
|
||||||
</div>
|
</div>
|
||||||
|
|
|
@ -1,11 +1,11 @@
|
||||||
<?xml version="1.0" encoding="UTF-8"?>
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
<urlset xmlns="http://www.sitemaps.org/schemas/sitemap/0.9">
|
<urlset xmlns="http://www.sitemaps.org/schemas/sitemap/0.9">
|
||||||
{% for sitemap_entry in entries %}
|
{%- for sitemap_entry in entries %}
|
||||||
<url>
|
<url>
|
||||||
<loc>{{ sitemap_entry.permalink | escape_xml | safe }}</loc>
|
<loc>{{ sitemap_entry.permalink | escape_xml | safe }}</loc>
|
||||||
{% if sitemap_entry.date %}
|
{%- if sitemap_entry.updated %}
|
||||||
<lastmod>{{ sitemap_entry.date }}</lastmod>
|
<lastmod>{{ sitemap_entry.updated }}</lastmod>
|
||||||
{% endif %}
|
{%- endif %}
|
||||||
</url>
|
</url>
|
||||||
{% endfor %}
|
{%- endfor %}
|
||||||
</urlset>
|
</urlset>
|
||||||
|
|
|
@ -1,8 +1,8 @@
|
||||||
<?xml version="1.0" encoding="UTF-8"?>
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
<sitemapindex xmlns="http://www.sitemaps.org/schemas/sitemap/0.9">
|
<sitemapindex xmlns="http://www.sitemaps.org/schemas/sitemap/0.9">
|
||||||
{% for sitemap in sitemaps %}
|
{%- for sitemap in sitemaps %}
|
||||||
<sitemap>
|
<sitemap>
|
||||||
<loc>{{ sitemap }}</loc>
|
<loc>{{ sitemap }}</loc>
|
||||||
</sitemap>
|
</sitemap>
|
||||||
{% endfor %}
|
{%- endfor %}
|
||||||
</sitemapindex>
|
</sitemapindex>
|
|
@ -11,6 +11,7 @@ lazy_static! {
|
||||||
let mut tera = Tera::default();
|
let mut tera = Tera::default();
|
||||||
tera.add_raw_templates(vec![
|
tera.add_raw_templates(vec![
|
||||||
("__zola_builtins/404.html", include_str!("builtins/404.html")),
|
("__zola_builtins/404.html", include_str!("builtins/404.html")),
|
||||||
|
("__zola_builtins/atom.xml", include_str!("builtins/atom.xml")),
|
||||||
("__zola_builtins/rss.xml", include_str!("builtins/rss.xml")),
|
("__zola_builtins/rss.xml", include_str!("builtins/rss.xml")),
|
||||||
("__zola_builtins/sitemap.xml", include_str!("builtins/sitemap.xml")),
|
("__zola_builtins/sitemap.xml", include_str!("builtins/sitemap.xml")),
|
||||||
("__zola_builtins/robots.txt", include_str!("builtins/robots.txt")),
|
("__zola_builtins/robots.txt", include_str!("builtins/robots.txt")),
|
||||||
|
|
|
@ -5,8 +5,9 @@ weight = 50
|
||||||
|
|
||||||
## Heading id and anchor insertion
|
## Heading id and anchor insertion
|
||||||
While rendering the Markdown content, a unique id will automatically be assigned to each heading.
|
While rendering the Markdown content, a unique id will automatically be assigned to each heading.
|
||||||
This id is created by converting the heading text to a [slug](https://en.wikipedia.org/wiki/Semantic_URL#Slug) if `slugify_paths` is enabled.
|
This id is created by converting the heading text to a [slug](https://en.wikipedia.org/wiki/Semantic_URL#Slug) if `slugify.anchors` is set to `"on"` (the default).
|
||||||
if `slugify_paths` is disabled, whitespaces are replaced by `_` and the following characters are stripped: `#`, `%`, `<`, `>`, `[`, `]`, `(`, `)`, \`, `^`, `{`, `|`, `}`.
|
If `slugify.paths` is set to `"safe"`, whitespaces are replaced by `_` and the following characters are stripped: `#`, `%`, `<`, `>`, `[`, `]`, `(`, `)`, \`, `^`, `{`, `|`, `}`.
|
||||||
|
If `slugify.paths` is set to `"off"`, no modifications are made, and you may be left with nominally illegal ids.
|
||||||
A number is appended at the end if the slug already exists for that article
|
A number is appended at the end if the slug already exists for that article
|
||||||
For example:
|
For example:
|
||||||
|
|
||||||
|
|
|
@ -11,9 +11,9 @@ to your `config.toml`. For example:
|
||||||
|
|
||||||
```toml
|
```toml
|
||||||
languages = [
|
languages = [
|
||||||
{code = "fr", rss = true}, # there will be a RSS feed for French content
|
{code = "fr", feed = true}, # there will be a feed for French content
|
||||||
{code = "fr", search = true}, # there will be a Search Index for French content
|
{code = "fr", search = true}, # there will be a Search Index for French content
|
||||||
{code = "it"}, # there won't be a RSS feed for Italian content
|
{code = "it"}, # there won't be a feed for Italian content
|
||||||
]
|
]
|
||||||
```
|
```
|
||||||
|
|
||||||
|
|
|
@ -35,12 +35,13 @@ For any page within your content folder, its output path will be defined by eith
|
||||||
- its filename
|
- its filename
|
||||||
|
|
||||||
Either way, these proposed path will be sanitized before being used.
|
Either way, these proposed path will be sanitized before being used.
|
||||||
If `slugify_paths` is enabled in the site's config - the default - paths are [slugified](https://en.wikipedia.org/wiki/Clean_URL#Slug).
|
If `slugify.paths` is set to `"on"` in the site's config - the default - paths are [slugified](https://en.wikipedia.org/wiki/Clean_URL#Slug).
|
||||||
Otherwise, a simpler sanitation is performed, outputting only valid NTFS paths.
|
If it is set to `"safe"`, only sanitation is performed, with the following characters being removed: `<`, `>`, `:`, `/`, `|`, `?`, `*`, `#`, `\\`, `(`, `)`, `[`, `]` as well as newlines and tabulations. This ensures that the path can be represented on all operating systems.
|
||||||
The following characters are removed: `<`, `>`, `:`, `/`, `|`, `?`, `*`, `#`, `\\`, `(`, `)`, `[`, `]` as well as newlines and tabulations.
|
|
||||||
Additionally, trailing whitespace and dots are removed and whitespaces are replaced by `_`.
|
Additionally, trailing whitespace and dots are removed and whitespaces are replaced by `_`.
|
||||||
|
|
||||||
**NOTE:** To produce URLs containing non-English characters (UTF8), `slugify_paths` needs to be set to `false`.
|
If `slugify.paths` is set to `"off"`, no modifications are made.
|
||||||
|
|
||||||
|
If you want URLs containing non-ASCII characters, `slugify.paths` needs to be set to `"safe"` or `"off"`.
|
||||||
|
|
||||||
### Path from frontmatter
|
### Path from frontmatter
|
||||||
|
|
||||||
|
@ -56,7 +57,7 @@ slug = "femmes-libres-libération-kurde"
|
||||||
This is my article.
|
This is my article.
|
||||||
```
|
```
|
||||||
|
|
||||||
This frontmatter will output the article to `[base_url]/zines/femmes-libres-libération-kurde` with `slugify_paths` disabled, and to `[base_url]/zines/femmes-libres-liberation-kurde` with `slugify_enabled` enabled.
|
This frontmatter will output the article to `[base_url]/zines/femmes-libres-libération-kurde` with `slugify.paths` set to `"safe"` or `"off"`, and to `[base_url]/zines/femmes-libres-liberation-kurde` with the default value for `slugify.paths` of `"on"`.
|
||||||
|
|
||||||
### Path from filename
|
### Path from filename
|
||||||
|
|
||||||
|
@ -66,7 +67,7 @@ When the article's output path is not specified in the frontmatter, it is extrac
|
||||||
|
|
||||||
If the path found starts with a datetime string (`YYYY-mm-dd` or [a RFC3339 datetime](https://www.ietf.org/rfc/rfc3339.txt)) followed by an underscore (`_`) or a dash (`-`), this date is removed from the output path and will be used as the page date (unless already set in the front-matter). Note that the full RFC3339 datetime contains colons, which is not a valid character in a filename on Windows.
|
If the path found starts with a datetime string (`YYYY-mm-dd` or [a RFC3339 datetime](https://www.ietf.org/rfc/rfc3339.txt)) followed by an underscore (`_`) or a dash (`-`), this date is removed from the output path and will be used as the page date (unless already set in the front-matter). Note that the full RFC3339 datetime contains colons, which is not a valid character in a filename on Windows.
|
||||||
|
|
||||||
The output path extracted from the file path is then slugified or not depending on the `slugify_paths` config, as explained previously.
|
The output path extracted from the file path is then slugified or not, depending on the `slugify.paths` config, as explained previously.
|
||||||
|
|
||||||
**Example:** The file `content/blog/2018-10-10-hello-world.md` will generated a page available at will be available at `[base_url]/hello-world`.
|
**Example:** The file `content/blog/2018-10-10-hello-world.md` will generated a page available at will be available at `[base_url]/hello-world`.
|
||||||
|
|
||||||
|
@ -92,6 +93,10 @@ description = ""
|
||||||
# Setting this overrides a date set in the filename.
|
# Setting this overrides a date set in the filename.
|
||||||
date =
|
date =
|
||||||
|
|
||||||
|
# The last updated date of the post, if different from the date.
|
||||||
|
# Same format as `date`.
|
||||||
|
updated =
|
||||||
|
|
||||||
# The weight as defined on the Section page of the documentation.
|
# The weight as defined on the Section page of the documentation.
|
||||||
# If the section variable `sort_by` is set to `weight`, then any page that lacks a `weight`
|
# If the section variable `sort_by` is set to `weight`, then any page that lacks a `weight`
|
||||||
# will not be rendered.
|
# will not be rendered.
|
||||||
|
|
|
@ -13,7 +13,7 @@ A taxonomy has five variables:
|
||||||
- `paginate_by`: if this is set to a number, each term page will be paginated by this much.
|
- `paginate_by`: if this is set to a number, each term page will be paginated by this much.
|
||||||
- `paginate_path`: if set, this path will be used by the paginated page and the page number will be appended after it.
|
- `paginate_path`: if set, this path will be used by the paginated page and the page number will be appended after it.
|
||||||
For example the default would be page/1.
|
For example the default would be page/1.
|
||||||
- `rss`: if set to `true`, an RSS feed will be generated for each term.
|
- `feed`: if set to `true`, a feed will be generated for each term.
|
||||||
- `lang`: only set this if you are making a multilingual site and want to indicate which language this taxonomy is for
|
- `lang`: only set this if you are making a multilingual site and want to indicate which language this taxonomy is for
|
||||||
|
|
||||||
**Example 1:** (one language)
|
**Example 1:** (one language)
|
||||||
|
@ -52,7 +52,7 @@ categories = ["programming"]
|
||||||
|
|
||||||
In a similar manner to how section and pages calculate their output path:
|
In a similar manner to how section and pages calculate their output path:
|
||||||
- the taxonomy name is never slugified
|
- the taxonomy name is never slugified
|
||||||
- the taxonomy entry (eg. as specific tag) is slugified when `slugify_paths` is enabled in the configuration
|
- the taxonomy term (eg. as specific tag) is slugified when `slugify.taxonomies` is enabled (`"on"`, the default) in the configuration
|
||||||
|
|
||||||
The taxonomy pages are then available at the following paths:
|
The taxonomy pages are then available at the following paths:
|
||||||
|
|
||||||
|
|
|
@ -17,11 +17,11 @@ used by Zola as well as their default values are listed below:
|
||||||
# The base URL of the site; the only required configuration variable.
|
# The base URL of the site; the only required configuration variable.
|
||||||
base_url = "mywebsite.com"
|
base_url = "mywebsite.com"
|
||||||
|
|
||||||
# The site title and description; used in RSS by default.
|
# The site title and description; used in feeds by default.
|
||||||
title = ""
|
title = ""
|
||||||
description = ""
|
description = ""
|
||||||
|
|
||||||
# The default language; used in RSS.
|
# The default language; used in feeds.
|
||||||
default_language = "en"
|
default_language = "en"
|
||||||
|
|
||||||
# The site theme to use.
|
# The site theme to use.
|
||||||
|
@ -34,12 +34,17 @@ highlight_code = false
|
||||||
# See below for list of allowed values.
|
# See below for list of allowed values.
|
||||||
highlight_theme = "base16-ocean-dark"
|
highlight_theme = "base16-ocean-dark"
|
||||||
|
|
||||||
# When set to "true", an RSS feed is automatically generated.
|
# When set to "true", a feed is automatically generated.
|
||||||
generate_rss = false
|
generate_feed = false
|
||||||
|
|
||||||
# The number of articles to include in the RSS feed. All items are included if
|
# The filename to use for the feed. Used as the template filename, too.
|
||||||
|
# Defaults to "atom.xml", which has a builtin template that renders an Atom 1.0 feed.
|
||||||
|
# There is also a builtin template "rss.xml" that renders an RSS 2.0 feed.
|
||||||
|
# feed_filename = "atom.xml"
|
||||||
|
|
||||||
|
# The number of articles to include in the feed. All items are included if
|
||||||
# this limit is not set (the default).
|
# this limit is not set (the default).
|
||||||
# rss_limit = 20
|
# feed_limit = 20
|
||||||
|
|
||||||
# When set to "true", files in the `static` directory are hard-linked. Useful for large
|
# When set to "true", files in the `static` directory are hard-linked. Useful for large
|
||||||
# static files. Note that for this to work, both `static` and the
|
# static files. Note that for this to work, both `static` and the
|
||||||
|
@ -50,10 +55,10 @@ generate_rss = false
|
||||||
# The taxonomies to be rendered for the site and their configuration.
|
# The taxonomies to be rendered for the site and their configuration.
|
||||||
# Example:
|
# Example:
|
||||||
# taxonomies = [
|
# taxonomies = [
|
||||||
# {name = "tags", rss = true}, # each tag will have its own RSS feed
|
# {name = "tags", feed = true}, # each tag will have its own feed
|
||||||
# {name = "tags", lang = "fr"}, # you can have taxonomies with the same name in multiple languages
|
# {name = "tags", lang = "fr"}, # you can have taxonomies with the same name in multiple languages
|
||||||
# {name = "categories", paginate_by = 5}, # 5 items per page for a term
|
# {name = "categories", paginate_by = 5}, # 5 items per page for a term
|
||||||
# {name = "authors"}, # Basic definition: no RSS or pagination
|
# {name = "authors"}, # Basic definition: no feed or pagination
|
||||||
# ]
|
# ]
|
||||||
#
|
#
|
||||||
taxonomies = []
|
taxonomies = []
|
||||||
|
@ -61,9 +66,9 @@ taxonomies = []
|
||||||
# The additional languages for the site.
|
# The additional languages for the site.
|
||||||
# Example:
|
# Example:
|
||||||
# languages = [
|
# languages = [
|
||||||
# {code = "fr", rss = true}, # there will be a RSS feed for French content
|
# {code = "fr", feed = true}, # there will be a feed for French content
|
||||||
# {code = "fr", search = true}, # there will be a Search Index for French content
|
# {code = "fr", search = true}, # there will be a Search Index for French content
|
||||||
# {code = "it"}, # there won't be a RSS feed for Italian content
|
# {code = "it"}, # there won't be a feed for Italian content
|
||||||
# ]
|
# ]
|
||||||
#
|
#
|
||||||
languages = []
|
languages = []
|
||||||
|
|
34
docs/content/documentation/templates/feeds.md
Normal file
34
docs/content/documentation/templates/feeds.md
Normal file
|
@ -0,0 +1,34 @@
|
||||||
|
+++
|
||||||
|
title = "Feeds"
|
||||||
|
weight = 50
|
||||||
|
aliases = ["/documentation/templates/rss/"]
|
||||||
|
+++
|
||||||
|
|
||||||
|
If the site `config.toml` file sets `generate_feed = true`, then Zola will
|
||||||
|
generate a feed file for the site, named according to the `feed_filename`
|
||||||
|
setting in `config.toml`, which defaults to `atom.xml`. Given the feed filename
|
||||||
|
`atom.xml`, the generated file will live at `base_url/atom.xml`, based upon the
|
||||||
|
`atom.xml` file in the `templates` directory, or the built-in Atom template.
|
||||||
|
|
||||||
|
`feed_filename` can be set to any value, but built-in templates are provided
|
||||||
|
for `atom.xml` (in the preferred Atom 1.0 format), and `rss.xml` (in the RSS
|
||||||
|
2.0 format). If you choose a different filename (e.g. `feed.xml`), you will
|
||||||
|
need to provide a template yourself.
|
||||||
|
|
||||||
|
**Only pages with a date will be available.**
|
||||||
|
|
||||||
|
The feed template gets five variables:
|
||||||
|
|
||||||
|
- `config`: the site config
|
||||||
|
- `feed_url`: the full url to that specific feed
|
||||||
|
- `last_updated`: the most recent `updated` or `date` field of any post
|
||||||
|
- `pages`: see [page variables](@/documentation/templates/pages-sections.md#page-variables)
|
||||||
|
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)
|
|
@ -13,7 +13,7 @@ to learn more about it first.
|
||||||
All templates live in the `templates` directory. If you are not sure what variables are available in a template,
|
All templates live in the `templates` directory. If you are not sure what variables are available in a template,
|
||||||
you can place `{{ __tera_context }}` in the template to print the whole context.
|
you can place `{{ __tera_context }}` in the template to print the whole context.
|
||||||
|
|
||||||
A few variables are available on all templates except RSS and the sitemap:
|
A few variables are available on all templates except feeds and the sitemap:
|
||||||
|
|
||||||
- `config`: the [configuration](@/documentation/getting-started/configuration.md) without any modifications
|
- `config`: the [configuration](@/documentation/getting-started/configuration.md) without any modifications
|
||||||
- `current_path`: the path (full URL without `base_url`) of the current page, never starting with a `/`
|
- `current_path`: the path (full URL without `base_url`) of the current page, never starting with a `/`
|
||||||
|
@ -36,12 +36,13 @@ section variables. The `page.html` template has access to the page variables.
|
||||||
The page and section variables are described in more detail in the next section.
|
The page and section variables are described in more detail in the next section.
|
||||||
|
|
||||||
## Built-in templates
|
## Built-in templates
|
||||||
Zola comes with three built-in templates: `rss.xml`, `sitemap.xml` and
|
Zola comes with four built-in templates: `atom.xml` and `rss.xml` (described in
|
||||||
`robots.txt` (each is described in its own section of this documentation).
|
[Feeds](@/documentation/templates/feeds.md)), `sitemap.xml` (described in [Sitemap](@/documentation/templates/sitemap.md)),
|
||||||
|
and `robots.txt` (described in [Robots.txt](@/documentation/templates/robots.md)).
|
||||||
Additionally, themes can add their own templates, which will be applied if not
|
Additionally, themes can add their own templates, which will be applied if not
|
||||||
overridden. You can override built-in or theme templates by creating a template with
|
overridden. You can override built-in or theme templates by creating a template with
|
||||||
the same name in the correct path. For example, you can override the RSS template by
|
the same name in the correct path. For example, you can override the Atom template by
|
||||||
creating a `templates/rss.xml` file.
|
creating a `templates/atom.xml` file.
|
||||||
|
|
||||||
## Custom templates
|
## Custom templates
|
||||||
In addition to the standard `index.html`, `section.html` and `page.html` templates,
|
In addition to the standard `index.html`, `section.html` and `page.html` templates,
|
||||||
|
|
|
@ -19,6 +19,8 @@ content: String;
|
||||||
title: String?;
|
title: String?;
|
||||||
description: String?;
|
description: String?;
|
||||||
date: String?;
|
date: String?;
|
||||||
|
// `updated` will be the same as `date` if `date` is specified but `updated` is not in front-matter
|
||||||
|
updated: String?;
|
||||||
slug: String;
|
slug: String;
|
||||||
path: String;
|
path: String;
|
||||||
draft: Bool;
|
draft: Bool;
|
||||||
|
|
|
@ -1,18 +0,0 @@
|
||||||
+++
|
|
||||||
title = "RSS"
|
|
||||||
weight = 50
|
|
||||||
+++
|
|
||||||
|
|
||||||
If the site `config.toml` file sets `generate_rss = true`, then Zola will
|
|
||||||
generate an `rss.xml` page for the site, which will live at `base_url/rss.xml`. To
|
|
||||||
generate the `rss.xml` page, Zola will look for an `rss.xml` file in the `templates`
|
|
||||||
directory or, if one does not exist, it will use the use the built-in rss template.
|
|
||||||
|
|
||||||
**Only pages with a date will be available.**
|
|
||||||
|
|
||||||
The RSS template gets three variables in addition to `config`:
|
|
||||||
|
|
||||||
- `feed_url`: the full url to that specific feed
|
|
||||||
- `last_build_date`: the date of the latest post
|
|
||||||
- `pages`: see [page variables](@/documentation/templates/pages-sections.md#page-variables) for
|
|
||||||
a detailed description of what this contains
|
|
|
@ -25,7 +25,7 @@ A `SitemapEntry` has the following fields:
|
||||||
|
|
||||||
```ts
|
```ts
|
||||||
permalink: String;
|
permalink: String;
|
||||||
date: String?;
|
updated: String?;
|
||||||
extra: Hashmap<String, Any>?;
|
extra: Hashmap<String, Any>?;
|
||||||
```
|
```
|
||||||
|
|
||||||
|
|
|
@ -21,10 +21,10 @@ and `TaxonomyConfig` has the following fields:
|
||||||
|
|
||||||
```ts
|
```ts
|
||||||
name: String,
|
name: String,
|
||||||
slug: String,
|
|
||||||
paginate_by: Number?;
|
paginate_by: Number?;
|
||||||
paginate_path: String?;
|
paginate_path: String?;
|
||||||
rss: Bool;
|
feed: Bool;
|
||||||
|
lang: String;
|
||||||
```
|
```
|
||||||
|
|
||||||
|
|
||||||
|
@ -64,5 +64,5 @@ term: TaxonomyTerm;
|
||||||
lang: String;
|
lang: String;
|
||||||
```
|
```
|
||||||
|
|
||||||
A paginated taxonomy term will also get a `paginator` variable; see the [pagination page]
|
A paginated taxonomy term will also get a `paginator` variable; see the
|
||||||
(@/documentation/templates/pagination.md) for more details.
|
[pagination page](@/documentation/templates/pagination.md) for more details.
|
||||||
|
|
|
@ -100,8 +100,8 @@ Zulma has 3 taxonomies already set internally: `tags`, `cateogories` and `author
|
||||||
```toml
|
```toml
|
||||||
taxonomies = [
|
taxonomies = [
|
||||||
{name = "categories"},
|
{name = "categories"},
|
||||||
{name = "tags", paginate_by = 5, rss = true},
|
{name = "tags", paginate_by = 5, feed = true},
|
||||||
{name = "authors", rss = true},
|
{name = "authors", feed = true},
|
||||||
]
|
]
|
||||||
```
|
```
|
||||||
|
|
||||||
|
|
|
@ -55,9 +55,9 @@ The theme requires tags and categories taxonomies to be enabled in your `config.
|
||||||
|
|
||||||
```toml
|
```toml
|
||||||
taxonomies = [
|
taxonomies = [
|
||||||
# You can enable/disable RSS
|
# You can enable/disable feeds
|
||||||
{name = "categories", rss = true},
|
{name = "categories", feed = true},
|
||||||
{name = "tags", rss = true},
|
{name = "tags", feed = true},
|
||||||
]
|
]
|
||||||
```
|
```
|
||||||
If you want to paginate taxonomies pages, you will need to overwrite the templates
|
If you want to paginate taxonomies pages, you will need to overwrite the templates
|
||||||
|
|
|
@ -48,9 +48,9 @@ The theme requires tags and categories taxonomies to be enabled in your `config.
|
||||||
|
|
||||||
```toml
|
```toml
|
||||||
taxonomies = [
|
taxonomies = [
|
||||||
# You can enable/disable RSS
|
# You can enable/disable feeds
|
||||||
{name = "categories", rss = true},
|
{name = "categories", feed = true},
|
||||||
{name = "tags", rss = true},
|
{name = "tags", feed = true},
|
||||||
]
|
]
|
||||||
```
|
```
|
||||||
If you want to paginate taxonomies pages, you will need to overwrite the templates
|
If you want to paginate taxonomies pages, you will need to overwrite the templates
|
||||||
|
|
0
sublime_themes/dracula.tmTheme
Executable file → Normal file
0
sublime_themes/dracula.tmTheme
Executable file → Normal file
|
@ -2,12 +2,12 @@ title = "My site"
|
||||||
base_url = "https://replace-this-with-your-url.com"
|
base_url = "https://replace-this-with-your-url.com"
|
||||||
highlight_code = true
|
highlight_code = true
|
||||||
compile_sass = true
|
compile_sass = true
|
||||||
generate_rss = true
|
generate_feed = true
|
||||||
theme = "sample"
|
theme = "sample"
|
||||||
slugify_paths = true
|
slugify_paths = true
|
||||||
|
|
||||||
taxonomies = [
|
taxonomies = [
|
||||||
{name = "categories", rss = true},
|
{name = "categories", feed = true},
|
||||||
]
|
]
|
||||||
|
|
||||||
extra_syntaxes = ["syntaxes"]
|
extra_syntaxes = ["syntaxes"]
|
||||||
|
|
|
@ -13,18 +13,18 @@ build_search_index = true
|
||||||
|
|
||||||
default_language = "en"
|
default_language = "en"
|
||||||
|
|
||||||
generate_rss = true
|
generate_feed = true
|
||||||
|
|
||||||
taxonomies = [
|
taxonomies = [
|
||||||
{name = "authors", rss = true},
|
{name = "authors", feed = true},
|
||||||
{name = "auteurs", lang = "fr"},
|
{name = "auteurs", lang = "fr"},
|
||||||
{name = "tags"},
|
{name = "tags"},
|
||||||
{name = "tags", lang = "fr"},
|
{name = "tags", lang = "fr"},
|
||||||
]
|
]
|
||||||
|
|
||||||
languages = [
|
languages = [
|
||||||
{code = "fr", rss = true},
|
{code = "fr", feed = true},
|
||||||
{code = "it", rss = false, search = true },
|
{code = "it", feed = false, search = true },
|
||||||
]
|
]
|
||||||
|
|
||||||
[extra]
|
[extra]
|
||||||
|
|
Loading…
Reference in a new issue