Paginate from slice of Page

Hi,

I’m trying to display a slice of Page in a very specific order that I build from various front-matter information.

The sort function is way too limited for my need (I would need a user comparison function, but there is no user functions within hugo templates).

Without pagination, I succeed by manually building a (sorted according to my need) slice of pages.
A quick example (my real code is more complex):

    {{ $s := .Page.Scratch }}
    {{ $s.Set "pages" .Page.Data.Pages }}
    {{ $s.Set "default" (slice) }}
    {{ $s.Set "cours" (slice) }}
    {{ range ($s.Get "pages") }}
    {{   $s.Set "type" "default" }}
    {{   if findRE "/ue/$" .File.Dir }}
    {{     $s.Set "type" "cours" }}
    {{   end }}
    {{   $s.Set ($s.Get "type") (union ($s.Get ($s.Get "type")) (slice .)) }}
    {{ end }}
    {{ $s.Set "pages" (union ($s.Get "cours") ($s.Get "default")) }}

Having sorted my pages, I can do

{{ range ($s.Get "pages") }}
...
{{ end }}

However, if I want to add some pagination, it does not work anymore.
If I try:

{{ $paginator := .Page.Paginate (($s.Get "pages")) }}
{{ range $paginator.Pages }}
...
}}

then I get:

[...] at <.Page.Paginate>: error calling Paginate: unsupported type in paginate, got []interface {}

Is it possible to allow Paginate to work from a slice of Page (instead of an internal “Pages” object)? Or is it possible to manually build a “Pages” object?

And same question about a dict of slice of pages that would be accepted by Paginate with the PageGroups function… For now, I get:

[...] at <.Page.Paginate>: error calling Paginate: unsupported type in paginate, got map[string]interface {}

Regards,
Vincent

1 Like

No. (but if anyone knows otherwise prove me wrong).

For me “building a slice of Pages” means to query a page collection (where) or use one of the many other funcs that works for pages, first, after, union, intersect… I must be missing something in the question, because this should be clear in the paginator docs.

1 Like

If you manually build a slice of pages with union, you get a basic array (as internal go type) and not a Pages (internal fo type) object. The first one is refused by Paginate in hugo, the second one is accepted.

That should be fixed. Can you create a GH issue? We should be able to “cast” it to Pages if all the elements are of the same type.

I just tried other code.
If I start from a hugolib.Pages and take care to stick to that, it works (ie it is accepted by Paginate).
For example, I can create an empty hugolib.Pages:

{{ $pagescol := .Data.Pages }}
{{ $s.Set "default" (where $pagescol "Title" "__") }}

(of course with no existing pages with “__” as title)

Iterating over pages, I can add it to my variable:

{{ range .Data.Pages }}
{{    $s.Set "default" (union ($s.Get "default") (where $pagescol "Title" .Title)) }}
{{ end }}

It does not work if I lost the hugolib.Pages somewhere. For example, the line within the range cannot be rewritten as

 {{    $s.Set "default" (union ($s.Get "default") (slice .)) }}

So, now, I can call Paginate:

{{ $paginator := .Page.Paginate ($s.Get "default") }}

But I cannot sort my pages because ‘sort’ then loose the hugolib.Pages structure:

{{ $paginator := .Page.Paginate (sort ($s.Get "default") "Params.rating") }}

The code in hugo seems indeed to be very strict about what can be given to create a Paginator. Perhaps this code can be extended/relaxed to accept array of Page (and dict of array of pages for PageGroups).

func toPages(seq interface{}) (Pages, error) {
  if seq == nil {
	return Pages{}, nil
  }

  switch seq.(type) {
  case Pages:
	return seq.(Pages), nil
  case *Pages:
	return *(seq.(*Pages)), nil
  case WeightedPages:
	return (seq.(WeightedPages)).Pages(), nil
  case PageGroup:
	return (seq.(PageGroup)).Pages, nil
  default:
	return nil, fmt.Errorf("unsupported type in paginate, got %T", seq)
  }
}
1 Like

I would not say “very strict”, but it could be improved, but you need to open a GitHub issue to track it.