Organize Your Hugo Content: Generating Subfolder Pages with a Prebuild Script

Hugo, a popular static site generator, offers a flexible way to structure your content. While it's common to place Markdown files directly within the content directory, organizing content into subfolders can lead to a cleaner and more manageable website structure. This article will guide you through a method to automatically generate .md files within distinct subfolders (like articles and projects) using a Hugo prebuild script.

The Challenge: Centralized Content Management

When fetching content from external sources (like a CMS via an API), you might want to categorize different content types into separate sections on your website. Manually creating these folders and placing the generated Markdown files can become tedious.

The Solution: A Unified Prebuild Script

The provided prebuild.html template leverages Hugo's templating capabilities and the resources.GetRemote function to fetch data from two different API endpoints and organize them into respective subfolders.

Here's a breakdown of the script ( where Bearer Token and api url are saved in the config.toml file):

HTML
    {{ $bearer := (printf "Bearer %s" site.Params.api_token) }}
    {{ $opts := dict
      "headers" (dict "Authorization" $bearer)
    }}
{{ $articlesUrl := (printf "%s/items/articles?sort=-id&random=4" site.Params.api_url) }}
{{ with resources.GetRemote $articlesUrl $opts | transform.Unmarshal }}
    {{ range index .data }}
        {{ $meta := dict "slug" .slug "title" .title "tags" .tags }} 
        {{ $metaJson := jsonify $meta }}
        {{ $content := .long_description | safeHTML }}
        {{ $output := printf "%s\n%s" $metaJson $content }}
        {{ $filename := printf "content/articles/%s.md" .slug }}
        {{ $resource := resources.FromString $filename $output }} 
        {{ $file := $resource.RelPermalink }} 
    {{ end }}
{{ end }}


{{ $projectsUrl := (printf "%s/items/projects?sort=sort&random=2" site.Params.api_url) }}
{{ with resources.GetRemote $projectsUrl $opts | transform.Unmarshal }}
    {{ range index .data }}
        {{ $meta := dict "slug" .slug "title" .title "tags" .tags }} 
        {{ $metaJson := jsonify $meta }}
        {{ $content := .long_description | safeHTML }}
        {{ $output := printf "%s\n%s" $metaJson $content }}
        {{ $filename := printf "content/projects/%s.md" .slug }}
        {{ $resource := resources.FromString $filename $output }} 
        {{ $file := $resource.RelPermalink }} 
    {{ end }}
{{ end }}

Key aspects of this solution:

  1. Directory Structure: Instead of placing all files directly in the content folder, the script defines specific output paths:

    • content/articles/[slug].md for articles
    • content/projects/[slug].md for projects
  2. Combined Script: A single index.html template handles fetching and generating content for both "articles" and "projects" based on their respective API endpoints.

 

Implementation Steps

To integrate this into your Hugo site:

  1. Inside the main folder of your project create the prebuild/layouts directory: If it doesn't already exist in your Hugo project.
  2. Place prebuild.html: Save the provided code asprebuild/layouts/index.html.
  3. Run hugo --minify  in prebuild folder
  4. Map the  prebuild public folder inside your config.toml
      [module.mounts]
        source = "prebuild/public/content"
        target = "content"
  5. Run hugo --minify  in main project folder

Now, when you build your Hugo site, this prebuild script will fetch your articles and projects and automatically place their corresponding .md files in the content/articles and content/projects folders, respectively.

 

Benefits of this Approach

  • Organized Content: Clear separation of content types within your content directory.
  • Simplified Management: A single script handles the generation for multiple content types.
  • Clean URLs: Hugo will automatically create clean URLs based on the subfolder structure (e.g., /articles/your-article-slug/ and /projects/your-project-slug/).

This method provides an efficient way to manage and structure your Hugo content when sourcing data from external APIs. You can easily extend this approach to handle more content types by adding additional fetch and generation blocks to the prebuild/layouts/index.html file.


Hugo Prebuild SEO