Salin dan Bagikan
Data-Driven Content di Hugo: JSON, YAML, dan CSV Integration - Panduan lengkap data-driven content di Hugo. Pelajari cara menggunakan JSON, YAML, dan CSV untuk …

Data-Driven Content di Hugo: JSON, YAML, dan CSV Integration

Data-Driven Content di Hugo: JSON, YAML, dan CSV Integration

Hugo’s data files adalah fitur powerful yang memungkinkan Anda menyimpan data secara eksternal dan mengaksesnya di templates. Ini sangat useful untuk membuat konten yang driven oleh data seperti price lists, team members, FAQ sections, dan berbagai data yang perlu terpisah dari konten utama. Panduan ini akan membahas cara menggunakan data files di Hugo secara efektif.

Data files di Hugo adalah files yang disimpan di folder data/ dan dapat diakses melalui .Site.Data di templates. Hugo mendukung berbagai formats termasuk JSON, YAML, TOML, dan CSV. Dengan data files, Anda dapat maintain data secara terpisah dari content, memungkinkan updates yang lebih mudah tanpa harus modify content files.

Struktur Data Files

Lokasi dan Organisasi

Data files disimpan di folder data/ di root proyek Hugo:

data/
├── authors.yaml
├── team.yaml
├── products.json
├── prices.csv
├── locations/
│   ├── jakarta.yaml
│   ├── surabaya.yaml
│   └── bandung.yaml
└── navigation.yaml

Format yang Didukung

Hugo mendukung empat format data files: JSON untuk data terstruktur modern, YAML untuk human-readable configuration, TOML untuk configuration files, dan CSV untuk tabular data.

Menggunakan JSON Data

Struktur JSON Data

// data/products.json
{
  "products": [
    {
      "id": 1,
      "name": "Laptop Pro",
      "price": 15000000,
      "currency": "IDR",
      "category": "electronics",
      "inStock": true,
      "features": ["16GB RAM", "512GB SSD", "Intel i7"],
      "specifications": {
        "processor": "Intel Core i7-1165G7",
        "memory": "16GB DDR4",
        "storage": "512GB NVMe SSD",
        "display": "14 inch FHD"
      }
    },
    {
      "id": 2,
      "name": "Wireless Mouse",
      "price": 350000,
      "currency": "IDR",
      "category": "accessories",
      "inStock": true,
      "features": ["Ergonomic", "Long battery life"]
    }
  ]
}

Mengakses JSON di Templates

{{/* layouts/_default/single.html */}}
{{ range .Site.Data.products.products }}
    <div class="product">
        <h3>{{ .name }}</h3>
        <p class="price">{{ .price | lang.NumFmt 0 }} {{ .currency }}</p>
        <ul class="features">
            {{ range .features }}
                <li>{{ . }}</li>
            {{ end }}
        </ul>
    </div>
{{ end }}

Nested JSON

// data/company.json
{
  "name": "Tech Solutions",
  "established": 2020,
  "locations": {
    "headquarters": {
      "city": "Jakarta",
      "address": "Jl. Sudirman No. 1"
    },
    "branches": ["Surabaya", "Bandung", "Medan"]
  },
  "stats": {
    "employees": 150,
    "revenue": 50000000000
  }
}
{{ with .Site.Data.company }}
    <h2>{{ .name }}</h2>
    <p>Headquarters: {{ .locations.headquarters.city }}</p>
    <p>Revenue: {{ .stats.revenue | lang.NumFmt 0 }}</p>
{{ end }}

Menggunakan YAML Data

Struktur YAML Data

# data/authors.yaml
- id: 1
  name: "John Doe"
  email: "john@example.com"
  bio: "Full-stack developer dengan 10 tahun pengalaman."
  avatar: "/images/authors/john.jpg"
  social:
    twitter: "johndoe"
    github: "johndoe"
    linkedin: "johndoe"
  role: "Senior Developer"

- id: 2
  name: "Jane Smith"
  email: "jane@example.com"
  bio: "UI/UX Designer passionate about accessibility."
  avatar: "/images/authors/jane.jpg"
  social:
    twitter: "janesmith"
    dribbble: "janesmith"
  role: "Lead Designer"

Mengakses YAML di Templates

{{ range .Site.Data.authors }}
    <div class="author-card">
        <img src="{{ .avatar }}" alt="{{ .name }}">
        <h3>{{ .name }}</h3>
        <p>{{ .bio }}</p>
        {{ with .social }}
            <div class="social-links">
                {{ with .twitter }}
                    <a href="https://twitter.com/{{ . }}">Twitter</a>
                {{ end }}
                {{ with .github }}
                    <a href="https://github.com/{{ . }}">GitHub</a>
                {{ end }}
            </div>
        {{ end }}
    </div>
{{ end }}

