diff --git a/components/content/src/front_matter/page.rs b/components/content/src/front_matter/page.rs index 4615ef6618..6d277e4cd6 100644 --- a/components/content/src/front_matter/page.rs +++ b/components/content/src/front_matter/page.rs @@ -39,6 +39,8 @@ pub struct PageFrontMatter { pub datetime_tuple: Option<(i32, u8, u8)>, /// Whether this page is a draft pub draft: bool, + /// Whether this page is hidden + pub hidden: Option, /// Prevent generation of a folder for current page /// Defaults to `true` #[serde(skip_serializing)] @@ -155,6 +157,7 @@ impl Default for PageFrontMatter { datetime: None, datetime_tuple: None, draft: false, + hidden: None, render: true, slug: None, path: None, diff --git a/components/content/src/front_matter/section.rs b/components/content/src/front_matter/section.rs index 2eea5dd006..41ea69e065 100644 --- a/components/content/src/front_matter/section.rs +++ b/components/content/src/front_matter/section.rs @@ -47,6 +47,8 @@ pub struct SectionFrontMatter { /// to be used directly, like a posts section in a personal site #[serde(skip_serializing)] pub render: bool, + /// Whether to render all of the pages in this section, but not list them by defaulting their `hidden` to `true` + pub hidden: Option, /// Whether to redirect when landing on that section. Defaults to `None`. /// Useful for the same reason as `render` but when you don't want a 404 when /// landing on the root section page @@ -107,6 +109,7 @@ impl Default for SectionFrontMatter { paginate_reversed: false, paginate_path: DEFAULT_PAGINATE_PATH.to_string(), render: true, + hidden: None, redirect_to: None, insert_anchor_links: None, in_search_index: true, diff --git a/components/content/src/library.rs b/components/content/src/library.rs index 990de93eac..4679887f01 100644 --- a/components/content/src/library.rs +++ b/components/content/src/library.rs @@ -176,7 +176,36 @@ impl Library { pub fn sort_section_pages(&mut self) { let mut updates = AHashMap::new(); for (path, section) in &self.sections { - let pages: Vec<_> = section.pages.iter().map(|p| &self.pages[p]).collect(); + let pages: Vec<_> = section + .pages + .iter() + .map(|p| &self.pages[p]) + .filter(|page| { + !page + .ancestors + .iter() + .map(|ancestor| { + // Go through each ancestor in the library map, + // find it based on relative anchestor path + // and map the hidden (Option) + &self + .sections + .values() + .find(|section| §ion.file.relative == ancestor) + .expect("to find ancestor of page") + .meta + .hidden + }) + // Add page hidden meta to the chain, to fold into final value + .chain([page.meta.hidden].iter()) + // Accumulate together as `accumulator || boolean` unless value explicitely + // set by a section's or page's frontmatter as `hidden = false` + .fold(false, |accumulator, boolean| match (accumulator, boolean) { + (_, Some(value)) => *value, + (value, None) => value, + }) + }) + .collect(); let (sorted_pages, cannot_be_sorted_pages) = match section.meta.sort_by { SortBy::None => continue, _ => sort_pages(&pages, section.meta.sort_by), diff --git a/components/content/src/pagination.rs b/components/content/src/pagination.rs index c620bb3a72..5589f2ea54 100644 --- a/components/content/src/pagination.rs +++ b/components/content/src/pagination.rs @@ -130,9 +130,41 @@ impl<'a> Paginator<'a> { for p in &*self.all_pages { let page = &library.pages[p]; + if !page.meta.render { continue; } + + // Check if any ancestor or page is hidden and allows any + // `hidden = false` to override prior explicit or + // inferred `hidden = true` + let is_hidden = page + .ancestors + .iter() + .map(|ancestor| { + // Go through each ancestor in the library map, + // find it based on relative anchestor path + // and map the hidden (Option) + library + .sections + .values() + .find(|section| §ion.file.relative == ancestor)? + .meta + .hidden + }) + // Add page hidden meta to the chain, to fold into final value + .chain([page.meta.hidden].into_iter()) + // Accumulate together as `accumulator || boolean` unless value explicitely + // set by a section's or page's frontmatter as `hidden = false` + .fold(false, |accumulator, boolean| match (accumulator, boolean) { + (_, Some(value)) => value, + (value, None) => value, + }); + + if is_hidden { + continue; + } + current_page.push(SerializingPage::new(page, Some(library), false)); if current_page.len() == self.paginate_by { diff --git a/components/site/src/feeds.rs b/components/site/src/feeds.rs index 435dfea5d2..8698c7fc19 100644 --- a/components/site/src/feeds.rs +++ b/components/site/src/feeds.rs @@ -65,6 +65,31 @@ pub fn render_feeds( let num_entries = site.config.feed_limit.unwrap_or(pages.len()); let p = pages .iter() + .filter(|page| { + !page + .ancestors + .iter() + .map(|ancestor| { + // Go through each ancestor in the library map, + // find it based on relative anchestor path + // and map the hidden (Option) + &library + .sections + .values() + .find(|section| §ion.file.relative == ancestor) + .expect("page to have ancestor") + .meta + .hidden + }) + // Add page hidden meta to the chain, to fold into final value + .chain([page.meta.hidden].iter()) + // Accumulate together as `accumulator || boolean` unless value explicitely + // set by a section's or page's frontmatter as `hidden = false` + .fold(false, |accumulator, boolean| match (accumulator, boolean) { + (_, Some(value)) => *value, + (value, None) => value, + }) + }) .take(num_entries) .map(|x| x.serialize_without_siblings(&library)) .collect::>(); diff --git a/docs/content/documentation/content/page.md b/docs/content/documentation/content/page.md index faff548a07..3ee18ae542 100644 --- a/docs/content/documentation/content/page.md +++ b/docs/content/documentation/content/page.md @@ -112,6 +112,10 @@ weight = 0 # A draft page is only loaded if the `--drafts` flag is passed to `zola build`, `zola serve` or `zola check`. draft = false +# A hidden page is loaded and created, but won't be added to Paginators, +# set to true to hide page or false to override a parent section's `hidden = true` +hidden = false + # When set to "false" Zola will not create a separate folder with index.html inside for this page. render = false diff --git a/docs/content/documentation/content/section.md b/docs/content/documentation/content/section.md index 73ec1e50ea..196b829460 100644 --- a/docs/content/documentation/content/section.md +++ b/docs/content/documentation/content/section.md @@ -48,6 +48,10 @@ description = "" # A draft section is only loaded if the `--drafts` flag is passed to `zola build`, `zola serve` or `zola check`. draft = false +# A hidden section is loaded and created, but won't be added to Paginators, +# set to true to hide section's pages or false to override a parent section's `hidden = true` +hidden = false + # Used to sort pages by "date", "update_date", "title", "title_bytes", "weight", "slug" or "none". See below for more information. sort_by = "none"