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
|
||||
|
||||
## 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)
|
||||
|
||||
- Fix link checker not looking for anchor with capital id/name
|
||||
|
@ -17,8 +36,6 @@
|
|||
### Breaking
|
||||
- Remove `toc` variable in section/page context and pass it to `page.toc` and `section.toc` instead so they are
|
||||
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
|
||||
- Add zenburn syntax highlighting theme
|
||||
|
|
|
@ -47,15 +47,15 @@ impl Default for Slugify {
|
|||
pub struct Language {
|
||||
/// The language code
|
||||
pub code: String,
|
||||
/// Whether to generate a RSS feed for that language, defaults to `false`
|
||||
pub rss: bool,
|
||||
/// Whether to generate a feed for that language, defaults to `false`
|
||||
pub feed: bool,
|
||||
/// Whether to generate search index for that language, defaults to `false`
|
||||
pub search: bool,
|
||||
}
|
||||
|
||||
impl Default for Language {
|
||||
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
|
||||
pub paginate_by: Option<usize>,
|
||||
pub paginate_path: Option<String>,
|
||||
/// Whether to generate a RSS feed only for each taxonomy term, defaults to false
|
||||
pub rss: bool,
|
||||
/// Whether to generate a feed only for each taxonomy term, defaults to false
|
||||
pub feed: bool,
|
||||
/// The language for that taxonomy, only used in multilingual sites.
|
||||
/// Defaults to the config `default_language` if not set
|
||||
pub lang: String,
|
||||
|
@ -99,7 +99,7 @@ impl Default for Taxonomy {
|
|||
name: String::new(),
|
||||
paginate_by: None,
|
||||
paginate_path: None,
|
||||
rss: false,
|
||||
feed: false,
|
||||
lang: String::new(),
|
||||
}
|
||||
}
|
||||
|
@ -155,10 +155,13 @@ pub struct Config {
|
|||
/// Defaults to "base16-ocean-dark"
|
||||
pub highlight_theme: String,
|
||||
|
||||
/// Whether to generate RSS. Defaults to false
|
||||
pub generate_rss: bool,
|
||||
/// The number of articles to include in the RSS feed. Defaults to including all items.
|
||||
pub rss_limit: Option<usize>,
|
||||
/// Whether to generate a feed. Defaults to false.
|
||||
pub generate_feed: bool,
|
||||
/// The number of articles to include in the feed. Defaults to including all items.
|
||||
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.
|
||||
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
|
||||
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 {
|
||||
"/"
|
||||
|
@ -384,8 +388,9 @@ impl Default for Config {
|
|||
highlight_theme: "base16-ocean-dark".to_string(),
|
||||
default_language: "en".to_string(),
|
||||
languages: Vec::new(),
|
||||
generate_rss: false,
|
||||
rss_limit: None,
|
||||
generate_feed: false,
|
||||
feed_limit: None,
|
||||
feed_filename: "atom.xml".to_string(),
|
||||
hard_link_static: false,
|
||||
taxonomies: Vec::new(),
|
||||
compile_sass: false,
|
||||
|
@ -493,10 +498,10 @@ hello = "world"
|
|||
|
||||
// https://github.com/Keats/gutenberg/issues/486
|
||||
#[test]
|
||||
fn doesnt_add_trailing_slash_to_rss() {
|
||||
fn doesnt_add_trailing_slash_to_feed() {
|
||||
let mut config = Config::default();
|
||||
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]
|
||||
|
|
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>,
|
||||
/// Description in <meta> that appears when linked, e.g. on twitter
|
||||
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)
|
||||
#[serde(default, deserialize_with = "from_toml_datetime")]
|
||||
pub date: Option<String>,
|
||||
|
@ -117,6 +120,7 @@ impl Default for PageFrontMatter {
|
|||
PageFrontMatter {
|
||||
title: None,
|
||||
description: None,
|
||||
updated: None,
|
||||
date: None,
|
||||
datetime: None,
|
||||
datetime_tuple: None,
|
||||
|
|
|
@ -195,7 +195,7 @@ mod tests {
|
|||
#[test]
|
||||
fn can_find_valid_language_in_page() {
|
||||
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(
|
||||
&Path::new("/home/vincent/code/site/content/posts/tutorials/python.fr.md"),
|
||||
&PathBuf::new(),
|
||||
|
@ -208,7 +208,7 @@ mod tests {
|
|||
#[test]
|
||||
fn can_find_valid_language_in_page_with_assets() {
|
||||
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(
|
||||
&Path::new("/home/vincent/code/site/content/posts/tutorials/python/index.fr.md"),
|
||||
&PathBuf::new(),
|
||||
|
@ -234,7 +234,7 @@ mod tests {
|
|||
#[test]
|
||||
fn errors_on_unknown_language_in_page_with_i18n_on() {
|
||||
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(
|
||||
&Path::new("/home/vincent/code/site/content/posts/tutorials/python.fr.md"),
|
||||
&PathBuf::new(),
|
||||
|
@ -246,7 +246,7 @@ mod tests {
|
|||
#[test]
|
||||
fn can_find_valid_language_in_section() {
|
||||
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(
|
||||
&Path::new("/home/vincent/code/site/content/posts/tutorials/_index.fr.md"),
|
||||
&PathBuf::new(),
|
||||
|
@ -273,7 +273,7 @@ mod tests {
|
|||
#[test]
|
||||
fn correct_canonical_after_find_language() {
|
||||
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(
|
||||
&Path::new("/home/vincent/code/site/content/posts/tutorials/python/index.fr.md"),
|
||||
&PathBuf::new(),
|
||||
|
|
|
@ -770,7 +770,7 @@ Hello world
|
|||
#[test]
|
||||
fn can_specify_language_in_filename() {
|
||||
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#"
|
||||
+++
|
||||
+++
|
||||
|
@ -787,7 +787,7 @@ Bonjour le monde"#
|
|||
#[test]
|
||||
fn can_specify_language_in_filename_with_date() {
|
||||
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#"
|
||||
+++
|
||||
+++
|
||||
|
@ -806,7 +806,7 @@ Bonjour le monde"#
|
|||
#[test]
|
||||
fn i18n_frontmatter_path_overrides_default_permalink() {
|
||||
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#"
|
||||
+++
|
||||
path = "bonjour"
|
||||
|
|
|
@ -350,7 +350,7 @@ mod tests {
|
|||
#[test]
|
||||
fn can_specify_language_in_filename() {
|
||||
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#"
|
||||
+++
|
||||
+++
|
||||
|
@ -372,7 +372,7 @@ Bonjour le monde"#
|
|||
#[test]
|
||||
fn can_make_links_to_translated_sections_without_double_trailing_slash() {
|
||||
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#"
|
||||
+++
|
||||
+++
|
||||
|
@ -389,7 +389,7 @@ Bonjour le monde"#
|
|||
#[test]
|
||||
fn can_make_links_to_translated_subsections_with_trailing_slash() {
|
||||
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#"
|
||||
+++
|
||||
+++
|
||||
|
|
|
@ -63,6 +63,7 @@ pub struct SerializingPage<'a> {
|
|||
ancestors: Vec<String>,
|
||||
title: &'a Option<String>,
|
||||
description: &'a Option<String>,
|
||||
updated: &'a Option<String>,
|
||||
date: &'a Option<String>,
|
||||
year: Option<i32>,
|
||||
month: Option<u32>,
|
||||
|
@ -126,6 +127,7 @@ impl<'a> SerializingPage<'a> {
|
|||
title: &page.meta.title,
|
||||
description: &page.meta.description,
|
||||
extra: &page.meta.extra,
|
||||
updated: &page.meta.updated,
|
||||
date: &page.meta.date,
|
||||
year,
|
||||
month,
|
||||
|
@ -182,6 +184,7 @@ impl<'a> SerializingPage<'a> {
|
|||
title: &page.meta.title,
|
||||
description: &page.meta.description,
|
||||
extra: &page.meta.extra,
|
||||
updated: &page.meta.updated,
|
||||
date: &page.meta.date,
|
||||
year,
|
||||
month,
|
||||
|
|
|
@ -6,7 +6,7 @@ use slotmap::DefaultKey;
|
|||
|
||||
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
|
||||
#[allow(clippy::trivially_copy_pass_by_ref)]
|
||||
pub fn sort_actual_pages_by_date(a: &&Page, b: &&Page) -> Ordering {
|
||||
|
|
|
@ -458,7 +458,7 @@ mod tests {
|
|||
#[test]
|
||||
fn can_make_taxonomies_in_multiple_languages() {
|
||||
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);
|
||||
|
||||
config.taxonomies = vec![
|
||||
|
@ -569,7 +569,7 @@ mod tests {
|
|||
let mut config = Config::default();
|
||||
config.slugify.taxonomies = SlugifyStrategy::Safe;
|
||||
config.languages.push(Language {
|
||||
rss: false,
|
||||
feed: false,
|
||||
code: "fr".to_string(),
|
||||
..Language::default()
|
||||
});
|
||||
|
@ -602,7 +602,7 @@ mod tests {
|
|||
let mut config = Config::default();
|
||||
config.slugify.taxonomies = SlugifyStrategy::On;
|
||||
config.languages.push(Language {
|
||||
rss: false,
|
||||
feed: false,
|
||||
code: "fr".to_string(),
|
||||
..Language::default()
|
||||
});
|
||||
|
|
|
@ -395,7 +395,17 @@ pub fn after_template_change(site: &mut Site, path: &Path) -> Result<()> {
|
|||
|
||||
match filename {
|
||||
"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(),
|
||||
"robots.txt" => site.render_robots(),
|
||||
"single.html" | "list.html" => site.render_taxonomies(),
|
||||
|
|
|
@ -108,7 +108,7 @@ base_url = "https://replace-this-with-your-url.com"
|
|||
theme = "sample"
|
||||
|
||||
taxonomies = [
|
||||
{name = "tags", rss = true},
|
||||
{name = "tags", feed = true},
|
||||
{name = "categories"}
|
||||
]
|
||||
|
||||
|
|
|
@ -35,12 +35,19 @@ fn bench_render_sitemap(b: &mut test::Bencher) {
|
|||
}
|
||||
|
||||
#[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 tmp_dir = tempdir().expect("create temp dir");
|
||||
let public = &tmp_dir.path().join("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]
|
||||
|
|
|
@ -8,13 +8,15 @@ use std::sync::{Arc, Mutex, RwLock};
|
|||
use glob::glob;
|
||||
use rayon::prelude::*;
|
||||
use sass_rs::{compile_file, Options as SassOptions, OutputStyle};
|
||||
use serde_derive::Serialize;
|
||||
use tera::{Context, Tera};
|
||||
|
||||
use config::{get_config, Config};
|
||||
use config::{get_config, Config, Taxonomy as TaxonomyConfig};
|
||||
use errors::{bail, Error, ErrorKind, Result};
|
||||
use front_matter::InsertAnchor;
|
||||
use library::{
|
||||
find_taxonomies, sort_actual_pages_by_date, Library, Page, Paginator, Section, Taxonomy,
|
||||
TaxonomyItem,
|
||||
};
|
||||
use link_checker::check_url;
|
||||
use templates::{global_fns, render_redirect_template, ZOLA_TERA};
|
||||
|
@ -45,6 +47,23 @@ pub struct Site {
|
|||
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 {
|
||||
/// 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
|
||||
|
@ -626,15 +645,17 @@ impl Site {
|
|||
}
|
||||
|
||||
/// 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 {
|
||||
return html.replace(
|
||||
"</body>",
|
||||
&format!(
|
||||
r#"<script src="/livereload.js?port={}&mindelay=10"></script></body>"#,
|
||||
port
|
||||
),
|
||||
let script = format!(
|
||||
r#"<script src="/livereload.js?port={}&mindelay=10"></script>"#,
|
||||
port,
|
||||
);
|
||||
if let Some(index) = html.rfind("</body>") {
|
||||
html.insert_str(index, &script);
|
||||
} else {
|
||||
html.push_str(&script);
|
||||
}
|
||||
}
|
||||
|
||||
html
|
||||
|
@ -743,8 +764,9 @@ impl Site {
|
|||
self.render_sitemap()?;
|
||||
|
||||
let library = self.library.read().unwrap();
|
||||
if self.config.generate_rss {
|
||||
let pages = if self.config.is_multilingual() {
|
||||
if self.config.generate_feed {
|
||||
let is_multilingual = self.config.is_multilingual();
|
||||
let pages = if is_multilingual {
|
||||
library
|
||||
.pages_values()
|
||||
.iter()
|
||||
|
@ -754,16 +776,26 @@ impl Site {
|
|||
} else {
|
||||
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 {
|
||||
if !lang.rss {
|
||||
if !lang.feed {
|
||||
continue;
|
||||
}
|
||||
let pages =
|
||||
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()?;
|
||||
|
@ -981,10 +1013,16 @@ impl Site {
|
|||
create_file(&path.join("index.html"), &self.inject_livereload(single_output))?;
|
||||
}
|
||||
|
||||
if taxonomy.kind.rss {
|
||||
self.render_rss_feed(
|
||||
if taxonomy.kind.feed {
|
||||
self.render_feed(
|
||||
item.pages.iter().map(|p| library.get_page_by_key(*p)).collect(),
|
||||
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 {
|
||||
Ok(())
|
||||
|
@ -1043,30 +1081,39 @@ impl Site {
|
|||
Ok(())
|
||||
}
|
||||
|
||||
/// Renders a RSS 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
|
||||
/// Renders a feed for the given path and at the given path
|
||||
/// If both arguments are `None`, it will render only the feed for the whole
|
||||
/// site at the root folder.
|
||||
pub fn render_rss_feed(
|
||||
pub fn render_feed(
|
||||
&self,
|
||||
all_pages: Vec<&Page>,
|
||||
base_path: Option<&PathBuf>,
|
||||
lang: &str,
|
||||
taxonomy_and_item: Option<(&TaxonomyConfig, &TaxonomyItem)>,
|
||||
) -> Result<()> {
|
||||
ensure_directory_exists(&self.output_path)?;
|
||||
|
||||
let mut context = Context::new();
|
||||
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() {
|
||||
return Ok(());
|
||||
}
|
||||
|
||||
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();
|
||||
// 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
|
||||
.iter()
|
||||
.take(num_entries)
|
||||
|
@ -1075,16 +1122,28 @@ impl Site {
|
|||
|
||||
context.insert("pages", &p);
|
||||
context.insert("config", &self.config);
|
||||
context.insert("lang", lang);
|
||||
|
||||
let rss_feed_url = if let Some(ref base) = base_path {
|
||||
self.config.make_permalink(&base.join("rss.xml").to_string_lossy().replace('\\', "/"))
|
||||
let feed_filename = &self.config.feed_filename;
|
||||
let feed_url = if let Some(ref base) = base_path {
|
||||
self.config.make_permalink(
|
||||
&base
|
||||
.join(feed_filename)
|
||||
.to_string_lossy()
|
||||
.replace('\\', "/"),
|
||||
)
|
||||
} 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 {
|
||||
let mut output_path = self.output_path.clone();
|
||||
|
@ -1094,9 +1153,9 @@ impl Site {
|
|||
create_directory(&output_path)?;
|
||||
}
|
||||
}
|
||||
create_file(&output_path.join("rss.xml"), feed)?;
|
||||
create_file(&output_path.join(feed_filename), feed)?;
|
||||
} else {
|
||||
create_file(&self.output_path.join("rss.xml"), feed)?;
|
||||
create_file(&self.output_path.join(feed_filename), feed)?;
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
|
|
|
@ -14,7 +14,7 @@ use tera::{Map, Value};
|
|||
#[derive(Debug, Serialize)]
|
||||
pub struct SitemapEntry<'a> {
|
||||
pub permalink: Cow<'a, str>,
|
||||
pub date: Option<String>,
|
||||
pub updated: Option<String>,
|
||||
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> SitemapEntry<'a> {
|
||||
pub fn new(permalink: Cow<'a, str>, date: Option<String>) -> Self {
|
||||
SitemapEntry { permalink, date, extra: None }
|
||||
pub fn new(permalink: Cow<'a, str>, updated: Option<String>) -> Self {
|
||||
SitemapEntry { permalink, updated, extra: None }
|
||||
}
|
||||
|
||||
pub fn add_extra(&mut self, extra: &'a Map<String, Value>) {
|
||||
|
@ -65,11 +65,10 @@ pub fn find_entries<'a>(
|
|||
.pages_values()
|
||||
.iter()
|
||||
.map(|p| {
|
||||
let date = match p.meta.date {
|
||||
Some(ref d) => Some(d.to_string()),
|
||||
None => None,
|
||||
};
|
||||
let mut entry = SitemapEntry::new(Cow::Borrowed(&p.permalink), date);
|
||||
let mut entry = SitemapEntry::new(
|
||||
Cow::Borrowed(&p.permalink),
|
||||
p.meta.updated.clone().or_else(|| p.meta.date.clone()),
|
||||
);
|
||||
entry.add_extra(&p.meta.extra);
|
||||
entry
|
||||
})
|
||||
|
|
|
@ -152,7 +152,7 @@ fn can_build_site_without_live_reload() {
|
|||
// We do have categories
|
||||
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/rss.xml"), true);
|
||||
assert_eq!(file_exists!(public, "categories/a-category/atom.xml"), true);
|
||||
// But no tags
|
||||
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
|
||||
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/rss.xml"), true);
|
||||
assert_eq!(file_exists!(public, "categories/a-category/atom.xml"), true);
|
||||
// But no tags
|
||||
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/a/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!(
|
||||
public,
|
||||
"categories/a/rss.xml",
|
||||
"https://replace-this-with-your-url.com/categories/a/rss.xml"
|
||||
"categories/a/atom.xml",
|
||||
"https://replace-this-with-your-url.com/categories/a/atom.xml"
|
||||
));
|
||||
// Extending from a theme works
|
||||
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(),
|
||||
paginate_by: Some(2),
|
||||
paginate_path: None,
|
||||
rss: true,
|
||||
feed: true,
|
||||
lang: site.config.default_language.clone(),
|
||||
});
|
||||
site.load().unwrap();
|
||||
|
@ -547,9 +547,9 @@ fn can_build_site_with_pagination_for_taxonomy() {
|
|||
|
||||
// Tags
|
||||
assert!(file_exists!(public, "tags/index.html"));
|
||||
// With RSS
|
||||
assert!(file_exists!(public, "tags/a/rss.xml"));
|
||||
assert!(file_exists!(public, "tags/b/rss.xml"));
|
||||
// With Atom
|
||||
assert!(file_exists!(public, "tags/a/atom.xml"));
|
||||
assert!(file_exists!(public, "tags/b/atom.xml"));
|
||||
// And pagination!
|
||||
assert!(file_exists!(public, "tags/a/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]
|
||||
fn can_build_rss_feed() {
|
||||
fn can_build_feed() {
|
||||
let (_, _tmp_dir, public) = build_site("test_site");
|
||||
|
||||
assert!(&public.exists());
|
||||
assert!(file_exists!(public, "rss.xml"));
|
||||
assert!(file_exists!(public, "atom.xml"));
|
||||
// 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
|
||||
assert!(file_contains!(public, "rss.xml", "Simple article with shortcodes"));
|
||||
assert!(file_contains!(public, "atom.xml", "Simple article with shortcodes"));
|
||||
}
|
||||
|
||||
#[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/it/blog/something-else/"));
|
||||
|
||||
// one rss per language
|
||||
assert!(file_exists!(public, "rss.xml"));
|
||||
assert!(file_contains!(public, "rss.xml", "https://example.com/blog/something-else/"));
|
||||
assert!(!file_contains!(public, "rss.xml", "https://example.com/fr/blog/something-else/"));
|
||||
assert!(file_exists!(public, "fr/rss.xml"));
|
||||
assert!(!file_contains!(public, "fr/rss.xml", "https://example.com/blog/something-else/"));
|
||||
assert!(file_contains!(public, "fr/rss.xml", "https://example.com/fr/blog/something-else/"));
|
||||
// Italian doesn't have RSS enabled
|
||||
assert!(!file_exists!(public, "it/rss.xml"));
|
||||
// one feed per language
|
||||
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/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_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", 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
|
||||
// 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", "Vincent"));
|
||||
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_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_contains!(public, "fr/auteurs/index.html", "Queen"));
|
||||
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_contains!(public, "fr/tags/index.html", "bonjour"));
|
||||
|
|
|
@ -1,10 +1,3 @@
|
|||
<!doctype html>
|
||||
<html>
|
||||
<head>
|
||||
<title>File Not Found: 404.</title>
|
||||
</head>
|
||||
<body>
|
||||
<h1>Oops!</h1>
|
||||
<h2>File Not Found: 404.</h2>
|
||||
</body>
|
||||
</html>
|
||||
<title>404 Not Found</title>
|
||||
<h1>404 Not Found</h1>
|
||||
|
|
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>
|
||||
<html>
|
||||
<head>
|
||||
<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>
|
||||
</body>
|
||||
</html>
|
||||
<!doctype html>
|
||||
<meta charset="utf-8">
|
||||
<link rel="canonical" href="{{ url | safe }}">
|
||||
<meta http-equiv="refresh" content="0;url={{ url | safe }}">
|
||||
<title>Redirect</title>
|
||||
<p><a href="{{ url | safe }}">Click here</a> to be redirected.</p>
|
||||
|
|
|
@ -7,8 +7,8 @@
|
|||
<generator>Zola</generator>
|
||||
<language>{{ config.default_language }}</language>
|
||||
<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>
|
||||
{% for page in pages %}
|
||||
<lastBuildDate>{{ last_updated | date(format="%a, %d %b %Y %H:%M:%S %z") }}</lastBuildDate>
|
||||
{%- for page in pages %}
|
||||
<item>
|
||||
<title>{{ page.title }}</title>
|
||||
<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>
|
||||
<description>{% if page.summary %}{{ page.summary }}{% else %}{{ page.content }}{% endif %}</description>
|
||||
</item>
|
||||
{% endfor %}
|
||||
{%- endfor %}
|
||||
</channel>
|
||||
</rss>
|
||||
|
|
|
@ -1,7 +1,3 @@
|
|||
<div {% if class %}class="{{class}}"{% endif %}>
|
||||
<iframe src="https://www.streamable.com/e/{{id}}"
|
||||
scrolling="no"
|
||||
frameborder="0"
|
||||
allowfullscreen mozallowfullscreen webkitallowfullscreen>
|
||||
</iframe>
|
||||
<iframe src="https://www.streamable.com/e/{{id}}" scrolling="no" frameborder="0" allowfullscreen mozallowfullscreen webkitallowfullscreen></iframe>
|
||||
</div>
|
||||
|
|
|
@ -1,4 +1,3 @@
|
|||
<div {% if class %}class="{{class}}"{% endif %}>
|
||||
<iframe src="//player.vimeo.com/video/{{id}}" webkitallowfullscreen mozallowfullscreen allowfullscreen>
|
||||
</iframe>
|
||||
<iframe src="//player.vimeo.com/video/{{id}}" webkitallowfullscreen mozallowfullscreen allowfullscreen></iframe>
|
||||
</div>
|
||||
|
|
|
@ -1,4 +1,3 @@
|
|||
<div {% if class %}class="{{class}}"{% endif %}>
|
||||
<iframe src="https://www.youtube.com/embed/{{id}}{% if autoplay %}?autoplay=1{% endif %}" webkitallowfullscreen mozallowfullscreen allowfullscreen>
|
||||
</iframe>
|
||||
<iframe src="https://www.youtube.com/embed/{{id}}{% if autoplay %}?autoplay=1{% endif %}" webkitallowfullscreen mozallowfullscreen allowfullscreen></iframe>
|
||||
</div>
|
||||
|
|
|
@ -1,11 +1,11 @@
|
|||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<urlset xmlns="http://www.sitemaps.org/schemas/sitemap/0.9">
|
||||
{% for sitemap_entry in entries %}
|
||||
{%- for sitemap_entry in entries %}
|
||||
<url>
|
||||
<loc>{{ sitemap_entry.permalink | escape_xml | safe }}</loc>
|
||||
{% if sitemap_entry.date %}
|
||||
<lastmod>{{ sitemap_entry.date }}</lastmod>
|
||||
{% endif %}
|
||||
{%- if sitemap_entry.updated %}
|
||||
<lastmod>{{ sitemap_entry.updated }}</lastmod>
|
||||
{%- endif %}
|
||||
</url>
|
||||
{% endfor %}
|
||||
{%- endfor %}
|
||||
</urlset>
|
||||
|
|
|
@ -1,8 +1,8 @@
|
|||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<sitemapindex xmlns="http://www.sitemaps.org/schemas/sitemap/0.9">
|
||||
{% for sitemap in sitemaps %}
|
||||
{%- for sitemap in sitemaps %}
|
||||
<sitemap>
|
||||
<loc>{{ sitemap }}</loc>
|
||||
</sitemap>
|
||||
{% endfor %}
|
||||
{%- endfor %}
|
||||
</sitemapindex>
|
|
@ -11,6 +11,7 @@ lazy_static! {
|
|||
let mut tera = Tera::default();
|
||||
tera.add_raw_templates(vec![
|
||||
("__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/sitemap.xml", include_str!("builtins/sitemap.xml")),
|
||||
("__zola_builtins/robots.txt", include_str!("builtins/robots.txt")),
|
||||
|
|
|
@ -5,8 +5,9 @@ weight = 50
|
|||
|
||||
## Heading id and anchor insertion
|
||||
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.
|
||||
if `slugify_paths` is disabled, whitespaces are replaced by `_` and the following characters are stripped: `#`, `%`, `<`, `>`, `[`, `]`, `(`, `)`, \`, `^`, `{`, `|`, `}`.
|
||||
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 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
|
||||
For example:
|
||||
|
||||
|
|
|
@ -11,9 +11,9 @@ to your `config.toml`. For example:
|
|||
|
||||
```toml
|
||||
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 = "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
|
||||
|
||||
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).
|
||||
Otherwise, a simpler sanitation is performed, outputting only valid NTFS paths.
|
||||
The following characters are removed: `<`, `>`, `:`, `/`, `|`, `?`, `*`, `#`, `\\`, `(`, `)`, `[`, `]` as well as newlines and tabulations.
|
||||
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).
|
||||
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.
|
||||
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
|
||||
|
||||
|
@ -56,7 +57,7 @@ slug = "femmes-libres-libération-kurde"
|
|||
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
|
||||
|
||||
|
@ -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.
|
||||
|
||||
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`.
|
||||
|
||||
|
@ -92,6 +93,10 @@ description = ""
|
|||
# Setting this overrides a date set in the filename.
|
||||
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.
|
||||
# If the section variable `sort_by` is set to `weight`, then any page that lacks a `weight`
|
||||
# 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_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.
|
||||
- `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
|
||||
|
||||
**Example 1:** (one language)
|
||||
|
@ -52,7 +52,7 @@ categories = ["programming"]
|
|||
|
||||
In a similar manner to how section and pages calculate their output path:
|
||||
- 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:
|
||||
|
||||
|
|
|
@ -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.
|
||||
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 = ""
|
||||
description = ""
|
||||
|
||||
# The default language; used in RSS.
|
||||
# The default language; used in feeds.
|
||||
default_language = "en"
|
||||
|
||||
# The site theme to use.
|
||||
|
@ -34,12 +34,17 @@ highlight_code = false
|
|||
# See below for list of allowed values.
|
||||
highlight_theme = "base16-ocean-dark"
|
||||
|
||||
# When set to "true", an RSS feed is automatically generated.
|
||||
generate_rss = false
|
||||
# When set to "true", a feed is automatically generated.
|
||||
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).
|
||||
# rss_limit = 20
|
||||
# feed_limit = 20
|
||||
|
||||
# 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
|
||||
|
@ -50,10 +55,10 @@ generate_rss = false
|
|||
# The taxonomies to be rendered for the site and their configuration.
|
||||
# Example:
|
||||
# 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 = "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 = []
|
||||
|
@ -61,9 +66,9 @@ taxonomies = []
|
|||
# The additional languages for the site.
|
||||
# Example:
|
||||
# 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 = "it"}, # there won't be a RSS feed for Italian content
|
||||
# {code = "it"}, # there won't be a feed for Italian content
|
||||
# ]
|
||||
#
|
||||
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,
|
||||
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
|
||||
- `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.
|
||||
|
||||
## Built-in templates
|
||||
Zola comes with three built-in templates: `rss.xml`, `sitemap.xml` and
|
||||
`robots.txt` (each is described in its own section of this documentation).
|
||||
Zola comes with four built-in templates: `atom.xml` and `rss.xml` (described in
|
||||
[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
|
||||
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
|
||||
creating a `templates/rss.xml` file.
|
||||
the same name in the correct path. For example, you can override the Atom template by
|
||||
creating a `templates/atom.xml` file.
|
||||
|
||||
## Custom templates
|
||||
In addition to the standard `index.html`, `section.html` and `page.html` templates,
|
||||
|
|
|
@ -19,6 +19,8 @@ content: String;
|
|||
title: String?;
|
||||
description: 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;
|
||||
path: String;
|
||||
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
|
||||
permalink: String;
|
||||
date: String?;
|
||||
updated: String?;
|
||||
extra: Hashmap<String, Any>?;
|
||||
```
|
||||
|
||||
|
|
|
@ -21,10 +21,10 @@ and `TaxonomyConfig` has the following fields:
|
|||
|
||||
```ts
|
||||
name: String,
|
||||
slug: String,
|
||||
paginate_by: Number?;
|
||||
paginate_path: String?;
|
||||
rss: Bool;
|
||||
feed: Bool;
|
||||
lang: String;
|
||||
```
|
||||
|
||||
|
||||
|
@ -64,5 +64,5 @@ term: TaxonomyTerm;
|
|||
lang: String;
|
||||
```
|
||||
|
||||
A paginated taxonomy term will also get a `paginator` variable; see the [pagination page]
|
||||
(@/documentation/templates/pagination.md) for more details.
|
||||
A paginated taxonomy term will also get a `paginator` variable; see the
|
||||
[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
|
||||
taxonomies = [
|
||||
{name = "categories"},
|
||||
{name = "tags", paginate_by = 5, rss = true},
|
||||
{name = "authors", rss = true},
|
||||
{name = "tags", paginate_by = 5, feed = true},
|
||||
{name = "authors", feed = true},
|
||||
]
|
||||
```
|
||||
|
||||
|
|
|
@ -55,9 +55,9 @@ The theme requires tags and categories taxonomies to be enabled in your `config.
|
|||
|
||||
```toml
|
||||
taxonomies = [
|
||||
# You can enable/disable RSS
|
||||
{name = "categories", rss = true},
|
||||
{name = "tags", rss = true},
|
||||
# You can enable/disable feeds
|
||||
{name = "categories", feed = true},
|
||||
{name = "tags", feed = true},
|
||||
]
|
||||
```
|
||||
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
|
||||
taxonomies = [
|
||||
# You can enable/disable RSS
|
||||
{name = "categories", rss = true},
|
||||
{name = "tags", rss = true},
|
||||
# You can enable/disable feeds
|
||||
{name = "categories", feed = true},
|
||||
{name = "tags", feed = true},
|
||||
]
|
||||
```
|
||||
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"
|
||||
highlight_code = true
|
||||
compile_sass = true
|
||||
generate_rss = true
|
||||
generate_feed = true
|
||||
theme = "sample"
|
||||
slugify_paths = true
|
||||
|
||||
taxonomies = [
|
||||
{name = "categories", rss = true},
|
||||
{name = "categories", feed = true},
|
||||
]
|
||||
|
||||
extra_syntaxes = ["syntaxes"]
|
||||
|
|
|
@ -13,18 +13,18 @@ build_search_index = true
|
|||
|
||||
default_language = "en"
|
||||
|
||||
generate_rss = true
|
||||
generate_feed = true
|
||||
|
||||
taxonomies = [
|
||||
{name = "authors", rss = true},
|
||||
{name = "authors", feed = true},
|
||||
{name = "auteurs", lang = "fr"},
|
||||
{name = "tags"},
|
||||
{name = "tags", lang = "fr"},
|
||||
]
|
||||
|
||||
languages = [
|
||||
{code = "fr", rss = true},
|
||||
{code = "it", rss = false, search = true },
|
||||
{code = "fr", feed = true},
|
||||
{code = "it", feed = false, search = true },
|
||||
]
|
||||
|
||||
[extra]
|
||||
|
|
Loading…
Reference in a new issue