Files
foldsite/docs/content/templates/template-discovery.md
Tanishq Dubey ad81d7f3db
All checks were successful
Datadog Software Composition Analysis / Datadog SBOM Generation and Upload (push) Successful in 52s
Datadog Secrets Scanning / Datadog Static Analyzer (push) Successful in 1m1s
Datadog Static Analysis / Datadog Static Analyzer (push) Successful in 5m50s
docs refactor
2025-10-09 18:21:23 -04:00

12 KiB

version, date, author, title, description, summary, quick_tips
version date author title description summary quick_tips
1.0 2025-01-15 DWS Foldsite Team Template Discovery System Understanding how Foldsite finds and chooses templates Deep dive into Foldsite's hierarchical template discovery algorithm - learn exactly how templates are matched to content.
Templates are searched from most specific to most general
First match wins - more specific templates override general ones
Templates cascade down through directory hierarchies

Template Discovery System

Understanding how Foldsite discovers and chooses templates is key to building sophisticated sites. This guide explains the complete template resolution algorithm.

The Discovery Algorithm

When Foldsite renders a page, it follows a hierarchical search pattern to find the best template.

Core Principle

Specificity wins. More specific templates override general ones.

Think of it like CSS specificity:

#specific-id      (most specific)
.class-name
element           (least specific)

In Foldsite:

my-post.html           (most specific - exact file)
__file.md.html         (category + extension)
__file.document.html   (category only)
__file.html            (least specific - any file)

File Type Detection

Before template discovery, Foldsite determines the content type:

For Files

Step 1: Extract extension

blog/my-post.md  →  extension: "md"

Step 2: Map to categories

"md"  →  categories: ["document", "md"]

Category mapping:

GENERIC_FILE_MAPPING = {
    "document": ["md", "txt", "html"],
    "image": ["png", "jpg", "jpeg", "gif", "svg"],
    "multimedia": ["mp4", "mp3", "webm"],
    "other": [...]  # Everything else
}

For Folders

Step 1: Count file types in folder

photos/vacation/
  IMG_001.jpg  →  jpg: 1
  IMG_002.jpg  →  jpg: 2
  IMG_003.jpg  →  jpg: 3
  notes.txt    →  txt: 1

Step 2: Most common type wins

Most common: jpg (3 files)
→ categories: ["image", "jpg"]

Template Search Order

For Files: blog/my-post.md

Given:

  • Path: blog/my-post.md
  • Type: file
  • Categories: ["document", "md"]
  • Extension: md

Search order:

  1. Exact file match in current directory

    templates/blog/my-post.html
    
  2. Type + extension in current directory

    templates/blog/__file.md.html
    
  3. Type + category in current directory (most specific category first)

    templates/blog/__file.document.html
    
  4. Generic type in current directory

    templates/blog/__file.html
    
  5. Move up one directory, repeat steps 2-4

    templates/__file.md.html
    templates/__file.document.html
    templates/__file.html
    
  6. Default template (if exists)

    templates/default.html
    

First match wins!

For Folders: photos/vacation/

Given:

  • Path: photos/vacation/
  • Type: folder
  • Categories: ["image"] (most files are images)

Search order:

  1. Exact folder match

    templates/photos/vacation/__folder.html
    
  2. Type + category in current directory

    templates/photos/__folder.image.html
    
  3. Generic folder in current directory

    templates/photos/__folder.html
    
  4. Move up one directory, repeat steps 2-3

    templates/__folder.image.html
    templates/__folder.html
    
  5. Default template

    templates/default.html
    

Practical Examples

Example 1: Blog Post

Content: content/blog/posts/2024-my-post.md

Template search:

1. templates/blog/posts/2024-my-post.html        ✗ Not found
2. templates/blog/posts/__file.md.html           ✗ Not found
3. templates/blog/posts/__file.document.html     ✗ Not found
4. templates/blog/posts/__file.html              ✗ Not found
5. templates/blog/__file.md.html                 ✓ FOUND!

Result: Uses templates/blog/__file.md.html

Why: Most specific template found in the hierarchy.

Example 2: Homepage

Content: content/index.md

Template search:

1. templates/index.html                          ✓ FOUND!

Result: Uses templates/index.html

Why: Exact file match (most specific possible).

Content: content/photos/vacation/ (folder with 50 JPG files)

Categories: ["image"]

Template search:

1. templates/photos/vacation/__folder.html       ✗ Not found
2. templates/photos/__folder.image.html          ✓ FOUND!

Result: Uses templates/photos/__folder.image.html

Why: Type + category match in parent directory.

Example 4: Deep Nesting

Content: content/docs/guides/advanced/testing.md

Template search:

1. templates/docs/guides/advanced/testing.html   ✗ Not found
2. templates/docs/guides/advanced/__file.md.html ✗ Not found
3. templates/docs/guides/__file.md.html          ✗ Not found
4. templates/docs/__file.md.html                 ✓ FOUND!

Result: Uses templates/docs/__file.md.html

Why: Climbs directory tree until finding a match.

Template Cascade

Templates cascade down through directories:

templates/
├── __file.md.html              ← Default for ALL markdown
└── blog/
    └── __file.md.html          ← Override for blog/ only

Rendering content/about.md:

  • Uses templates/__file.md.html

Rendering content/blog/post.md:

  • Uses templates/blog/__file.md.html (more specific)

Multi-Level Cascade

templates/
├── __file.md.html              ← Level 1: Site default
├── blog/
│   └── __file.md.html          ← Level 2: Blog default
└── blog/
    └── tutorials/
        └── __file.md.html      ← Level 3: Tutorial-specific

