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: trueNested 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_workflowWorkflow:
- 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 sitePreview Links
show_preview_links: trueSetiap 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: scaleUploadcare Integration
media_library: name: uploadcare config: publicKey: your-public-keyCustom Media Library
media_library: name: custom config: media_folder: "static/images" public_folder: "/images"Authentication Options
1. Netlify Identity (Default)
backend: name: git-gateway2. GitHub Backend
backend: name: github repo: owner/repo branch: main base_url: https://api.netlify.com auth_endpoint: auth3. GitLab Backend
backend: name: gitlab repo: owner/repo branch: main auth_type: pkceDeployment 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: ./publicCustomization
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 nameCustom Slug Format
slug: encoding: "unicode" clean_accents: false sanitize_replacement: "-"Troubleshooting
Issue: “Git Gateway Error”
Solusi:
1. Check Identity ter-enable
2. Git Gateway sudah diaktifkan
3. Repository permissions benarIssue: “Failed to Persist”
Solusi:
backend: name: git-gateway squash_merges: true # Untuk menghindari conflictIssue: “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 pathBest 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 dikustomisasiIdeal untuk:
– Teams dengan content writers non-technical
– Editorial workflow dengan approval process
– Client sites yang perlu CMS sederhana
Ditulis oleh
Hendra Wijaya