Salin dan Bagikan
Hugo RSS dan Sitemap: Otomasi Feed dan SEO - Panduan lengkap RSS feeds dan sitemap generation di Hugo. Pelajari cara membuat custom RSS, …

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:

  1. Login ke Search Console
  2. Select property
  3. Navigate ke Sitemaps
  4. 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

PracticeDescription
Limit RSS items20-50 items untuk performance
Include full contentUntuk RSS readers yang support
Valid XMLEnsure well-formed XML
Include imagesUntuk rich snippets
Update frequencySet appropriate changefreq
MultilingualInclude hreflang tags
Mobile sitemapJika 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/

Hendra WIjaya
Tirinfo
5 minutes.
4 February 2026