titleref: Referencing Hugo posts by their titles
— Kaushal ModiA custom Hugo shortcode to create cross-references to other posts using their title strings.
relref
shortcode #
Hugo has a built-in shortcode relref
that gets relative links
There’s also a ref
shortcode which creates absolute links. ref
can
be used wherever relref
is used.
to other posts by using their url
. In Hugo lingo, a post’s url
consists of the post’s section
and slug
This post’s section
is posts
and slug
is
titleref-referencing-hugo-posts-by-their-titles
. So the url
is
posts/titleref-referencing-hugo-posts-by-their-titles
.
.
This page’s relative link can be fetched by using {{< relref "posts/titleref-referencing-hugo-posts-by-their-titles" >}}
. If a
post’s slug is unique across all the posts, its section
part can be
skipped. So the same relref
can be written as {{< relref "titleref-referencing-hugo-posts-by-their-titles" >}}
and that will
still return
this
same link.
- Problem Statement
- The issue with
relref
is that it returns only the link — the description still needs to be written manually. I typically use a post’s title as description when I link to it. So the full link with description will look like this when writing in Org mode In Markdown, the same link will look like this:[titleref: Referencing Hugo posts by their titles]({{< relref "titleref-referencing-hugo-posts-by-their-titles" >}})
. for exporting using ox-hugo:[[@@hugo:{{< relref "titleref-referencing-hugo-posts-by-their-titles" >}}@@][titleref: Referencing Hugo posts by their titles]]
.
You can see how impractical and verbose that is!
If you write your posts in Markdown, you can jump to the titleref
shortcode section.
relref
Org macro #
An Org macro can help a little over here.
#+macro: relref @@hugo:[@@ $1 @@hugo:]({{< relref "$2" >}})@@
With this macro, that same relref
link can
be rewritten as {{{relref(titleref: Referencing Hugo posts by their titles,titleref-referencing-hugo-posts-by-their-titles)}}}
.
It’s a bit less verbose compared to using the shortcode directly, but I still wasn’t happy with the redundancy.
titleref
shortcode #
In that relref link, we are providing both, the post slug and the post title. Both are uniquely associated with each-other , and Hugo can internally derive one from the other. So there’s no need for us to specify both!
And so I thought that it should be pretty simple to specify just the
title of post that I want to link, and let Hugo derive the post’s
permalink — and it was simple, by using this custom
A user can add custom shortcodes or override the default Hugo
shortcodes by putting them in the layouts/shortcodes/
directory of
the site or theme repo.
shortcode!
An astute Org mode user might think that this idea looks like the
[[*Heading]]
syntax supported by Org, and they
would be right! This titleref
idea is inspired by that Org mode
feature.
|
|
This shortcode is designed to take up to two arguments:
- title (+anchor)
- The first argument can be just the title of the post that we want to link (e.g. “My post”). Optionally, it can also be followed by an anchor in that post, separated by “#” (e.g. “My post#some-heading”).
- (description)
- The second argument is optional, and it’s the link description. If this argument is not set, the description is set to the post’s title.
How this shortcode works
- In lines 2 and 3, the title and anchor portions are parsed from the first argument.
- In line 4, if the description is specified using a
second argument, it’s converted to HTML using
markdownify
. - ✨ Line 5 is the main logic – It returned a list of all the pages whose Title matches the title parsed from the first argument. This list should have only 1 element as the assumption is that all blog posts have unique titles.
- The first (and only) page element of that list is saved on
$first_match
in line 6. - If the Title based search was successfully in that main logic,
$first_match
won’t be nil. In line 12, the link description is set to the.Title
from that page object, if a description wasn’t already set using the second argument. Finally an HTML link is printed by using.RelPermalink
(relative permalink) from the page object and the description. - If the Title based search fails in the main logic, an error is printed on line 15.
Examples of using the titleref
shortcode (for Markdown users)
{{< titleref "TITLE" >}}
– Link to a page with that TITLE and set the link description to be the same as the TITLE.{{< titleref "TITLE" "DESC" >}}
– Link to a page with that TITLE, with DESC as description.{{< titleref "TITLE#ANCHOR" "DESC" >}}
– Link to an ANCHOR in a page with that TITLE, with DESC as description.
titleref
Org macro #
But the fun doesn’t end here for an Org mode user! 😃
I do not prefer using Hugo shortcodes directly in my Org source. So I created an Org macro to wrap this shortcode.
#+macro: titleref @@hugo:{{< titleref "$1" "@@ $2 @@hugo:" >}}@@
Now {{{titleref(titleref: Referencing Hugo posts by their titles,)}}}
will export to titleref: Referencing Hugo posts by their titles.
Here are some example uses of this macro:
{{{titleref(TITLE,)}}}
– Link to a page with that TITLE and set the link description to be the same as the TITLE.{{{titleref(TITLE,DESC)}}}
– Link to a page with that TITLE, with DESC as description.{{{titleref(TITLE#ANCHOR,DESC)}}}
– Link to an ANCHOR in a page with that TITLE, with DESC as description.
Summary #
By using the titleref
shortcode (or Org macro) instead of relref
,
we now have a tremendous reduction of redundancy.
- Before
- Org mode:
{{{relref(titleref: Referencing Hugo posts by their titles,titleref-referencing-hugo-posts-by-their-titles)}}}
- Markdown:
[titleref: Referencing Hugo posts by their titles]({{< relref "titleref-referencing-hugo-posts-by-their-titles" >}})
- Org mode:
- Now
- Org mode:
{{{titleref(titleref: Referencing Hugo posts by their titles,)}}}
- Markdown:
{{< titleref "titleref: Referencing Hugo posts by their titles" >}}
- Org mode: