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/