Skip to content

Commit

Permalink
Fix some related content issues with content adapters
Browse files Browse the repository at this point in the history
Fixes #13443
  • Loading branch information
bep committed Feb 25, 2025
1 parent 227e429 commit 381c0da
Show file tree
Hide file tree
Showing 8 changed files with 151 additions and 16 deletions.
14 changes: 14 additions & 0 deletions hugolib/page.go
Original file line number Diff line number Diff line change
Expand Up @@ -151,6 +151,20 @@ func (p *pageState) Key() string {
return "page-" + strconv.FormatUint(p.pid, 10)
}

// RelatedKeywords implements the related.Document interface needed for fast page searches.
func (p *pageState) RelatedKeywords(cfg related.IndexConfig) ([]related.Keyword, error) {
v, found, err := page.NamedPageMetaValue(p, cfg.Name)
if err != nil {
return nil, err
}

if !found {
return nil, nil
}

return cfg.ToKeywords(v)
}

func (p *pageState) resetBuildState() {
// Nothing to do for now.
}
Expand Down
1 change: 0 additions & 1 deletion hugolib/page__common.go
Original file line number Diff line number Diff line change
Expand Up @@ -68,7 +68,6 @@ type pageCommon struct {
page.PageMetaInternalProvider
page.Positioner
page.RawContentProvider
page.RelatedKeywordsProvider
page.RefProvider
page.ShortcodeInfoProvider
page.SitesProvider
Expand Down
12 changes: 0 additions & 12 deletions hugolib/page__meta.go
Original file line number Diff line number Diff line change
Expand Up @@ -27,8 +27,6 @@ import (
"github.com/gohugoio/hugo/markup/converter"
xmaps "golang.org/x/exp/maps"

"github.com/gohugoio/hugo/related"

"github.com/gohugoio/hugo/source"

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

// RelatedKeywords implements the related.Document interface needed for fast page searches.
func (p *pageMeta) RelatedKeywords(cfg related.IndexConfig) ([]related.Keyword, error) {
v, err := p.Param(cfg.Name)
if err != nil {
return nil, err
}

return cfg.ToKeywords(v)
}

func (p *pageMeta) IsSection() bool {
return p.Kind() == kinds.KindSection
}
Expand Down
1 change: 0 additions & 1 deletion hugolib/page__new.go
Original file line number Diff line number Diff line change
Expand Up @@ -202,7 +202,6 @@ func (h *HugoSites) doNewPage(m *pageMeta) (*pageState, *paths.Path, error) {
ResourceParamsProvider: m,
PageMetaProvider: m,
PageMetaInternalProvider: m,
RelatedKeywordsProvider: m,
OutputFormatsProvider: page.NopPage,
ResourceTypeProvider: pageTypesProvider,
MediaTypeProvider: pageTypesProvider,
Expand Down
24 changes: 22 additions & 2 deletions hugolib/pagesfromdata/pagesfromgotmpl_integration_test.go
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
// Copyright 2024 The Hugo Authors. All rights reserved.
// Copyright 2025 The Hugo Authors. All rights reserved.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
Expand All @@ -23,6 +23,7 @@ import (
"github.com/gohugoio/hugo/markup/asciidocext"
"github.com/gohugoio/hugo/markup/pandoc"
"github.com/gohugoio/hugo/markup/rst"
"github.com/gohugoio/hugo/related"
)

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

// Issue #13443.
func TestPagesFromGoRelatedKeywords(t *testing.T) {
t.Parallel()
b := hugolib.Test(t, filesPagesFromDataTempleBasic)

p1 := b.H.Sites[0].RegularPages()[0]
icfg := related.IndexConfig{
Name: "keywords",
}
k, err := p1.RelatedKeywords(icfg)
b.Assert(err, qt.IsNil)
b.Assert(k, qt.DeepEquals, icfg.StringsToKeywords("foo", "Bar"))
icfg.Name = "title"
k, err = p1.RelatedKeywords(icfg)
b.Assert(err, qt.IsNil)
b.Assert(k, qt.DeepEquals, icfg.StringsToKeywords("p1:p1"))
}

func TestPagesFromGoTmplLanguagePerFile(t *testing.T) {
filesTemplate := `
-- hugo.toml --
Expand Down
3 changes: 3 additions & 0 deletions related/inverted_index.go
Original file line number Diff line number Diff line change
Expand Up @@ -582,6 +582,9 @@ func DecodeConfig(m maps.Params) (Config, error) {
}
}
for i := range c.Indices {
// Lower case name.
c.Indices[i].Name = strings.ToLower(c.Indices[i].Name)

icfg := c.Indices[i]
if icfg.Type == "" {
c.Indices[i].Type = TypeBasic
Expand Down
45 changes: 45 additions & 0 deletions related/inverted_index_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@ import (
"time"

qt "github.com/frankban/quicktest"
"github.com/gohugoio/hugo/config"
)

type testDoc struct {
Expand Down Expand Up @@ -249,6 +250,50 @@ func TestToKeywordsToLower(t *testing.T) {
})
}

func TestDecodeConfig(t *testing.T) {
c := qt.New(t)

configToml := `
[related]
includeNewer = true
threshold = 32
toLower = false
[[related.indices]]
applyFilter = false
cardinalityThreshold = 0
name = 'KeyworDs'
pattern = ''
toLower = false
type = 'basic'
weight = 100
[[related.indices]]
applyFilter = true
cardinalityThreshold = 32
name = 'date'
pattern = ''
toLower = false
type = 'basic'
weight = 10
[[related.indices]]
applyFilter = false
cardinalityThreshold = 0
name = 'tags'
pattern = ''
toLower = false
type = 'fragments'
weight = 80
`

m, err := config.FromConfigString(configToml, "toml")
c.Assert(err, qt.IsNil)
conf, err := DecodeConfig(m.GetParams("related"))

c.Assert(err, qt.IsNil)
c.Assert(conf.IncludeNewer, qt.IsTrue)
first := conf.Indices[0]
c.Assert(first.Name, qt.Equals, "keywords")
}

func TestToKeywordsAnySlice(t *testing.T) {
c := qt.New(t)
var config IndexConfig
Expand Down
67 changes: 67 additions & 0 deletions resources/page/page.go
Original file line number Diff line number Diff line change
Expand Up @@ -180,6 +180,11 @@ type PageFragment interface {
resource.ResourceNameTitleProvider
}

type PageMetaResource interface {
PageMetaProvider
resource.Resource
}

// PageMetaProvider provides page metadata, typically provided via front matter.
type PageMetaProvider interface {
// The 4 page dates
Expand Down Expand Up @@ -251,6 +256,68 @@ type PageMetaProvider interface {
Weight() int
}

// NamedPageMetaValue returns a named metadata value from a PageMetaResource.
// This is currently only used to generate keywords for related content.
// If nameLower is not one of the metadata interface methods, we
// look in Params.
func NamedPageMetaValue(p PageMetaResource, nameLower string) (any, bool, error) {
var (
v any
err error
)

switch nameLower {
case "kind":
v = p.Kind()
case "bundletype":
v = p.BundleType()
case "mediatype":
v = p.MediaType()
case "section":
v = p.Section()
case "lang":
v = p.Lang()
case "aliases":
v = p.Aliases()
case "name":
v = p.Name()
case "keywords":
v = p.Keywords()
case "description":
v = p.Description()
case "title":
v = p.Title()
case "linktitle":
v = p.LinkTitle()
case "slug":
v = p.Slug()
case "date":
v = p.Date()
case "publishdate":
v = p.PublishDate()
case "expirydate":
v = p.ExpiryDate()
case "lastmod":
v = p.Lastmod()
case "draft":
v = p.Draft()
case "type":
v = p.Type()
case "layout":
v = p.Layout()
case "weight":
v = p.Weight()
default:
// Try params.
v, err = resource.Param(p, nil, nameLower)
if v == nil {
return nil, false, nil
}
}

return v, err == nil, err
}

// PageMetaInternalProvider provides internal page metadata.
type PageMetaInternalProvider interface {
// This is for internal use only.
Expand Down

0 comments on commit 381c0da

Please sign in to comment.