Open regisphilibert opened 3 years ago
So, while I do agree that we need something like this, I don't think we want to add yet another thing that we need to teach people.
Starting from a page, we already have some built-in one-to-many relations:
.Pages
, .RegularPages
.Resources
If you were to treat the above as named relationships (or named joins, naming is hard ...) then the above would be the same as:
.PagesByRelation "_pages"
, .PagesByRelation "_regular_pages"
.ResourcesByRelation "_resources"
Note that the naming above is just a first suggestion ...
So, if we can figure a way to express new relationships, and possibly also extend existing relationships (add to the default .Resources
collection), so you would do:
{{ $seeAlso := .PagesByRelation "see_also" }}
We could probably also overload the existing .Pages
method:
{{ $seeAlso := .Pages "see_also" }}
That way, both of the below would be the same:
{{ $pages1 := .Pages "_pages" }}
{{ $pages2 := .Pages }}
{{ $seeAlso := .Pages "see_also" }}
I prefer the addition of an extra argument to the existing .Pages
method.
So, if we can figure a way to express new relationships
From a CMS standpoint it has to be a reference of either a Front Matter value or the file. Most common usage is to use an array of paths (which also allows control of the sorting of the passed pages). Hence me wanting something people can associate with .GetPage
as its path argument is well known among Hugo users.
I don't think we want to add yet another thing that we need to teach people.
It actually very easy to teach. They will intuitively understand that a method named .GetPages
is expecting paths like its singular counterpart .GetPage
. It's used exaclty as the .GetPage
with the exception of taking a slice instead of a string. Also we wouldn't need to figure a new way to express relationships. We'll use the solution already in place on many Hugo Projects, but deliver a better way of retrieving those pages.
{{ $seeAlso := .Pages "see_also" }}
I prefer the addition of an extra argument to the existing
.Pages
method.
But then you would need to teach user what that second argument is used for. I guess it matches the key which stores the paths... but it's not clear to me.
Documentation-wise, adding .GetPages
with an example to the page/site methods after .GetPage
and its example requires no teaching at all. One take a single string parameter, the other one an array of strings.
For me .Pages
, .RegularPages
is retrieving the children pages of the object (.Page
or .Site
), I don't really think it should be changed in any way which would look limited to "establishing relationships".
Yes what I'm proposing could consequentially become a great solution for handling one to many relationships. But the main goal of this ticket is to add a built-in solution to retrieve multiple pages in a given order, relationships or otherwise.
As this is currently cumbersome and resourceful as illustrated below
{{ $related := slice }}
{{ with .Params.related_posts }}
{{ range . }}
{{ with site.GetPage }}
{{ $related = $related | append . }}
{{ end}}
{{ end }}
{{ end }}
{{ return $related }}
VS:
{{ $related := slice }}
{{ with .Params.related_posts }}
{{ with site.GetPages . }}
{{ $related = . }}
{{ end }}
{{ end }}
{{ return $related }}
@regisphilibert
With this front matter:
+++
title = 'Foo'
date = 2022-08-31T14:32:30-07:00
draft = false
related_pages = ['post-3', 'post-1', 'post-5']
+++
You can do this:
{{ range apply .Params.related_pages "site.GetPage" "." }}
<a href="{{ .RelPermalink }}">{{ .LinkTitle }}</a>
{{ end }}
To produce this:
<a href="/post/post-3/">Post 3</a>
<a href="/post/post-1/">Post 1</a>
<a href="/post/post-5/">Post 5</a>
Note that the original slice order is retained.
yes of course... Thanks for pointing that out. I wonder if it fares better "build time"-wise.
I'll try it out!
I wonder if it fares better "build time"-wise.
With .Params.related_pages
containing 999 elements:
{{ range .Params.related_pages }}
{{ with site.GetPage . }}
<a href="{{ .RelPermalink }}">{{ .LinkTitle }}</a>
{{ end }}
{{ end }}
392 ms (average of 5 runs)
{{ range apply .Params.related_pages "site.GetPage" "." }}
<a href="{{ .RelPermalink }}">{{ .LinkTitle }}</a>
{{ end }}
403 ms (average of 5 runs)
The 3% difference is meaningless, within the margin of measurement error. I ran the same tests again, and this time the second method was faster.
Current status
This is very common for a Front Matter fields to hold a list of file paths to content files in order to establish a one to many relationships between pages or settings.
Currently one has to define its own solution using
range
andsite.GetPage
and append it to aslice
. This might not be very efficient when dealing with hundreds of pages.Solution
If easily implemented and more efficient than the user defined solution Hugo could sport its own methods to retrieve a collection based on a slice of file paths with
site.GetPages
and.Page.GetPages
.Example