Multi-Language Data

# data/navigation.id.yaml
- title: "Beranda"
  url: "/"
- title: "Produk"
  url: "/products/"
  children:
    - title: "Elektronik"
      url: "/products/electronics/"
    - title: "Aksesori"
      url: "/products/accessories/"

# data/navigation.en.yaml
- title: "Home"
  url: "/"
- title: "Products"
  url: "/products/"
{{ $navData := index .Site.Data (printf "navigation.%s" .Site.Language.Lang) }}
{{ range $navData }}
    <a href="{{ .url }}">{{ .title }}</a>
{{ end }}

Menggunakan CSV Data

Struktur CSV Data

# data/prices.csv
product,category,price,currency,discount
Laptop Pro,electronics,15000000,IDR,10
Wireless Mouse,accessories,350000,IDR,5
USB-C Hub,accessories,750000,IDR,0
Monitor 27inch,electronics,4500000,IDR,15
Keyboard Mechanical,accessories,1200000,IDR,10

Mengakses CSV di Templates

{{ range .Site.Data.prices }}
    <tr>
        <td>{{ .product }}</td>
        <td>{{ .category }}</td>
        {{- $price := div .price 1000 }}
        <td>{{ lang.NumFmt 0 $price }} {{ .currency }}</td>
        {{- if gt .discount 0 -}}
        <td>{{ .discount }}%</td>
        {{- else -}}
        <td>-</td>
        {{- end -}}
    </tr>
{{ end }}

CSV dengan Header

Hugo automatically treats first row sebagai header. Akses dengan .header:

{{ with .Site.Data.prices }}
    <thead>
        <tr>
            {{ range .headers }}
                <th>{{ . }}</th>
            {{ end }}
        </tr>
    </thead>
    <tbody>
        {{ range .data }}
            <tr>
                {{ range $i, $v := . }}
                    <td>{{ $v }}</td>
                {{ end }}
            </tr>
        {{ end }}
    </tbody>
{{ end }}

Menggunakan TOML Data

Struktur TOML Data

# data/config.toml
[site]
name = "Tech Blog"
description = "Blog tentang teknologi dan programming"
logo = "/images/logo.png"

[social]
twitter = "techblog"
github = "techblog"
linkedin = "techblog"

[[authors]]
name = "John Doe"
role = "Editor"

[[authors]]
name = "Jane Smith"
role = "Contributor"

[features]
comments = true
search = true
dark_mode = true

Mengakses TOML di Templates

{{ with .Site.Data.config }}
    <h1>{{ .site.name }}</h1>
    <p>{{ .site.description }}</p>
    
    {{ with .features }}
        <p>Features: {{ if .dark_mode }}Dark Mode{{ end }}</p>
    {{ end }}
{{ end }}

Data-driven Components

FAQ Section

# data/faq.yaml
- question: "Apa itu Hugo?"
  answer: "Hugo adalah static site generator yang ditulis dalam Go."
  category: "General"

- question: "Bagaimana cara install Hugo?"
  answer: "Hugo dapat diinstall melalui package manager atau download binary."
  category: "Installation"

- question: "Apakah Hugo gratis?"
  answer: "Ya, Hugo adalah software open-source di bawah lisensi Apache 2.0."
  category: "General"
{{/* layouts/shortcodes/faq.html */}}
{{- $category := .Get "category" -}}
<div class="faq-section">
    {{- range where $.Site.Data.faq "category" $category -}}
    <details class="faq-item">
        <summary>{{ .question }}</summary>
        <div class="answer">{{ .answer | markdownify }}</div>
    </details>
    {{- end -}}
</div>

Team Members Grid

# data/team.yaml
- name: "John Doe"
  role: "CEO"
  bio: "Visionary leader dengan 15 tahun pengalaman di tech industry."
  image: "/images/team/john.jpg"
  email: "john@example.com"

- name: "Jane Smith"
  role: "CTO"
  bio: "Tech enthusiast dan open source contributor."
  image: "/images/team/jane.jpg"
  email: "jane@example.com"
{{/* layouts/partials/team-grid.html */}}
<div class="team-grid">
    {{ range .Site.Data.team }}
    <div class="team-card">
        <img src="{{ .image }}" alt="{{ .name }}">
        <h3>{{ .name }}</h3>
        <p class="role">{{ .role }}</p>
        <p class="bio">{{ .bio }}</p>
        <a href="mailto:{{ .email }}">{{ .email }}</a>
    </div>
    {{ end }}
</div>

Product Catalog

