Generate tag pages

21 views
Skip to first unread message

S. Qiouyi Lu

unread,
Aug 20, 2026, 3:24:48 PMAug 20
to nanoc
Hi!

I'm trying to programmatically generate tag pages instead of manually creating them.

I am making a log of reviews of wrestling matches. Each review has a wrestler metadata attribute and tags. I'll start with the wrestlers because it's slightly more complicated, involving each wrestler being tagged with a name and a slug.

I want the process to be:

1. Compile pages
2. Check if page has @item[:wrestlers]
3. If it does, find all pages in the /wrestler/ subdirectory
4. Loop through each wrestler listed in the review data, which has wrestler[:name] and wrestler[:slug]
5. If /wrestler/wrestler[:slug] exists, move on to next wrestler[:slug]
6. If /wrestler/wrestler[:slug] does not exist, create new file /wrestler/wrestler[:slug], which populates metadata headers with wrestler[:name] and wrestler[:slug], then move on to next wrestler

However, I can't seem to get the checking an array portion to match things properly:

if @item[:wrestlers]
wrestlers = @items.find_all('/interests/pro-wrestling/match-log/wrestler/*.md')
@item[:wrestlers].each do | wrestler |
puts wrestler[:slug]
if wrestlers.include?(wrestler[:slug])
puts "Tag page exists"
else
puts "Tag page not found"
end
end
end

Sample review header:

---
title: "Komander vs. Ariya Daivari"
layout: "/wrestling.*"
template: "match-log"
wrestlers:
- name: "Komander"
slug: "komander"
- name: "Ariya Daivari"
slug: "ariya-daivari"
promotions:
- "ROH"
event_name: "ROH YouTube Special Episode #13"
event_date: 2026-08-18
date_watched: 2026-08-18
is_rewatch: false
rewatch_number:
rating: "⭐️⭐️⭐️"
rating_numerical: 3.0
tags:
breadcrumbs:
- label: "Home"
url: "/"
- label: "Interests"
url: "/interests/"
- label: "Professional Wrestling"
url: "/interests/pro-wrestling/"
- label: "Match Log"
url: "/interests/pro-wrestling/match-log/"
---

The template for each wrestler page, where NAME and SLUG are to be auto-populated, and layouting will be handled automatically to collate reviews:

---
title: "Match Log: NAME"
layout: "/wrestling.*"
wrestler: "SLUG"
template: "match-log-wrestler"
breadcrumbs:
- label: "Home"
url: "/"
- label: "Interests"
url: "/interests/"
- label: "Professional Wrestling"
url: "/interests/pro-wrestling/"
- label: "Match Log"
url: "/interests/pro-wrestling/match-log/"
- label: "Wrestlers"
url: "/interests/pro-wrestling/match-log/wrestler/"
breadcrumb_label: "NAME"
---

Please let me know if there's anything else I should provide or any further explanation that would clarify this.

Thanks so much!
S.

Denis Defreyne

unread,
Aug 23, 2026, 3:21:36 AMAug 23
to na...@googlegroups.com
Hi S,

In this line:

  wrestlers = @items.find_all('/interests/pro-wrestling/match-log/wrestler/*.md')

the wrestlers collection is a collection of items, not slugs. If you want the slugs, you can do e.g.

  wrestler_slugs = wrestlers.map { |item| item[:slug] }

Then, use wrestler_slugs instead of wrestlers here:

  if wrestler_slugs.include?(wrestler[:slug])

Let me know how that works!

Best,

--
---
You received this message because you are subscribed to the Google Groups "nanoc" group.
To unsubscribe from this group and stop receiving emails from it, send an email to nanoc+un...@googlegroups.com.

S. Qiouyi Lu

unread,
Aug 24, 2026, 1:00:32 AMAug 24
to nanoc
Thank you! This gets the terminal to output the expected response:

if @item[:wrestlers]
wrestlers = @items.find_all('/interests/pro-wrestling/match-log/wrestler/*.md')
wrestler_slugs = wrestlers.map { |item| item[:wrestler] }
@item[:wrestlers].each do | wrestler |
puts wrestler[:slug]
if wrestler_slugs.include?(wrestler[:slug])
puts "Tag page exists"
else
puts "Tag page not found"
end
end
end

My question now is: can I use this logic to generate a Markdown file to put back into /content, or will this only create pages for /output? Most of the time an output page would be fine, but sometimes I want to add additional notes and being able to do that in the Markdown in /content would be ideal.

S.

Denis Defreyne

unread,
Aug 27, 2026, 2:57:15 AMAug 27
to na...@googlegroups.com
Hi S,

My recommended way of doing this would be to use the preprocess block to create in-memory items on the fly. Here’s what this could look like for a blog where the yearly archive pages are created automatically:

preprocess do
  def create_year_pages
    # collect years
    years = Set.new
    @items.find_all("/articles/*.md").each do |item|
      years << item[:year]
    end

    # create item for each year
    years.each do |year|
      @items.create(
        "<%= sorted_article_list_for_year(#{year}) %>",
        {
          title: "Year #{year}",
          layout: "/prime.*",
        },
        "/years/#{year}.erb"
      )
    end
  end

  create_year_pages
end

The @items.create method takes three arguments: the content, the attributes, and the item identifier. The created items live in memory only, and not on the disk. They’ve virtual, in a way, but behave identical to on-disk items otherwise.

In your case, you’d likely in the preprocess block have to loop through all items, check whether there is an existing page that matches items[:wrestler], and if not: use @items.create to create the missing wrestler page in memory. That is how I’d do it, at least!

An alternative would be to write a script (or a custom command) to create the missing items on disk, but I find that to be more cumbersome (and you’d have to remember to run it before every compilation).

Hope this helps,

s...@qiouyi.lu

unread,
Sep 9, 2026, 1:12:11 PMSep 9
to na...@googlegroups.com
Hi Denis,
 
Thanks so much! Related question: Would this preprocess block improve performance? Currently I have a bunch of content pages that have templates that use find all @items on each page, and I’m noticing as I add more pages (I’m into the hundreds now) that compilation time is increasing, especially the longer I have nanoc live running. Would this reduce the number of searches and speed up compilation time?
 
S.
You received this message because you are subscribed to a topic in the Google Groups "nanoc" group.
To unsubscribe from this topic, visit https://groups.google.com/d/topic/nanoc/03EE0i-unaI/unsubscribe.
To unsubscribe from this group and all its topics, send an email to nanoc+un...@googlegroups.com.
To view this discussion visit https://groups.google.com/d/msgid/nanoc/d57d9209-99b1-4886-81d1-ce5930574a60%40app.fastmail.com.
Reply all
Reply to author
Forward
0 new messages