Cara Integrasi Netlify CMS dengan Hugo untuk Headless CMS
Cara Integrasi Netlify CMS dengan Hugo untuk Headless CMS
Netlify CMS (sekarang Decap CMS) adalah open-source headless CMS yang menggunakan Git sebagai backend. Integrasi dengan Hugo memberikan workflow content management yang modern dan efisien.
Apa itu Netlify CMS?
Fitur Utama
- Git-based: Semua content tersimpan di Git repository
- Editorial Workflow: Draft, review, publish workflow
- Media Library: Upload dan manage images
- Real-time Preview: Preview content sebelum publish
- Open Source: Gratis dan self-hostable
Arsitektur
Browser (Netlify CMS Admin)
↓
Git Gateway (Authentication)
↓
Git Repository (GitHub/GitLab/Bitbucket)
↓
Hugo Build → Static Site
↓
CDN (Netlify/Cloudflare/Vercel)
Setup Netlify CMS dengan Hugo
Step 1: Struktur Project
my-hugo-site/
├── content/
├── static/
│ └── admin/ # Netlify CMS admin files
│ ├── index.html # Admin interface
│ └── config.yml # CMS configuration
├── layouts/
└── hugo.toml
Step 2: Buat Admin Interface
File static/admin/index.html:
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Content Manager</title>
<script src="https://identity.netlify.com/v1/netlify-identity-widget.js"></script>
</head>
<body>
<script src="https://unpkg.com/decap-cms@^3.0.0/dist/decap-cms.js"></script>
<script>
if (window.netlifyIdentity) {
window.netlifyIdentity.on("init", user => {
if (!user) {
window.netlifyIdentity.on("login", () => {
document.location.href = "/admin/";
});
}
});
}
</script>
</body>
</html>
Step 3: Konfigurasi CMS (config.yml)
File static/admin/config.yml:
backend:
name: git-gateway
branch: main
repo: username/repository-name
# Media folder
media_folder: "static/images/uploads"
public_folder: "/images/uploads"
# Collections
collections:
# Blog Posts
- name: "posts"
label: "Blog Posts"
folder: "content/posts"
create: true
slug: "{{year}}-{{month}}-{{day}}-{{slug}}"
fields:
- { label: "Title", name: "title", widget: "string" }
- { label: "Publish Date", name: "date", widget: "datetime" }
- { label: "Draft", name: "draft", widget: "boolean", default: false }
- { label: "Description", name: "description", widget: "text" }
- { label: "Featured Image", name: "image", widget: "image", required: false }
- { label: "Categories", name: "categories", widget: "list", required: false }
- { label: "Tags", name: "tags", widget: "list", required: false }
- { label: "Body", name: "body", widget: "markdown" }
# Pages
- name: "pages"
label: "Pages"
folder: "content"
create: true
slug: "{{slug}}"
fields:
- { label: "Title", name: "title", widget: "string" }
- { label: "Publish Date", name: "date", widget: "datetime" }
- { label: "Draft", name: "draft", widget: "boolean", default: false }
- { label: "Body", name: "body", widget: "markdown" }
# Editorial Workflow
publish_mode: editorial_workflow
# Display URLs
show_preview_links: true
Step 4: Setup Git Gateway
Di Netlify Dashboard:
- Buka Site Settings → Identity
- Enable Identity → Click “Enable Identity”
- Services → Git Gateway → Click “Enable Git Gateway”
- Registration → Set ke “Open” (untuk testing) atau “Invite only”
Step 5: Identity Widget Setup
Tambahkan widget ke homepage (layouts/partials/head.html):
<script src="https://identity.netlify.com/v1/netlify-identity-widget.js"></script>
<script>
if (window.netlifyIdentity) {
window.netlifyIdentity.on("init", user => {
if (!user) {
window.netlifyIdentity.on("login", () => {
document.location.href = "/admin/";
});
}
});
}
</script>
Advanced CMS Configuration
Widget Types
collections:
- name: "posts"
fields:
# Basic widgets
- { label: "Title", name: "title", widget: "string" }
- { label: "Body", name: "body", widget: "markdown" }
- { label: "Publish Date", name: "date", widget: "datetime" }
- { label: "Image", name: "image", widget: "image" }
- { label: "File", name: "file", widget: "file" }
- { label: "Draft", name: "draft", widget: "boolean" }
# Advanced widgets
- { label: "Rating", name: "rating", widget: "number", value_type: "int", min: 1, max: 5 }
- { label: "Layout", name: "layout", widget: "select", options: ["default", "full-width", "sidebar"] }
- { label: "Color", name: "color", widget: "color" }
- { label: "Content", name: "content", widget: "text" }
- { label: "Code", name: "code", widget: "code" }
# Lists
- { label: "Categories", name: "categories", widget: "list" }
- { label: "Tags", name: "tags", widget: "list", allow_add: true }
# Object
- label: "Author"
name: "author"
widget: "object"
fields:
- { label: "Name", name: "name", widget: "string" }
- { label: "Email", name: "email", widget: "string" }
- { label: "Bio", name: "bio", widget: "text" }
Folder Collections
collections:
# Single folder untuk posts
- name: "posts"
label: "Blog Posts"
folder: "content/posts"
create: true
# Nested folders (misal: docs dengan struktur folder)
- name: "docs"
label: "Documentation"
folder: "content/docs"
create: true
nested:
depth: 3 # Maksimum depth
summary: '{{title}}'
fields:
- { label: "Title", name: "title", widget: "string" }
- { label: "Body", name: "body", widget: "markdown" }
File Collections
collections:
# Untuk single files seperti settings
- name: "settings"
label: "Site Settings"
files:
- label: "General Settings"
name: "general"
file: "config/_default/params.yaml"
fields:
- { label: "Site Title", name: "title", widget: "string" }
- { label: "Description", name: "description", widget: "text" }
- { label: "Author", name: "author", widget: "string" }
- label: "Social Links"
name: "social"
file: "config/_default/social.yaml"
fields:
- label: "Social Links"
name: "links"
widget: "list"
fields:
- { label: "Platform", name: "platform", widget: "string" }
- { label: "URL", name: "url", widget: "string" }
Editorial Workflow
Draft → Review → Publish
# config.yml
publish_mode: editorial_workflow
Workflow:
- Draft: Author membuat content baru
- In Review: Editor review content
- Ready: Approved dan siap publish
Hugo akan build:
- Draft: Hanya preview URL
- Published: Live di production site
Preview Links
show_preview_links: true
Setiap draft akan mendapat preview URL unique untuk review.
Custom Previews
Register Preview Template
<!-- static/admin/index.html -->
<script>
CMS.registerPreviewStyle("/admin/preview.css");
CMS.registerPreviewTemplate("posts", createClass({
render: function() {
const entry = this.props.entry;
return h('div', {},
h('h1', {}, entry.getIn(['data', 'title'])),
h('img', {src: entry.getIn(['data', 'image'])}),
h('div', {"className": "content"}, this.props.widgetFor('body'))
);
}
}));
</script>
Preview Styles
File static/admin/preview.css:
/* Preview styles untuk match Hugo theme */
body {
font-family: -apple-system, system-ui, sans-serif;
max-width: 800px;
margin: 0 auto;
padding: 20px;
}
img {
max-width: 100%;
height: auto;
}
Media Library
Cloudinary Integration
# config.yml
media_library:
name: cloudinary
config:
cloud_name: your-cloud-name
api_key: your-api-key
default_transformations:
- fetch_format: auto
quality: auto
width: 800
crop: scale
Uploadcare Integration
media_library:
name: uploadcare
config:
publicKey: your-public-key
Custom Media Library
media_library:
name: custom
config:
media_folder: "static/images"
public_folder: "/images"
Authentication Options
1. Netlify Identity (Default)
backend:
name: git-gateway
2. GitHub Backend
backend:
name: github
repo: owner/repo
branch: main
base_url: https://api.netlify.com
auth_endpoint: auth
3. GitLab Backend
backend:
name: gitlab
repo: owner/repo
branch: main
auth_type: pkce
Deployment Integration
Netlify
- Connect repository ke Netlify
- Enable Identity dan Git Gateway
- CMS otomatis ter-deploy dengan Hugo site
GitHub Pages + Actions
# .github/workflows/cms.yml
name: Deploy Hugo with CMS
on:
push:
branches: [main]
jobs:
deploy:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v3
- uses: peaceiris/actions-hugo@v2
- run: hugo --minify
- uses: peaceiris/actions-gh-pages@v3
with:
github_token: ${{ secrets.GITHUB_TOKEN }}
publish_dir: ./public
Customization
Custom Widgets
// Custom color widget
CMS.registerWidget(
'color', // Widget name
ColorControl, // React component
ColorPreview // Preview component
);
Custom Icons
# config.yml
collections:
- name: "posts"
label: "Posts"
icon: "news" # Material icon name
Custom Slug Format
slug:
encoding: "unicode"
clean_accents: false
sanitize_replacement: "-"
Troubleshooting
Issue: “Git Gateway Error”
Solusi:
- Check Identity ter-enable
- Git Gateway sudah diaktifkan
- Repository permissions benar
Issue: “Failed to Persist”
Solusi:
backend:
name: git-gateway
squash_merges: true # Untuk menghindari conflict
Issue: “CORS Error”
Solusi:
Tambahkan di Netlify _headers:
/admin/*
Access-Control-Allow-Origin: *
Issue: “Images Not Showing”
Solusi:
Check media_folder dan public_folder paths:
media_folder: "static/images/uploads" # Local path
public_folder: "/images/uploads" # URL path
Best Practices
1. Content Structure
collections:
- name: "posts"
label: "Posts"
folder: "content/posts"
path: "{{slug}}/index" # Page bundle structure
media_folder: ""
public_folder: ""
fields:
- { label: "Title", name: "title", widget: "string" }
- { label: "Body", name: "body", widget: "markdown" }
2. Validation
fields:
- {
label: "Title",
name: "title",
widget: "string",
pattern: ['.{10,100}', "Must have 10-100 characters"]
}
- {
label: "Email",
name: "email",
widget: "string",
pattern: ['^\S+@\S+\.\S+$', "Must be a valid email"]
}
3. Default Values
fields:
- {
label: "Draft",
name: "draft",
widget: "boolean",
default: true # Default ke draft
}
- {
label: "Date",
name: "date",
widget: "datetime",
default: ""
}
Kesimpulan
Netlify CMS dengan Hugo memberikan:
✅ Git-based: Version control untuk content
✅ Editorial Workflow: Draft, review, publish
✅ User-friendly: Non-technical authors bisa contribute
✅ Real-time Preview: Preview sebelum publish
✅ Media Management: Upload dan organize images
✅ Customizable: Widgets dan fields bisa dikustomisasi
Ideal untuk:
- Teams dengan content writers non-technical
- Editorial workflow dengan approval process
- Client sites yang perlu CMS sederhana
Artikel Terkait
Link Postingan: https://www.tirinfo.com/cara-integrasi-netlify-cms-hugo/