// data/products.json
{
  "categories": [
    {
      "name": "Electronics",
      "slug": "electronics",
      "products": [
        {"name": "Laptop", "price": 15000000},
        {"name": "Monitor", "price": 4500000}
      ]
    }
  ]
}
{{/* layouts/partials/product-catalog.html */}}
{{ range .Site.Data.products.categories }}
    <section class="category">
        <h2>{{ .name }}</h2>
        <div class="products-grid">
            {{ range .products }}
            <div class="product-card">
                <h3>{{ .name }}</h3>
                <p class="price">{{ .price | lang.NumFmt 0 }} IDR</p>
            </div>
            {{ end }}
        </div>
    </section>
{{ end }}

Data Transformations

Filtering Data

{{/* Filter products by category */}}
{{ range where .Site.Data.products.products "category" "electronics" }}
    <div>{{ .name }} - {{ .price }}</div>
{{ end }}

{{/* Filter dengan multiple conditions */}}
{{ range where .Site.Data.products.products "inStock" true }}
    <div>{{ .name }} (In Stock)</div>
{{ end }}

Sorting Data

{{/* Sort by price ascending */}}
{{ range sort .Site.Data.products.products "price" "asc" }}
    <div>{{ .name }} - {{ .price }}</div>
{{ end }}

{{/* Sort by name descending */}}
{{ range sort .Site.Data.products.products "name" "desc" }}
    <div>{{ .name }}</div>
{{ end }}

Grouping Data

{{/* Group products by category */}}
{{ range group .Site.Data.products.products "category" }}
    <h2>{{ .Key }}</h2>
    {{ range .Pages }}
        <div>{{ .name }}</div>
    {{ end }}
{{ end }}

Data Math Operations

{{/* Calculate total */}}
{{ $total := 0 }}
{{ range .Site.Data.products.products }}
    {{ $total = add $total .price }}
{{ end }}
<p>Total Value: {{ $total | lang.NumFmt 0 }}</p>

Dynamic Content dari External APIs

Fetch External Data

Buat script untuk fetch data dari external API:

// scripts/fetch-data.js
const fs = require('fs');
const fetch = require('node-fetch');

async function fetchProducts() {
    const response = await fetch('https://api.example.com/products');
    const products = await response.json();
    
    fs.writeFileSync('data/products.json', JSON.stringify(products, null, 2));
    console.log('Products data updated');
}

fetchProducts().catch(console.error);

Integrate dengan CI/CD

// package.json
{
  "scripts": {
    "prebuild": "node scripts/fetch-data.js",
    "fetch:data": "node scripts/fetch-data.js"
  }
}

Best Practices

Data Organization

Gunakan struktur folder untuk organize data-related files:

data/
├── products/
│   ├── electronics.yaml
│   ├── accessories.yaml
│   └── services.yaml
├── team/
│   ├── core.yaml
│   └── advisors.yaml
├── locations/
│   ├── indonesia.yaml
│   └── singapore.yaml
└── content.yaml

Validation

Validasi data files dengan schema:

# data/validation-schema.yaml
type: object
properties:
  products:
    type: array
    items:
      type: object
      required:
        - name
        - price
      properties:
        name:
          type: string
        price:
          type: number

Documentation

Dokumentasikan data structures:

# data/README.md
# Team Data Structure

## Format
Array of author objects dengan fields:

- `name` (string): Full name
- `role` (string): Job title
- `bio` (string): Short biography
- `avatar` (string): Path ke image
- `social` (object): Social media links

## Example
```yaml
- name: "John Doe"
  role: "CEO"
  bio: "Tech leader"
  avatar: "/images/team/john.jpg"
  social:
    twitter: "johndoe"

## Kesimpulan

Data files di Hugo menyediakan powerful mechanism untuk membuat content yang driven oleh data. Dengan memahami cara menggunakan JSON, YAML, CSV, dan TOML, Anda dapat create dynamic dan maintainable content structures yang separate dari main content.

## Artikel Terkait

- [Hugo dengan Headless CMS: Strapi, Contentful, dan Sanity](/hugo-headless-cms/)
- [Hugo Taxonomy dan Menu: Struktur Navigasi dan Kategorisasi Konten](/hugo-taxonomy-menu/)
- [Tutorial Hugo Templating: Memahami Layouts, Templates, dan Partial](/tutorial-hugo-templating-layouts-templates-partial/)
- [Hugo Custom Output Formats: JSON, AMP, dan Custom Output](/hugo-custom-output-formats/)

Link Postingan : https://www.tirinfo.com/data-driven-content-hugo/

Hendra WIjaya
Tirinfo
6 minutes.
4 February 2026