Custom content type, multiple entries grouped by day, no individual permalink?

G’day! I’ve got a custom content type called activities (singular: activity). Content files are stored in content/activities/. I’d like to display these activities by day, without any individual permalinks. If there are five activities that have the same day (set in front matter date), I’d like to automatically generate a single list page (at, say, /activities/YYYY/MM/DD/index.html) that displays all five activities for that day. I would NOT like to generate ANY individual pages: I do not want five pages, one page per activity, to be generated. I anticipate tens of thousands of individual content/activities files, but I only ever want to (automatically) generate a number of HTML lists that equate to the number of days those activities spanned across.

Is this something Hugo can do?

One option appears to be a leaf bundle, as seen here:

but this would have me manually creating a duplicate _index.md for each and every day, and that’s not something I’d relish (as activities go back nearly 30 years). There’s a mention of Data sources there too, and I think I might be willing to do some sort of activity-by-day “data” $Date shortcode, but I don’t know how I’d rig it up to generate per-day lists at /activities/YYYY/MM/DD/.

Do you need to create a content file for each activity, or can you define the activities in a data file? If you can do the latter, use a content adapter to create your list pages.

MMm. Ok. I’ve never worked with content adapters before.

I would place the data in assets/data/activities with a data structure such as…

YAML

- 2026:
  - 03:
    - 30:
      - name: Lunch on the Wharf
        location: San Francisco, CA
        type: Meal
        time_begin: 2026-03-30T14:00:00-07:00
        time_end: 2026-03-30T16:00:00-07:00
        description: |
          We'll be having lunch on the wharf.

          It will be awesome.
      - name: Golden Gate Park Tour
        location: San Francisco, CA
        type: Tour
        time_begin: 2026-03-30T14:00:00-07:00
        time_end: 2026-03-30T16:00:00-07:00
        description: |
          This is a tour of Golden Gate Park.

It’s a lot easier to group the data up front.

Unfortunately, the data is coming from dozens of sources, so I’d prefer to have data/activities/SOURCE.json… otherwise, each data retrieval script would have to parse and generate a ginormous file, full of stuff that “is not theirs”. Not entirely out of the realm of reason, but not exactly what I was hoping for. I’m still trying trying to figure out the content adapter part of it :smiley:

If it were my project, I’d create an external pre-processor to validate, standardize, and combine the various source files into one file, JSON if you’d prefer.

assets/data/activities.json

[
  {
    "2026": [
      {
        "3": [
          {
            "30": [
              {
                "name": "Lunch on the Wharf",
                "location": "San Francisco, CA",
                "type": "Meal",
                "time_begin": "2026-03-30T21:00:00.000Z",
                "time_end": "2026-03-30T23:00:00.000Z",
                "description": "We'll be having lunch on the wharf.\n\nIt will be awesome.\n"
              },
              {
                "name": "Golden Gate Park Tour",
                "location": "San Francisco, CA",
                "type": "Tour",
                "time_begin": "2026-03-30T21:00:00.000Z",
                "time_end": "2026-03-30T23:00:00.000Z",
                "description": "This is a tour of Golden Gate Park.\n"
              }
            ]
          }
        ]
      }
    ]
  }
]

I’m pretty sure I can figure out the data aspects of it - could you help me with the content adapter? So far I’ve gotten as far as /content/activities/_content.gotmpl and

{{ with resources.Get 'letterboxd.json' }}

{{ end }}

:smiley:

Create a map from the resource using the transform.Unmarshal function, then start looping through the data.

I don’t really know what I’m doing here. Given data/activities.json:

{
  "days": [
    {
      "title": "2026-03-31",
      "date": "2026-03-31T10:00:00",
      "summary": "Something something 2222\nSomething something 3333\n",
      "items": [
        {
          "id": 2222
        },
        {
          "id": 3333
        }
      ]
    },
    {
      "title": "2026-03-30",
      "date": "2026-03-30T10:00:00",
      "summary": "Something something 4444\nSomething something 5555\n",
      "items": [
        {
          "id": 4444
        },
        {
          "id": 5555
        }
      ]
    }
  ]
}

And content/activities/_content.gotmpl (cobbled together from the “Example” on Content adapters , along with layout/activity/page.html), I can run hugo server --buildDrafts --disableFastRender and it doesn’t complain about any errors… but it also doesn’t seem to generate any pages at the path I’ve specified:

{{ range hugo.Data.activities.days }}
  {{ $content := dict "mediaType" "text/markdown" "value" .summary }}
  {{ $dates := dict "date" (time.AsTime .date) }}
  {{ $t := dict "date" (time.AsTime .date) }}
  {{ $page := dict
    "content" $content
    "dates" $dates
    "kind" "page"
    "path" "activities/$t.Year/$t.Month/$t.Day/"
    "title" .title
  }}
  {{ $.AddPage $page }}
{{ end }}

If this is the “best approach” for doing it in Hugo, and my scripts have to collectively generate a massive JSON (YAML, etc.) to power it… it’s really not that much extra work to, outside of Hugo, a) load that JSON myself and b) just generate daily /content/activities/YYYYMMDD.md files myself, without having to worry about Hugo content adapters. I’ll explore that approach instead.

Thank you for the help and consideration, @jmooring!