Hugo RSS dan Sitemap: Otomasi Feed dan SEO
Hugo RSS dan Sitemap: Otomasi Feed dan SEO
RSS feeds dan sitemaps adalah komponen essential untuk website modern. RSS memungkinkan pengunjung untuk subscribe ke konten Anda, sementara sitemaps membantu search engines menemukan dan mengindex konten Anda. Hugo menyediakan built-in support untuk keduanya, namun customization yang tepat sangat penting untuk SEO dan user experience yang optimal.
RSS (Really Simple Syndication) adalah format untuk mendistribusikan konten secara otomatis kepada subscribers. Sitemap adalah file yang memberikan informasi kepada search engines tentang struktur website dan halaman-halaman yang perlu di-index.
RSS Feed Configuration
Enable RSS di Hugo
# hugo.toml
[outputs]
home = ["HTML", "RSS"]
page = ["HTML", "RSS"]
section = ["HTML", "RSS"]
taxonomy = ["HTML", "RSS"]
[services]
[services.rss]
limit = 100 # Maximum items dalam RSS feed
Custom RSS Template
{{/* layouts/_default/rss.xml */}}
{{- printf "<?xml version=\"1.0\" encoding=\"UTF-8\"?>" | safeHTML -}}
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:content="http://purl.org/rss/1.0/modules/content/">
<channel>
<title>{{ .Site.Title }}</title>
<link>{{ .Site.BaseURL }}</link>
<description>{{ with .Description }}{{ . }}{{ else }}{{ .Site.Title }}{{ end }}</description>
{{- if .Site.LanguageCode }}
<language>{{ .Site.LanguageCode }}</language>
{{- end }}
{{- if .Site.Author.name }}
<managingEditor>{{ .Site.Author.name }}{{ with .Site.Author.email }} ({{ . }}){{ end }}</managingEditor>
<webMaster>{{ .Site.Author.name }}{{ with .Site.Author.email }} ({{ . }}){{ end }}</webMaster>
{{- end }}
{{- if not .Date.IsZero }}
<pubDate>{{ .Date.Format "Mon, 02 Jan 2006 15:04:05 -0700" | safeHTML }}</pubDate>
{{- end }}
{{- if .Lastmod }}
<lastBuildDate>{{ .Lastmod.Format "Mon, 02 Jan 2006 15:04:05 -0700" | safeHTML }}</lastBuildDate>
{{- end }}
<atom:link href="{{ .Permalink }}" rel="self" type="application/rss+xml" />
{{- range first 20 .Site.RegularPages }}
<item>
<title>{{ .Title }}</title>
<link>{{ .Permalink }}</link>
<guid isPermaLink="true">{{ .Permalink }}</guid>
{{- if .Description }}
<description>{{ .Description | html }}</description>
{{- else }}
<description>{{ .Summary | html }}</description>
{{- end }}
{{- if .Params.categories }}
<categories>{{ delimit .Params.categories "," }}</categories>
{{- end }}
{{- if .Site.Params.author }}
<author>{{ .Site.Params.author }}</author>
{{- end }}
<pubDate>{{ .Date.Format "Mon, 02 Jan 2006 15:04:05 -0700" | safeHTML }}</pubDate>
{{- if .Content }}
<content:encoded><![CDATA[{{ .Content }}]]></content:encoded>
{{- end }}
</item>
{{- end }}
</channel>
</rss>
Section-Specific RSS
{{/* layouts/_default/section.rss.xml */}}
{{- printf "<?xml version=\"1.0\" encoding=\"UTF-8\"?>" | safeHTML -}}
<rss version="2.0">
<channel>
<title>{{ .Title }} - {{ .Site.Title }}</title>
<link>{{ .Permalink }}</link>
<description>RSS feed for {{ .Title }}</description>
<atom:link href="{{ .Permalink }}" rel="self" type="application/rss+json" />
{{- range first 20 .Pages }}
<item>
<title>{{ .Title }}</title>
<link>{{ .Permalink }}</link>
<guid>{{ .Permalink }}</guid>
<description>{{ .Description | default .Summary }}</description>
<pubDate>{{ .Date.Format "Mon, 02 Jan 2006 15:04:05 -0700" }}</pubDate>
</item>
{{- end }}
</channel>
</rss>
JSON Feed
{{/* layouts/_default/feed.json */}}
{{- $title := .Site.Title -}}
{{- $description := with .Description }}{{ . }}{{ else }}{{ .Site.Title }}{{ end -}}
{{- $feedUrl := .Permalink -}}
{{- $.Scratch.Add "items" slice -}}
{{- range first 20 .Site.RegularPages -}}
{{- $.Scratch.Add "items" (dict
"id" .Permalink
"url" .Permalink
"title" .Title
"content_html" .Content
"summary" .Description
"date_published" (.Date.Format "2006-01-02T15:04:05-07:00")
"date_modified" (.Lastmod.Format "2006-01-02T15:04:05-07:00")
"author" (dict "name" .Site.Params.author)
) -}}
{{- end -}}
{{- $feed := dict
"version" "https://jsonfeed.org/version/1"
"title" $title
"home_page_url" .Site.BaseURL
"feed_url" $feedUrl
"description" $description
"items" ($.Scratch.Get "items")
-}}
{{- printf "%s" (jsonify $feed) -}}
Sitemap Generation
Default Sitemap
Hugo automatically generates sitemap.xml dengan konfigurasi di hugo.toml:
[services]
[services.sitemap]
changefreq = "weekly"
priority = 0.5
filename = "sitemap.xml"
Custom Sitemap Template
{{/* layouts/_default/sitemap.xml */}}
{{- printf "<?xml version=\"1.0\" encoding=\"UTF-8\"?>" | safeHTML -}}
<urlset xmlns="http://www.sitemaps.org/schemas/sitemap/0.9"
xmlns:xhtml="http://www.w3.org/1999/xhtml"
xmlns:mobile="http://www.google.com/schemas/sitemap-mobile/1.0"
xmlns:image="http://www.google.com/schemas/sitemap-image/1.1"
xmlns:news="http://www.google.com/schemas/sitemap-news/0.9">
{{- range .Site.RegularPages }}
<url>
<loc>{{ .Permalink }}</loc>
{{- if .Lastmod }}
<lastmod>{{ .Lastmod.Format "2006-01-02" }}</lastmod>
{{- end }}
{{- with .Params.changeFreq }}
<changefreq>{{ . }}</changefreq>
{{- else }}
<changefreq>weekly</changefreq>
{{- end }}
{{- with .Params.priority }}
<priority>{{ . }}</priority>
{{- else }}
<priority>{{ cond .IsHome 1.0 0.5 }}</priority>
{{- end }}
{{- /* Multilingual support */}}
{{- if .IsTranslated }}
{{- range .Translations }}
<xhtml:link
rel="alternate"
hreflang="{{ .Language.Lang }}"
href="{{ .Permalink }}" />
{{- end }}
{{- end }}
{{- /* Images in sitemap */}}
{{- with .Params.featuredImage }}
<image:image>
<image:loc>{{ . }}</image:loc>
<image:title>{{ $.Title }}</image:title>
</image:image>
{{- end }}
</url>
{{- end }}
</urlset>
Sitemap Index
Untuk website besar, sitemap index diperlukan:
{{/* layouts/_default/sitemap-index.xml */}}
{{- printf "<?xml version=\"1.0\" encoding=\"UTF-8\"?>" | safeHTML -}}
<sitemapindex xmlns="http://www.sitemaps.org/schemas/sitemap/0.9">
{{- range (where .Site.RegularPages "Section" "posts") }}
{{- $pageNum := 1 }}
{{- end }}
{{- range $i := seq 0 (div (sub (len .Site.RegularPages) 1) 500) }}
{{- $pageNum := add $i 1 }}
<sitemap>
<loc>{{ $.Site.BaseURL }}sitemap-{{ $pageNum }}.xml</loc>
<lastmod>{{ now.Format "2006-01-02" }}</lastmod>
</sitemap>
{{- end }}
</sitemapindex>
Video Sitemap
{{/* layouts/_default/video-sitemap.xml */}}
{{- printf "<?xml version=\"1.0\" encoding=\"UTF-8\"?>" | safeHTML -}}
<urlset xmlns="http://www.sitemaps.org/schemas/sitemap/0.9"
xmlns:video="http://www.google.com/schemas/sitemap-video/1.1">
{{- range where .Site.RegularPages "Section" "videos" }}
<url>
<loc>{{ .Permalink }}</loc>
<video:video>
<video:thumbnail_loc>{{ .Params.thumbnail }}</video:thumbnail_loc>
<video:title>{{ .Title }}</video:title>
<video:description>{{ .Description }}</video:description>
<video:player_loc>{{ .Params.videoUrl }}</video:player_loc>
<video:duration>{{ .Params.duration }}</video:duration>
<video:publication_date>{{ .Date.Format "2006-01-02T15:04:05+00:00" }}</video:publication_date>
<video:tag>{{ delimit .Params.tags "," }}</video:tag>
<video:category>{{ .Params.category }}</video:category>
</video:video>
</url>
{{- end }}
</urlset>
News Sitemap
{{/* layouts/_default/news-sitemap.xml */}}
{{- printf "<?xml version=\"1.0\" encoding=\"UTF-8\"?>" | safeHTML -}}
<urlset xmlns="http://www.sitemaps.org/schemas/sitemap/0.9"
xmlns:news="http://www.google.com/schemas/sitemap-news/0.9">
{{- range first 1000 (where .Site.RegularPages "Section" "posts") }}
{{- if ge .Date.AddDate 0 0 -2 }}
<url>
<loc>{{ .Permalink }}</loc>
<news:news>
<news:publication>
<news:name>{{ .Site.Title }}</news:name>
<news:language>{{ .Site.LanguageCode }}</news:language>
</news:publication>
<news:publication_date>{{ .Date.Format "2006-01-02T15:04:05+00:00" }}</news:publication_date>
<news:title>{{ .Title }}</news:title>
</news:news>
</url>
{{- end }}
{{- end }}
</urlset>
robots.txt Configuration
# netlify.toml atau vercel.json
[[headers]]
for = "/robots.txt"
[headers.values]
Content-Type = "text/plain"
[[headers]]
for = "/sitemap.xml"
[headers.values]
Content-Type = "application/xml"
# layouts/robots.txt
User-agent: *
Allow: /
Sitemap: {{ .Site.BaseURL }}sitemap.xml
Sitemap: {{ .Site.BaseURL }}sitemap-news.xml
User-agent: Googlebot
Allow: /
User-agent: Bingbot
Allow: /
SEO Considerations
Canonical URLs
{{/* layouts/_default/baseof.html */}}
<link rel="canonical" href="{{ .Permalink }}">
Hreflang untuk Multilingual
{{- if .IsTranslated -}}
{{- range .Translations -}}
<link rel="alternate"
hreflang="{{ .Language.Lang }}"
href="{{ .Permalink }}" />
{{- end -}}
{{- end -}}
Meta Tags
{{/* layouts/partials/seo-meta.html */}}
<meta name="description" content="{{ with .Description }}{{ . }}{{ else }}{{ .Summary }}{{ end }}">
<meta property="og:title" content="{{ .Title }}">
<meta property="og:description" content="{{ with .Description }}{{ . }}{{ else }}{{ .Summary }}{{ end }}">
<meta property="og:type" content="{{ if .IsHome }}website{{ else }}article{{ end }}">
<meta property="og:url" content="{{ .Permalink }}">
<meta property="og:image" content="{{ with .Params.image }}{{ . }}{{ else }}{{ .Site.Params.ogImage }}{{ end }}">
<meta name="twitter:card" content="summary_large_image">
Submit ke Search Engines
Google Search Console
Submit sitemap melalui Google Search Console:
- Login ke Search Console
- Select property
- Navigate ke Sitemaps
- Submit sitemap URL
Bing Webmaster Tools
# Submit via API atau manual di bing.com/webmasters
Auto-submit dengan Webhooks
# .github/workflows/seo-submit.yml
name: Submit Sitemap
on:
push:
branches: [main]
jobs:
submit:
runs-on: ubuntu-latest
steps:
- name: Submit to Google
run: |
curl -s -X POST -d "sitemap=0" \
"https://www.google.com/ping?sitemap={{ .Site.BaseURL }}sitemap.xml"
Monitoring dan Validation
Validate Sitemap
# Check sitemap syntax
xmllint --noout public/sitemap.xml && echo "Valid XML"
# Online validation
# https://validator.w3.org/feed/
# https://www.xml-sitemaps.com/validate-xml-sitemap.html
RSS Validation
# Check RSS syntax
xmllint --noout public/index.xml && echo "Valid RSS"
# Online validation
# https://validator.w3.org/feed/
Best Practices
| Practice | Description |
|---|---|
| Limit RSS items | 20-50 items untuk performance |
| Include full content | Untuk RSS readers yang support |
| Valid XML | Ensure well-formed XML |
| Include images | Untuk rich snippets |
| Update frequency | Set appropriate changefreq |
| Multilingual | Include hreflang tags |
| Mobile sitemap | Jika applicable |
Kesimpulan
RSS feeds dan sitemaps adalah komponen essential untuk SEO dan content distribution. Dengan konfigurasi yang tepat di Hugo, Anda dapat generate feeds dan sitemaps yang optimized untuk search engines dan readers.
Artikel Terkait
Link Postingan: https://www.tirinfo.com/hugo-rss-sitemap/