<?xml version="1.0" encoding="utf-8"?><feed xmlns="http://www.w3.org/2005/Atom" xml:lang="en-us"><generator uri="https://gohugo.io/" version="0.101.0">Hugo</generator><title type="html">backlinks on A Scripter's Notes</title><subtitle type="html">Emacs, scripting and anything text oriented.</subtitle><link href="https://scripter.co/tags/backlinks/" rel="alternate" type="text/html" title="HTML"/><link href="https://scripter.co/tags/backlinks/index.xml" rel="alternate" type="application/rss+xml" title="RSS"/><link href="https://scripter.co/tags/backlinks/atom.xml" rel="self" type="application/atom+xml" title="Atom"/><link href="https://scripter.co/tags/backlinks/jf2feed.json" rel="alternate" type="application/jf2feed+json" title="jf2feed"/><updated>2026-04-22T08:24:57-04:00</updated><author><name>Kaushal Modi</name><email>kaushal.modi@gmail.com</email></author><id>https://scripter.co/tags/backlinks/</id><entry><title type="html">Parsing Backlinks in Hugo</title><link href="https://scripter.co/parsing-backlinks-in-hugo/?utm_source=atom_feed" rel="alternate" type="text/html"/><link href="https://scripter.co/improving-ox-hugo-exported-org-info-links/?utm_source=atom_feed" rel="related" type="text/html" title='  Improving ox-hugo exported Org "info:" links   '/><link href="https://scripter.co/linking-and-exporting-org-info-links/?utm_source=atom_feed" rel="related" type="text/html" title='  Linking and Exporting Org "info:" links   '/><link href="https://scripter.co/straight-and-curved-quotes-in-emacs-lisp/?utm_source=atom_feed" rel="related" type="text/html" title="Straight and Curved Quotes in Emacs Lisp"/><link href="https://scripter.co/hugo-use-goat-code-blocks-for-ascii-diagrams/?utm_source=atom_feed" rel="related" type="text/html" title="Hugo: Use goat code blocks for ASCII diagrams"/><link href="https://scripter.co/using-emacs-advice-to-silence-messages-from-functions/?utm_source=atom_feed" rel="related" type="text/html" title="Using Emacs advice to silence messages from functions"/><id>https://scripter.co/parsing-backlinks-in-hugo/</id><author><name>Kaushal Modi</name></author><published>2022-04-20T09:50:00-04:00</published><updated>2022-04-20T09:50:00-04:00</updated><content type="html"><![CDATA[<blockquote>A Hugo partial to parse all the <em>backlinks</em> to any post from the same
Hugo-generated website.</blockquote><div class="ox-hugo-toc toc">
<div class="heading">Table of Contents</div>
<ul>
<li><a href="#code">Code</a>
<ul>
<li><a href="#create-a-backlinks-dot-html-partial"><span class="section-num">1</span> Create a <code>backlinks.html</code> <em>partial</em></a></li>
<li><a href="#use-the-partial"><span class="section-num">2</span> Use the partial</a></li>
</ul>
</li>
<li><a href="#features-and-improvements">Features and Improvements</a></li>
<li><a href="#closing">Closing</a></li>
</ul>
</div>
<!--endtoc-->
<p>If a post is referred to in other posts, then all those posts are
creating <em>backlinks</em> to that first post.</p>
<p>As of writing this (<span class="timestamp-wrapper"><span class="timestamp">&lt;2022-04-19 Tue&gt;</span></span>), Hugo doesn&rsquo;t have a built-in
way to generate a list of such backlinks, though there&rsquo;s an open issue
(<a href="https://github.com/gohugoio/hugo/issues/8077"># 8077</a>) to track this feature request.</p>
<p>One way to gather a list of backlinks to a post is to find out that
post&rsquo;s relative or absolute <em>permalink</em>, and search for the
occurrences of that link in all the other posts on the published
site. The author of <a href="https://seds.nl/notes/export_org_roam_backlinks_with_gohugo/">seds.nl: Export org-roam backlinks with Gohugo</a>,
Ben Mezger, uses this approach in his solution for creating backlinks
in that post.</p>
<p>In this post, I am expanding upon that solution and refactoring it bit
to fit my needs.</p>

<h2 id="code">Code&nbsp;<a class="headline-hash no-text-decoration" href="#code">#</a></h2>


<p>Without further ado, here is my version of the <em>partial</em>:</p>

<h3 id="create-a-backlinks-dot-html-partial"><span class="section-num">1</span> Create a <code>backlinks.html</code> <em>partial</em>&nbsp;<a class="headline-hash no-text-decoration" href="#create-a-backlinks-dot-html-partial">#</a></h3>


<p>Save this partial to your site repo as
<code>layouts/partials/backlinks.html</code>.</p>
<p><a id="code-snippet--backlinks-partial"></a></p>
<div class="highlight"><div class="chroma">
<table class="lntable"><tr><td class="lntd">
<pre tabindex="0" class="chroma"><code><span class="lnt" id="org-coderef--e7ca1c-1"><a style="outline: none; text-decoration:none; color:inherit" href="#org-coderef--e7ca1c-1"> 1</a>
</span><span class="lnt" id="org-coderef--e7ca1c-2"><a style="outline: none; text-decoration:none; color:inherit" href="#org-coderef--e7ca1c-2"> 2</a>
</span><span class="lnt" id="org-coderef--e7ca1c-3"><a style="outline: none; text-decoration:none; color:inherit" href="#org-coderef--e7ca1c-3"> 3</a>
</span><span class="lnt" id="org-coderef--e7ca1c-4"><a style="outline: none; text-decoration:none; color:inherit" href="#org-coderef--e7ca1c-4"> 4</a>
</span><span class="lnt" id="org-coderef--e7ca1c-5"><a style="outline: none; text-decoration:none; color:inherit" href="#org-coderef--e7ca1c-5"> 5</a>
</span><span class="lnt" id="org-coderef--e7ca1c-6"><a style="outline: none; text-decoration:none; color:inherit" href="#org-coderef--e7ca1c-6"> 6</a>
</span><span class="lnt" id="org-coderef--e7ca1c-7"><a style="outline: none; text-decoration:none; color:inherit" href="#org-coderef--e7ca1c-7"> 7</a>
</span><span class="lnt" id="org-coderef--e7ca1c-8"><a style="outline: none; text-decoration:none; color:inherit" href="#org-coderef--e7ca1c-8"> 8</a>
</span><span class="lnt" id="org-coderef--e7ca1c-9"><a style="outline: none; text-decoration:none; color:inherit" href="#org-coderef--e7ca1c-9"> 9</a>
</span><span class="lnt" id="org-coderef--e7ca1c-10"><a style="outline: none; text-decoration:none; color:inherit" href="#org-coderef--e7ca1c-10">10</a>
</span><span class="lnt" id="org-coderef--e7ca1c-11"><a style="outline: none; text-decoration:none; color:inherit" href="#org-coderef--e7ca1c-11">11</a>
</span><span class="lnt" id="org-coderef--e7ca1c-12"><a style="outline: none; text-decoration:none; color:inherit" href="#org-coderef--e7ca1c-12">12</a>
</span><span class="lnt" id="org-coderef--e7ca1c-13"><a style="outline: none; text-decoration:none; color:inherit" href="#org-coderef--e7ca1c-13">13</a>
</span><span class="lnt" id="org-coderef--e7ca1c-14"><a style="outline: none; text-decoration:none; color:inherit" href="#org-coderef--e7ca1c-14">14</a>
</span><span class="lnt" id="org-coderef--e7ca1c-15"><a style="outline: none; text-decoration:none; color:inherit" href="#org-coderef--e7ca1c-15">15</a>
</span><span class="lnt" id="org-coderef--e7ca1c-16"><a style="outline: none; text-decoration:none; color:inherit" href="#org-coderef--e7ca1c-16">16</a>
</span><span class="lnt" id="org-coderef--e7ca1c-17"><a style="outline: none; text-decoration:none; color:inherit" href="#org-coderef--e7ca1c-17">17</a>
</span><span class="lnt" id="org-coderef--e7ca1c-18"><a style="outline: none; text-decoration:none; color:inherit" href="#org-coderef--e7ca1c-18">18</a>
</span><span class="lnt" id="org-coderef--e7ca1c-19"><a style="outline: none; text-decoration:none; color:inherit" href="#org-coderef--e7ca1c-19">19</a>
</span><span class="lnt" id="org-coderef--e7ca1c-20"><a style="outline: none; text-decoration:none; color:inherit" href="#org-coderef--e7ca1c-20">20</a>
</span><span class="lnt" id="org-coderef--e7ca1c-21"><a style="outline: none; text-decoration:none; color:inherit" href="#org-coderef--e7ca1c-21">21</a>
</span><span class="lnt" id="org-coderef--e7ca1c-22"><a style="outline: none; text-decoration:none; color:inherit" href="#org-coderef--e7ca1c-22">22</a>
</span></code></pre></td>
<td class="lntd">
<pre tabindex="0" class="chroma"><code class="language-go-html-template" data-lang="go-html-template"><span class="line"><span class="cl"><span class="cp">{{</span><span class="w"> </span><span class="nx">$backlinks</span><span class="w"> </span><span class="o">:=</span><span class="w"> </span><span class="nx">slice</span><span class="w"> </span><span class="cp">}}</span>
</span></span><span class="line"><span class="cl"><span class="cp">{{</span><span class="w"> </span><span class="nx">$path_base</span><span class="w"> </span><span class="o">:=</span><span class="w"> </span><span class="na">.page.File.ContentBaseName</span><span class="w"> </span><span class="cp">}}</span>
</span></span><span class="line"><span class="cl"><span class="cp">{{</span><span class="w"> </span><span class="nx">$path_base_re</span><span class="w"> </span><span class="o">:=</span><span class="w"> </span><span class="k">printf</span><span class="w"> </span><span class="s">`[&#34;/(]%s[&#34;/)]`</span><span class="w"> </span><span class="nx">$path_base</span><span class="w"> </span><span class="cp">}}</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="cp">{{</span><span class="w"> </span><span class="k">range</span><span class="w"> </span><span class="nx">where</span><span class="w"> </span><span class="nx">site</span><span class="na">.RegularPages</span><span class="w"> </span><span class="s">&#34;RelPermalink&#34;</span><span class="w"> </span><span class="s">&#34;ne&#34;</span><span class="w"> </span><span class="na">.page.RelPermalink</span><span class="w"> </span><span class="cp">}}</span>
</span></span><span class="line"><span class="cl">    <span class="cp">{{</span><span class="w"> </span><span class="k">if</span><span class="w"> </span><span class="o">(</span><span class="nx">findRE</span><span class="w"> </span><span class="nx">$path_base_re</span><span class="w"> </span><span class="na">.RawContent</span><span class="w"> </span><span class="nx">1</span><span class="o">)</span><span class="w"> </span><span class="cp">}}</span>
</span></span><span class="line"><span class="cl">        <span class="cp">{{</span><span class="w"> </span><span class="nx">$backlinks</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="nx">$backlinks</span><span class="w"> </span><span class="o">|</span><span class="w"> </span><span class="nx">append</span><span class="w"> </span><span class="na">.</span><span class="w"> </span><span class="cp">}}</span>
</span></span><span class="line"><span class="cl">    <span class="cp">{{</span><span class="w"> </span><span class="k">end</span><span class="w"> </span><span class="cp">}}</span>
</span></span><span class="line"><span class="cl"><span class="cp">{{</span><span class="w"> </span><span class="k">end</span><span class="w"> </span><span class="cp">}}</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="cp">{{</span><span class="w"> </span><span class="k">with</span><span class="w"> </span><span class="nx">$backlinks</span><span class="w"> </span><span class="cp">}}</span>
</span></span><span class="line"><span class="cl">    <span class="p">&lt;</span><span class="nt">section</span> <span class="na">class</span><span class="o">=</span><span class="s">&#34;backlinks&#34;</span><span class="p">&gt;</span>
</span></span><span class="line"><span class="cl">        <span class="cp">{{</span><span class="w"> </span><span class="k">printf</span><span class="w"> </span><span class="s">&#34;%s&#34;</span><span class="w"> </span><span class="o">(</span><span class="na">$.heading</span><span class="w"> </span><span class="o">|</span><span class="w"> </span><span class="nx">default</span><span class="w"> </span><span class="s">&#34;&lt;h2&gt;Backlinks&lt;/h2&gt;&#34;</span><span class="o">)</span><span class="w"> </span><span class="o">|</span><span class="w"> </span><span class="nx">safeHTML</span><span class="w"> </span><span class="cp">}}</span>
</span></span><span class="line"><span class="cl">        <span class="p">&lt;</span><span class="nt">nav</span><span class="p">&gt;</span>
</span></span><span class="line"><span class="cl">            <span class="p">&lt;</span><span class="nt">ul</span><span class="p">&gt;</span>
</span></span><span class="line"><span class="cl">                <span class="cp">{{</span><span class="w"> </span><span class="k">range</span><span class="w"> </span><span class="na">.</span><span class="w"> </span><span class="cp">}}</span>
</span></span><span class="line"><span class="cl">                    <span class="p">&lt;</span><span class="nt">li</span><span class="p">&gt;&lt;</span><span class="nt">a</span> <span class="na">href</span><span class="o">=</span><span class="s">&#34;</span><span class="cp">{{</span><span class="w"> </span><span class="na">.RelPermalink</span><span class="w"> </span><span class="cp">}}</span><span class="s">&#34;</span><span class="p">&gt;</span><span class="cp">{{</span><span class="w"> </span><span class="na">.Title</span><span class="w"> </span><span class="cp">}}</span><span class="p">&lt;/</span><span class="nt">a</span><span class="p">&gt;&lt;/</span><span class="nt">li</span><span class="p">&gt;</span>
</span></span><span class="line"><span class="cl">                <span class="cp">{{</span><span class="w"> </span><span class="k">end</span><span class="w"> </span><span class="cp">}}</span>
</span></span><span class="line"><span class="cl">            <span class="p">&lt;/</span><span class="nt">ul</span><span class="p">&gt;</span>
</span></span><span class="line"><span class="cl">        <span class="p">&lt;/</span><span class="nt">nav</span><span class="p">&gt;</span>
</span></span><span class="line"><span class="cl">    <span class="p">&lt;/</span><span class="nt">section</span><span class="p">&gt;</span>
</span></span><span class="line"><span class="cl"><span class="cp">{{</span><span class="w"> </span><span class="k">end</span><span class="w"> </span><span class="cp">}}</span>
</span></span></code></pre></td></tr></table>
</div>
</div><div class="src-block-caption">
  <span class="src-block-number"><a href="#code-snippet--backlinks-partial">Code Snippet 1</a>:</span>
  <code>backlinks.html</code> Hugo partial
</div>

<h3 id="use-the-partial"><span class="section-num">2</span> Use the partial&nbsp;<a class="headline-hash no-text-decoration" href="#use-the-partial">#</a></h3>


<p>Add a call to this partial in your &ldquo;single&rdquo; layout&rsquo;s template file,
which is typically <code>layouts/_default/single.html</code>.</p>
<p><a id="code-snippet--call-backlinks-partial"></a></p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-go-html-template" data-lang="go-html-template"><span class="line"><span class="cl"><span class="cp">{{</span><span class="w"> </span><span class="nx">partial</span><span class="w"> </span><span class="s">&#34;backlinks.html&#34;</span><span class="w"> </span><span class="o">(</span><span class="nx">dict</span><span class="w"> </span><span class="s">&#34;page&#34;</span><span class="w"> </span><span class="na">.</span><span class="o">)</span><span class="w"> </span><span class="cp">}}</span>
</span></span></code></pre></div><div class="src-block-caption">
  <span class="src-block-number"><a href="#code-snippet--call-backlinks-partial">Code Snippet 2</a>:</span>
  Calling the <code>backlinks.html</code> partial
</div>

<h2 id="features-and-improvements">Features and Improvements&nbsp;<a class="headline-hash no-text-decoration" href="#features-and-improvements">#</a></h2>


<ol>
<li>✨ The partial now accepts a <code>dict</code> or a dictionary with
keys <code>page</code> and <code>heading</code>.
<ul>
<li>The <code>page</code> key is required to pass the page context from where
the partial is called.</li>
<li>The <code>heading</code> key is optional. This can be used by the user to
set the &ldquo;Backlinks&rdquo; heading differently. For example,
<code class="code-inline language-go-html-template"><span class="cp">{{</span><span class="w"> </span><span class="nx">partial</span><span class="w"> </span><span class="s">&#34;backlinks.html&#34;</span><span class="w"> </span><span class="o">(</span><span class="nx">dict</span><span class="w"> </span><span class="s">&#34;page&#34;</span><span class="w"> </span><span class="na">.</span><span class="w"> </span><span class="s">&#34;heading&#34;</span><span class="w"> </span><span class="s">&#34;&lt;h4&gt;Links to this note&lt;/h4&gt;&#34;</span><span class="o">)</span><span class="w"> </span><span class="cp">}}</span></code>.</li>
</ul>
</li>
<li>🐛 <a href="#org-coderef--e7ca1c-2">Line 2</a>: <code>.File.BaseFileName</code> would be
just &ldquo;index&rdquo; for all the <a href="/hugo-leaf-and-branch-bundles/"><em>Leaf Bundles</em></a>
<span class="sidenote-number"><small class="sidenote">
If you follow this link and scroll to the bottom of that page, you
will see a &ldquo;Backlinks&rdquo; section auto-generated with the help of this
partial. This post will be linked there because I just referenced
that post here.
</small></span>
, and I use them <strong>heavily</strong>! Using <code>.File.ContentBaseName</code> fixes
this problem. See <a href="https://gohugo.io/variables/files/">📖 Hugo File Variables</a> for more
info. [Credit: <a href="https://github.com/benmezger/blog/issues/8#issuecomment-894750079"><em>@sjgknight</em></a>]</li>
<li>🐛 <a href="#org-coderef--e7ca1c-3">Line 3</a>: Reduce false matches for
backlinks by making the regular expression a bit stricter. Now it
will match only if the derived <code>$path_base</code> variable is found
wrapped in characters like <strong><code>&quot;</code></strong>, <strong><code>/</code></strong>, <strong><code>(</code></strong> or <strong><code>)</code></strong>.
<ul>
<li>If <code>$path_base</code> is &lsquo;hello&rsquo;, I don&rsquo;t want its mere reference like
in this line to create a backlink on that &lsquo;hello&rsquo; post!</li>
<li>Instead, a match will happen only if something like <strong><code>&quot;hello&quot;</code></strong>
(as in <code class="code-inline language-go-html-template"><span class="cp">{{</span><span class="err">&lt;</span><span class="w"> </span><span class="nx">relref</span><span class="w"> </span><span class="s">&#34;hello&#34;</span><span class="w"> </span><span class="err">&gt;</span><span class="cp">}}</span></code>), or <strong><code>/hello&quot;</code></strong> (as in <code class="code-inline language-go-html-template"><span class="cp">{{</span><span class="err">&lt;</span><span class="w"> </span><span class="nx">relref</span><span class="w"> </span><span class="s">&#34;/posts/hello&#34;</span><span class="w"> </span><span class="err">&gt;</span><span class="cp">}}</span></code>), or <strong><code>/hello)</code></strong> (as in
<code class="code-inline language-md">[<span class="nt">Hello</span>](<span class="na">/hello</span>)</code>) is found in the raw
Markdown content (<code>.RawContent</code>).</li>
</ul>
</li>
<li>⚡ <a href="#org-coderef--e7ca1c-5">Line 5</a>: Look for backlinks only in
<code>site.RegularPages</code>. See <a href="https://gohugo.io/variables/site/#sitepages-compared-to-pages">📖 About site Pages variables</a> for
more info. <code>site.AllPages</code> includes <strong>all</strong> pages.. even the list
pages like section and taxonomy pages which, I believe, won&rsquo;t
contain backlinks.</li>
<li>⚡ The <code>findRE</code> in <a href="#org-coderef--e7ca1c-6">line 6</a> is slightly optimized
by quitting the search immediately as soon as the first match is
found.</li>
<li>💄 Rest of the changes are just using a different style of
coding using Hugo templates and creating a different structure in
HTML.</li>
</ol>

<h2 id="closing">Closing&nbsp;<a class="headline-hash no-text-decoration" href="#closing">#</a></h2>


<p>This partial works great for this site &mdash; adds only a few hundred
<em>milliseconds</em> to the build time.</p>
<p>But it&rsquo;s not an efficient solution. The partial is called in the
<em>single</em> template where it searching for backlinks to the current page
in <strong>all</strong> other regular pages, and the <em>single</em> template is evaluated
for <strong>all</strong> the regular pages. So its <a href="https://en.wikipedia.org/wiki/Big_O_notation">\(O\) notation</a> will be close to
\(O(n^2)\) where \(n\) is the number of regular pages.</p>
<p>I have only about a hundred regular pages at the moment, but I can see
this partial taking a major chunk of the build time
<span class="sidenote-number"><small class="sidenote">
The <code>hugo --templateMetrics --templateMetricsHints</code> command prints a
table listing all the partials used in the build and how much time
each of them took. See <a href="https://gohugo.io/troubleshooting/build-performance/">📖 Hugo Build Performance</a> for more
info.
</small></span>
as the number of pages increase.</p>
<p>A built-in support for backlinks from Hugo (<a href="https://github.com/gohugoio/hugo/issues/8077"># 8077</a>) would really help
in this performance department.</p>
]]></content><category scheme="https://scripter.co/categories/hugo" term="hugo" label="hugo"/><category scheme="https://scripter.co/tags/partials" term="partials" label="partials"/><category scheme="https://scripter.co/tags/backlinks" term="backlinks" label="backlinks"/><category scheme="https://scripter.co/tags/100daystooffload" term="100daystooffload" label="100DaysToOffload"/></entry></feed>