Repository: gohugoio/hugo (language: go)

Issue:
Support `where` operators for partial matches
Currently, the `where` function is a concise way to filter a collection by comparing *exact matches* between the collections’ data and known values. However, there’s no way to filter it to contain non-exact matches, such as substring, regex, or other types of matches.

One use-case: on my website, I have a data template containing Webmentions (a type of decentralized commenting) for my entire site. Each Webmention has a target URL. I insert Webmentions whose target URL matches the current page, so that each page can end with its own comments section.

I used to use a `where` filter to select just the mentions whose targets match the canonical URL of the current page; however, this didn’t account for fragments. I wanted the fragments at the end of a target URL to be ignored during comparison. `where` doesn’t support operators regular expressions, substring matching, or URL parsing. I had to resort to iteration and appending. Here’s a diff containing that change: <https://github.com/Seirdy/seirdy.one/commit/6fc55df73639149e715f0dacf7bceb6a61f94d46> ([plaintext](https://git.sr.ht/~seirdy/seirdy.one/commit/6fc55df73639149e715f0dacf7bceb6a61f94d46.patch)).

[Discussed on discourse.gohugo.io](https://discourse.gohugo.io/t/add-like-comparison-operator-to-the-where-function/42013)


Discussion / hints:

Fix patch:
diff --git a/tpl/collections/where.go b/tpl/collections/where.go
index 2904b7cdd4a..07c2d3deb3b 100644
--- a/tpl/collections/where.go
+++ b/tpl/collections/where.go
@@ -21,6 +21,7 @@ import (
 	"strings"
 
 	"github.com/gohugoio/hugo/common/hreflect"
+	"github.com/gohugoio/hugo/common/hstrings"
 	"github.com/gohugoio/hugo/common/maps"
 )
 
@@ -272,6 +273,17 @@ func (ns *Namespace) checkCondition(v, mv reflect.Value, op string) (bool, error
 			return false, nil
 		}
 		return false, errors.New("invalid intersect values")
+	case "like":
+		if svp != nil && smvp != nil {
+			re, err := hstrings.GetOrCompileRegexp(*smvp)
+			if err != nil {
+				return false, err
+			}
+			if re.MatchString(*svp) {
+				return true, nil
+			}
+			return false, nil
+		}
 	default:
 		return false, errors.New("no such operator")
 	}


Test patch:
diff --git a/tpl/collections/integration_test.go b/tpl/collections/integration_test.go
index 7ef0b6c47c8..a059bfd26be 100644
--- a/tpl/collections/integration_test.go
+++ b/tpl/collections/integration_test.go
@@ -196,3 +196,38 @@ title: "p3"
 Home: p1|p3|
 `)
 }
+
+// Issue #11279
+func TestWhereLikeOperator(t *testing.T) {
+	t.Parallel()
+	files := `
+-- content/p1.md --
+---
+title: P1
+foo: ab
+---
+-- content/p2.md --
+---
+title: P2
+foo: abc
+---
+-- content/p3.md --
+---
+title: P3
+foo: bc
+---
+-- layouts/index.html --
+<ul>
+  {{- range where site.RegularPages "Params.foo" "like" "^ab" -}}
+    <li>{{ .Title }}</li>
+  {{- end -}}
+</ul>
+  `
+	b := hugolib.NewIntegrationTestBuilder(
+		hugolib.IntegrationTestConfig{
+			T:           t,
+			TxtarString: files,
+		},
+	).Build()
+	b.AssertFileContent("public/index.html", "<ul><li>P1</li><li>P2</li></ul>")
+}