Repository: gohugoio/hugo (language: go)

Issue:
Cascade _target.kind not accepting glob pattern
<!-- Please answer these questions before submitting your issue. Thanks! -->

### What version of Hugo are you using (`hugo version`)?

<pre>
hugo v0.86.1-F6821B88+extended darwin/amd64 BuildDate=2021-07-30T10:13:35Z VendorInfo=gohugoio

</pre>

### Does this issue reproduce with the latest release?
Yes

Using the following `cascade` configuration: 

```
# content/_index.md
cascade:
- _target:
    path: /poetry/**
    lang: en
    kind: '{section,page}'
```

Hugo returns the following error:

``` 
Error: Error building site: ".../content/en/_index.md:1:1": "{section,page}" is not a valid Page Kind
```

As per doc:
> A Glob pattern matching the Page’s Kind(s), e.g. “{home,section}”.


Discussion / hints:
I closed this when I was in a little bit of a grumpy mood -- we should fix this. :-)
Maybe for this particulier case it would be easier for both maintainers and users to add a `kinds` key which take an array rather than suggest glob for a list of predefined and documented strings...

Fix patch:
diff --git a/docs/content/en/content-management/front-matter.md b/docs/content/en/content-management/front-matter.md
index 2155f19925c..6986f067fa6 100644
--- a/docs/content/en/content-management/front-matter.md
+++ b/docs/content/en/content-management/front-matter.md
@@ -184,7 +184,7 @@ path
 : A [Glob](https://github.com/gobwas/glob) pattern matching the content path below /content. Expects Unix-styled slashes. Note that this is the virtual path, so it starts at the mount root. The matching support double-asterisks so you can match for patterns like `/blog/*/**` to match anything from the third level and down.
 
 kind
-: The Page's Kind, e.g. "section".
+: A Glob pattern matching the Page's Kind(s), e.g. "{home,section}".
 
 lang
 : A Glob pattern matching the Page's language, e.g. "{en,sv}".
diff --git a/resources/page/page_matcher.go b/resources/page/page_matcher.go
index 0c4c2d0e29e..4c1409e9e97 100644
--- a/resources/page/page_matcher.go
+++ b/resources/page/page_matcher.go
@@ -17,11 +17,10 @@ import (
 	"path/filepath"
 	"strings"
 
-	"github.com/pkg/errors"
-
 	"github.com/gohugoio/hugo/common/maps"
 	"github.com/gohugoio/hugo/hugofs/glob"
 	"github.com/mitchellh/mapstructure"
+	"github.com/pkg/errors"
 )
 
 // A PageMatcher can be used to match a Page with Glob patterns.
@@ -114,8 +113,16 @@ func DecodePageMatcher(m interface{}, v *PageMatcher) error {
 
 	v.Kind = strings.ToLower(v.Kind)
 	if v.Kind != "" {
-		if _, found := kindMap[v.Kind]; !found {
-			return errors.Errorf("%q is not a valid Page Kind", v.Kind)
+		g, _ := glob.GetGlob(v.Kind)
+		found := false
+		for _, k := range kindMap {
+			if g.Match(k) {
+				found = true
+				break
+			}
+		}
+		if !found {
+			return errors.Errorf("%q did not match a valid Page Kind", v.Kind)
 		}
 	}
 


Test patch:
diff --git a/resources/page/page_matcher_test.go b/resources/page/page_matcher_test.go
index 745a6aa3230..aaef27eaa37 100644
--- a/resources/page/page_matcher_test.go
+++ b/resources/page/page_matcher_test.go
@@ -54,7 +54,12 @@ func TestPageMatcher(t *testing.T) {
 
 	c.Run("Decode", func(c *qt.C) {
 		var v PageMatcher
-		c.Assert(DecodePageMatcher(map[string]interface{}{"kind": "foo"}, &v), qt.Not((qt.IsNil)))
+		c.Assert(DecodePageMatcher(map[string]interface{}{"kind": "foo"}, &v), qt.Not(qt.IsNil))
+		c.Assert(DecodePageMatcher(map[string]interface{}{"kind": "{foo,bar}"}, &v), qt.Not(qt.IsNil))
+		c.Assert(DecodePageMatcher(map[string]interface{}{"kind": "taxonomy"}, &v), qt.IsNil)
+		c.Assert(DecodePageMatcher(map[string]interface{}{"kind": "{taxonomy,foo}"}, &v), qt.IsNil)
+		c.Assert(DecodePageMatcher(map[string]interface{}{"kind": "{taxonomy,term}"}, &v), qt.IsNil)
+		c.Assert(DecodePageMatcher(map[string]interface{}{"kind": "*"}, &v), qt.IsNil)
 		c.Assert(DecodePageMatcher(map[string]interface{}{"kind": "home", "path": filepath.FromSlash("/a/b/**")}, &v), qt.IsNil)
 		c.Assert(v, qt.Equals, PageMatcher{Kind: "home", Path: "/a/b/**"})
 	})