Effect:

  • content/about.md → Level 1 template
  • content/blog/news.md → Level 2 template
  • content/blog/tutorials/python.md → Level 3 template

Category Priority

Files can belong to multiple categories. More specific categories come first.

Category Hierarchy

For my-post.md:

Categories: ["md", "document"]
              ↑         ↑
         specific   general

Search order:

1. __file.md.html        ← Most specific
2. __file.document.html  ← More general
3. __file.html           ← Most general

Debug Mode

Enable debug mode to see template discovery in action:

# config.toml
[server]
debug = true

Console output when visiting a page:

[DEBUG] Template discovery for: blog/my-post.md
[DEBUG] Content type: file
[DEBUG] Categories: ['md', 'document']
[DEBUG] Extension: md
[DEBUG]
[DEBUG] Searching templates:
[DEBUG]   1. templates/blog/my-post.html          - NOT FOUND
[DEBUG]   2. templates/blog/__file.md.html        - FOUND!
[DEBUG]
[DEBUG] Using template: templates/blog/__file.md.html

Debug Test Page

Create a test page to understand discovery:

---
title: "Template Discovery Test"
---

# Current Template Info

**Current Path:** {{ currentPath }}

**Styles Loaded:**
{% for style in styles %}
- {{ style }}
{% endfor %}

**Metadata:**
{{ metadata }}

Visit this page and check the console to see which template was used.

Edge Cases

No Template Found

If no template matches:

For files:

  • Foldsite serves the file directly (download)
  • Useful for PDFs, images, etc.

For folders:

  • Returns 404 error
  • Need at least one __folder.html template

Hidden Files

Files/folders starting with ___ are ignored:

content/
├── post.md              ✓ Will be rendered
└── ___draft.md          ✗ Ignored completely

No template search is performed for hidden content.

Multiple Extensions

Only the last extension is considered:

my-file.tar.gz  →  extension: "gz"

Not: tar.gz or tar

Style Discovery

Styles follow similar logic to templates but accumulate instead of first-match:

Style Search for blog/post.md

All matching styles are loaded (in order):

1. /base.css                           ← Always loaded
2. /blog/__file.md.css                 ← If exists
3. /blog/__file.document.css           ← If exists
4. /__file.md.css                      ← If exists (from root)
5. /blog/post.md.css                   ← If exists (specific file)

All found styles are included (not just first match).

Rendering:

<link rel="stylesheet" href="/styles/base.css">
<link rel="stylesheet" href="/styles/blog/__file.md.css">
<link rel="stylesheet" href="/styles/__file.md.css">

Optimization Tips

1. Keep Templates at Appropriate Levels

Good:

templates/
├── __file.md.html       ← General template
└── blog/
    └── __file.md.html   ← Blog-specific customization

Avoid:

templates/
├── post1.html
├── post2.html
├── post3.html           ← Repetitive!
└── ...

2. Use Categories Effectively

Good:

templates/
├── __file.md.html           ← For markdown
├── __folder.image.html      ← For galleries
└── __file.document.html     ← For all documents

Avoid:

templates/
├── __file.html              ← Too generic
└── (nothing else)

3. Understand the Cascade

Place templates where they make sense:

Project structure:

content/
├── blog/       → Frequent posts, custom layout
├── docs/       → Technical docs, different layout
└── about.md    → One-off pages

Template structure:

templates/
├── __file.md.html         ← Default for one-off pages
├── blog/
│   └── __file.md.html     ← Blog-specific
└── docs/
    └── __file.md.html     ← Docs-specific

Common Patterns

Pattern: Section-Specific Layouts

Different sections need different layouts:

templates/
├── base.html                      ← Shared wrapper
├── __file.md.html                 ← Default content
├── blog/
│   ├── __file.md.html             ← Blog posts
│   └── __folder.md.html           ← Blog index
├── portfolio/
│   ├── __file.md.html             ← Project pages
│   └── __folder.md.html           ← Portfolio grid
└── docs/
    ├── __file.md.html             ← Documentation pages
    └── __folder.md.html           ← Docs index

Pattern: Gradual Specialization

Start general, add specificity as needed:

Phase 1: MVP

templates/
├── base.html
└── __file.md.html

Phase 2: Add Gallery

templates/
├── base.html
├── __file.md.html
└── __folder.image.html       ← New!

Phase 3: Custom Blog

templates/
├── base.html
├── __file.md.html
├── __folder.image.html
└── blog/
    └── __file.md.html       ← New!

Pattern: Override Single Page

Override one specific page:

templates/
├── __file.md.html           ← All markdown
└── index.html               ← Special homepage

Troubleshooting

Template Not Being Used

Check:

  1. File name - Is it exactly right?
  2. Location - Is it in the right directory?
  3. Extension - .html, not .htm or .jinja
  4. Debug mode - What does the console say?

Debug:

# Enable debug
[server]
debug = true

# Restart and check console output

Wrong Template Used

Likely cause: More specific template exists

Example:

Want: templates/__file.md.html
Using: templates/blog/__file.md.html  ← More specific!

Solution: Update the more specific template, or remove it.

Styles Not Loading

Check:

  1. Style file exists in styles/ directory
  2. Path matches template expectations
  3. Browser dev tools - Are styles being requested?

Remember: Unlike templates, all matching styles load.

Next Steps

Understanding template discovery gives you complete control over your site's presentation. Use it wisely!