Skip to content

Commit 381c0da

Browse files
committed
Fix some related content issues with content adapters
Fixes #13443
1 parent 227e429 commit 381c0da

8 files changed

+151
-16
lines changed

‎hugolib/page.go

+14
Original file line numberDiff line numberDiff line change
@@ -151,6 +151,20 @@ func (p *pageState) Key() string {
151151
return "page-" + strconv.FormatUint(p.pid, 10)
152152
}
153153

154+
// RelatedKeywords implements the related.Document interface needed for fast page searches.
155+
func (p *pageState) RelatedKeywords(cfg related.IndexConfig) ([]related.Keyword, error) {
156+
v, found, err := page.NamedPageMetaValue(p, cfg.Name)
157+
if err != nil {
158+
return nil, err
159+
}
160+
161+
if !found {
162+
return nil, nil
163+
}
164+
165+
return cfg.ToKeywords(v)
166+
}
167+
154168
func (p *pageState) resetBuildState() {
155169
// Nothing to do for now.
156170
}

‎hugolib/page__common.go

-1
Original file line numberDiff line numberDiff line change
@@ -68,7 +68,6 @@ type pageCommon struct {
6868
page.PageMetaInternalProvider
6969
page.Positioner
7070
page.RawContentProvider
71-
page.RelatedKeywordsProvider
7271
page.RefProvider
7372
page.ShortcodeInfoProvider
7473
page.SitesProvider

‎hugolib/page__meta.go

-12
Original file line numberDiff line numberDiff line change
@@ -27,8 +27,6 @@ import (
2727
"github.com/gohugoio/hugo/markup/converter"
2828
xmaps "golang.org/x/exp/maps"
2929

30-
"github.com/gohugoio/hugo/related"
31-
3230
"github.com/gohugoio/hugo/source"
3331

3432
"github.com/gohugoio/hugo/common/constants"
@@ -215,16 +213,6 @@ func (p *pageMeta) PathInfo() *paths.Path {
215213
return p.pathInfo
216214
}
217215

218-
// RelatedKeywords implements the related.Document interface needed for fast page searches.
219-
func (p *pageMeta) RelatedKeywords(cfg related.IndexConfig) ([]related.Keyword, error) {
220-
v, err := p.Param(cfg.Name)
221-
if err != nil {
222-
return nil, err
223-
}
224-
225-
return cfg.ToKeywords(v)
226-
}
227-
228216
func (p *pageMeta) IsSection() bool {
229217
return p.Kind() == kinds.KindSection
230218
}

‎hugolib/page__new.go

-1
Original file line numberDiff line numberDiff line change
@@ -202,7 +202,6 @@ func (h *HugoSites) doNewPage(m *pageMeta) (*pageState, *paths.Path, error) {
202202
ResourceParamsProvider: m,
203203
PageMetaProvider: m,
204204
PageMetaInternalProvider: m,
205-
RelatedKeywordsProvider: m,
206205
OutputFormatsProvider: page.NopPage,
207206
ResourceTypeProvider: pageTypesProvider,
208207
MediaTypeProvider: pageTypesProvider,

‎hugolib/pagesfromdata/pagesfromgotmpl_integration_test.go

+22-2
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
// Copyright 2024 The Hugo Authors. All rights reserved.
1+
// Copyright 2025 The Hugo Authors. All rights reserved.
22
//
33
// Licensed under the Apache License, Version 2.0 (the "License");
44
// you may not use this file except in compliance with the License.
@@ -23,6 +23,7 @@ import (
2323
"github.com/gohugoio/hugo/markup/asciidocext"
2424
"github.com/gohugoio/hugo/markup/pandoc"
2525
"github.com/gohugoio/hugo/markup/rst"
26+
"github.com/gohugoio/hugo/related"
2627
)
2728

2829
const filesPagesFromDataTempleBasic = `
@@ -73,10 +74,11 @@ Pfile Content
7374
{{ $title := printf "%s:%s" $pd $pp }}
7475
{{ $date := "2023-03-01" | time.AsTime }}
7576
{{ $dates := dict "date" $date }}
77+
{{ $keywords := slice "foo" "Bar"}}
7678
{{ $contentMarkdown := dict "value" "**Hello World**" "mediaType" "text/markdown" }}
7779
{{ $contentMarkdownDefault := dict "value" "**Hello World Default**" }}
7880
{{ $contentHTML := dict "value" "<b>Hello World!</b> No **markdown** here." "mediaType" "text/html" }}
79-
{{ $.AddPage (dict "kind" "page" "path" "P1" "title" $title "dates" $dates "content" $contentMarkdown "params" (dict "param1" "param1v" ) ) }}
81+
{{ $.AddPage (dict "kind" "page" "path" "P1" "title" $title "dates" $dates "keywords" $keywords "content" $contentMarkdown "params" (dict "param1" "param1v" ) ) }}
8082
{{ $.AddPage (dict "kind" "page" "path" "p2" "title" "p2title" "dates" $dates "content" $contentHTML ) }}
8183
{{ $.AddPage (dict "kind" "page" "path" "p3" "title" "p3title" "dates" $dates "content" $contentMarkdownDefault "draft" false ) }}
8284
{{ $.AddPage (dict "kind" "page" "path" "p4" "title" "p4title" "dates" $dates "content" $contentMarkdownDefault "draft" $data.draft ) }}
@@ -329,6 +331,24 @@ func TestPagesFromGoTmplRemoveGoTmpl(t *testing.T) {
329331
b.AssertFileContent("public/docs/index.html", "RegularPagesRecursive: pfile:/docs/pfile|$")
330332
}
331333

334+
// Issue #13443.
335+
func TestPagesFromGoRelatedKeywords(t *testing.T) {
336+
t.Parallel()
337+
b := hugolib.Test(t, filesPagesFromDataTempleBasic)
338+
339+
p1 := b.H.Sites[0].RegularPages()[0]
340+
icfg := related.IndexConfig{
341+
Name: "keywords",
342+
}
343+
k, err := p1.RelatedKeywords(icfg)
344+
b.Assert(err, qt.IsNil)
345+
b.Assert(k, qt.DeepEquals, icfg.StringsToKeywords("foo", "Bar"))
346+
icfg.Name = "title"
347+
k, err = p1.RelatedKeywords(icfg)
348+
b.Assert(err, qt.IsNil)
349+
b.Assert(k, qt.DeepEquals, icfg.StringsToKeywords("p1:p1"))
350+
}
351+
332352
func TestPagesFromGoTmplLanguagePerFile(t *testing.T) {
333353
filesTemplate := `
334354
-- hugo.toml --

‎related/inverted_index.go

+3
Original file line numberDiff line numberDiff line change
@@ -582,6 +582,9 @@ func DecodeConfig(m maps.Params) (Config, error) {
582582
}
583583
}
584584
for i := range c.Indices {
585+
// Lower case name.
586+
c.Indices[i].Name = strings.ToLower(c.Indices[i].Name)
587+
585588
icfg := c.Indices[i]
586589
if icfg.Type == "" {
587590
c.Indices[i].Type = TypeBasic

‎related/inverted_index_test.go

+45
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,7 @@ import (
2121
"time"
2222

2323
qt "github.com/frankban/quicktest"
24+
"github.com/gohugoio/hugo/config"
2425
)
2526

2627
type testDoc struct {
@@ -249,6 +250,50 @@ func TestToKeywordsToLower(t *testing.T) {
249250
})
250251
}
251252

253+
func TestDecodeConfig(t *testing.T) {
254+
c := qt.New(t)
255+
256+
configToml := `
257+
[related]
258+
includeNewer = true
259+
threshold = 32
260+
toLower = false
261+
[[related.indices]]
262+
applyFilter = false
263+
cardinalityThreshold = 0
264+
name = 'KeyworDs'
265+
pattern = ''
266+
toLower = false
267+
type = 'basic'
268+
weight = 100
269+
[[related.indices]]
270+
applyFilter = true
271+
cardinalityThreshold = 32
272+
name = 'date'
273+
pattern = ''
274+
toLower = false
275+
type = 'basic'
276+
weight = 10
277+
[[related.indices]]
278+
applyFilter = false
279+
cardinalityThreshold = 0
280+
name = 'tags'
281+
pattern = ''
282+
toLower = false
283+
type = 'fragments'
284+
weight = 80
285+
`
286+
287+
m, err := config.FromConfigString(configToml, "toml")
288+
c.Assert(err, qt.IsNil)
289+
conf, err := DecodeConfig(m.GetParams("related"))
290+
291+
c.Assert(err, qt.IsNil)
292+
c.Assert(conf.IncludeNewer, qt.IsTrue)
293+
first := conf.Indices[0]
294+
c.Assert(first.Name, qt.Equals, "keywords")
295+
}
296+
252297
func TestToKeywordsAnySlice(t *testing.T) {
253298
c := qt.New(t)
254299
var config IndexConfig

‎resources/page/page.go

+67
Original file line numberDiff line numberDiff line change
@@ -180,6 +180,11 @@ type PageFragment interface {
180180
resource.ResourceNameTitleProvider
181181
}
182182

183+
type PageMetaResource interface {
184+
PageMetaProvider
185+
resource.Resource
186+
}
187+
183188
// PageMetaProvider provides page metadata, typically provided via front matter.
184189
type PageMetaProvider interface {
185190
// The 4 page dates
@@ -251,6 +256,68 @@ type PageMetaProvider interface {
251256
Weight() int
252257
}
253258

259+
// NamedPageMetaValue returns a named metadata value from a PageMetaResource.
260+
// This is currently only used to generate keywords for related content.
261+
// If nameLower is not one of the metadata interface methods, we
262+
// look in Params.
263+
func NamedPageMetaValue(p PageMetaResource, nameLower string) (any, bool, error) {
264+
var (
265+
v any
266+
err error
267+
)
268+
269+
switch nameLower {
270+
case "kind":
271+
v = p.Kind()
272+
case "bundletype":
273+
v = p.BundleType()
274+
case "mediatype":
275+
v = p.MediaType()
276+
case "section":
277+
v = p.Section()
278+
case "lang":
279+
v = p.Lang()
280+
case "aliases":
281+
v = p.Aliases()
282+
case "name":
283+
v = p.Name()
284+
case "keywords":
285+
v = p.Keywords()
286+
case "description":
287+
v = p.Description()
288+
case "title":
289+
v = p.Title()
290+
case "linktitle":
291+
v = p.LinkTitle()
292+
case "slug":
293+
v = p.Slug()
294+
case "date":
295+
v = p.Date()
296+
case "publishdate":
297+
v = p.PublishDate()
298+
case "expirydate":
299+
v = p.ExpiryDate()
300+
case "lastmod":
301+
v = p.Lastmod()
302+
case "draft":
303+
v = p.Draft()
304+
case "type":
305+
v = p.Type()
306+
case "layout":
307+
v = p.Layout()
308+
case "weight":
309+
v = p.Weight()
310+
default:
311+
// Try params.
312+
v, err = resource.Param(p, nil, nameLower)
313+
if v == nil {
314+
return nil, false, nil
315+
}
316+
}
317+
318+
return v, err == nil, err
319+
}
320+
254321
// PageMetaInternalProvider provides internal page metadata.
255322
type PageMetaInternalProvider interface {
256323
// This is for internal use only.

0 commit comments

Comments
 (0)