Rename taxonomy kinds from taxonomy to term, taxonomyTerm to taxonomy

And we have taken great measures to limit potential site breakage:

* For `disableKinds` and `outputs` we try to map from old to new values if possible, if not we print an ERROR that can be toggled off if not relevant.
* The layout lookup is mostly compatible with more options for the new `term` kind.

That leaves:

* Where queries in site.Pages using taxonomy/taxonomyTerm Kind values as filter.
* Other places where these kind value are used in the templates (classes etc.)

Fixes #6911
Fixes #7395
This commit is contained in:
Bjørn Erik Pedersen 2020-06-16 15:43:50 +02:00
parent 9679023f2b
commit fc045e12a9
44 changed files with 644 additions and 220 deletions

View File

@ -0,0 +1,21 @@
// Copyright 2020 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.
// You may obtain a copy of the License at
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
package constants
// Error IDs.
// Do not change these values.
const (
ErrIDAmbigousDisableKindTaxonomy = "error-disable-taxonomy"
ErrIDAmbigousOutputKindTaxonomy = "error-output-taxonomy"
)

View File

@ -0,0 +1,52 @@
// Copyright 2020 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.
// You may obtain a copy of the License at
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
package loggers
import (
"fmt"
"strings"
)
// IgnorableLogger is a logger that ignores certain log statements.
type IgnorableLogger struct {
logger *Logger
statements map[string]bool
}
// NewIgnorableLogger wraps the given logger and ignores the log statement IDs given.
func NewIgnorableLogger(logger *Logger, statements ...string) IgnorableLogger {
statementsSet := make(map[string]bool)
for _, s := range statements {
statementsSet[strings.ToLower(s)] = true
}
return IgnorableLogger{
logger: logger,
statements: statementsSet,
}
}
func (l IgnorableLogger) Errorf(statementID, format string, v ...interface{}) {
if l.statements[statementID] {
// Ignore.
return
}
ignoreMsg := fmt.Sprintf(`
If you feel that this should not be logged as an ERROR, you can ignore it by adding this to your site config:
ignoreErrors = [%q]`, statementID)
format += ignoreMsg
l.logger.ERROR.Printf(format, v...)
}

View File

@ -1,10 +1,9 @@
---
title: Taxonomies
linktitle:
description: Hugo includes support for user-defined taxonomies to help you demonstrate logical relationships between content for the end users of your website.
description: Hugo includes support for user-defined taxonomies..
date: 2017-02-01
publishdate: 2017-02-01
lastmod: 2017-02-01
keywords: [taxonomies,metadata,front matter,terms]
categories: [content management]
menu:
@ -32,7 +31,6 @@ Term
Value
: a piece of content assigned to a term
{{< youtube pCPCQgqC8RA >}}
## Example Taxonomy: Movie Website
@ -97,9 +95,13 @@ Without adding a single line to your [site config][config] file, Hugo will autom
If you do not want Hugo to create any taxonomies, set `disableKinds` in your [site config][config] to the following:
{{< code-toggle copy="false" >}}
disableKinds = ["taxonomy","taxonomyTerm"]
disableKinds = ["taxonomy","term"]
{{</ code-toggle >}}
{{< new-in "0.73.0" >}} We have fixed the before confusing page kinds used for taxonomies (see the listing below) to be in line with the terms used when we talk about taxonomies. We have been careful to avoid site breakage, and you should get an ERROR in the console if you need to adjust your `disableKinds` section.
{{< page-kinds >}}
### Default Destinations
When taxonomies are used---and [taxonomy templates][] are provided---Hugo will automatically create both a page listing all the taxonomy's terms and individual pages with lists of content associated with each term. For example, a `categories` taxonomy declared in your configuration and used in your content front matter will create the following pages:
@ -190,7 +192,7 @@ By using taxonomic weight, the same piece of content can appear in different pos
Currently taxonomies only support the [default `weight => date` ordering of list content](/templates/lists/#default-weight-date). For more information, see the documentation on [taxonomy templates](/templates/taxonomy-templates/).
{{% /note %}}
## Add custom metadata to a Taxonomy Term
## Add custom metadata a Taxonomy or Term
If you need to add custom metadata to your taxonomy terms, you will need to create a page for that term at `/content/<TAXONOMY>/<TERM>/_index.md` and add your metadata in it's front matter. Continuing with our 'Actors' example, let's say you want to add a wikipedia page link to each actor. Your terms pages would be something like this:
@ -201,7 +203,6 @@ If you need to add custom metadata to your taxonomy terms, you will need to crea
---
{{< /code >}}
You can later use your custom metadata as shown in the [Taxonomy Terms Templates documentation](/templates/taxonomy-templates/#displaying-custom-metadata-in-taxonomy-terms-templates).
[`urlize` template function]: /functions/urlize/
[content section]: /content-management/sections/

View File

@ -124,7 +124,7 @@ disableHugoGeneratorInject (false)
: Hugo will, by default, inject a generator meta tag in the HTML head on the _home page only_. You can turn it off, but we would really appreciate if you don't, as this is a good way to watch Hugo's popularity on the rise.
disableKinds ([])
: Enable disabling of all pages of the specified *Kinds*. Allowed values in this list: `"page"`, `"home"`, `"section"`, `"taxonomy"`, `"taxonomyTerm"`, `"RSS"`, `"sitemap"`, `"robotsTXT"`, `"404"`.
: Enable disabling of all pages of the specified *Kinds*. Allowed values in this list: `"page"`, `"home"`, `"section"`, `"taxonomy"`, `"term"`, `"RSS"`, `"sitemap"`, `"robotsTXT"`, `"404"`.
disableLiveReload (false)
: Disable automatic live reloading of browser window.

View File

@ -41,7 +41,7 @@ Type
: Is value of `type` if set in front matter, else it is the name of the root section (e.g. "blog"). It will always have a value, so if not set, the value is "page".
Section
: Is relevant for `section`, `taxonomy` and `taxonomyTerm` types.
: Is relevant for `section`, `taxonomy` and `term` types.
{{% note %}}
**Tip:** The examples below looks long and complex. That is the flexibility talking. Most Hugo sites contain just a handful of templates:
@ -72,13 +72,13 @@ In Hugo, layouts can live in either the project's or the themes' layout folders,
{{< datatable-filtered "output" "layouts" "Kind == section" "Example" "OutputFormat" "Suffix" "Template Lookup Order" >}}
## Examples: Layout Lookup for Taxonomy List Pages
## Examples: Layout Lookup for Taxonomy Pages
{{< datatable-filtered "output" "layouts" "Kind == taxonomy" "Example" "OutputFormat" "Suffix" "Template Lookup Order" >}}
## Examples: Layout Lookup for Taxonomy Terms Pages
## Examples: Layout Lookup for Term Pages
{{< datatable-filtered "output" "layouts" "Kind == taxonomyTerm" "Example" "OutputFormat" "Suffix" "Template Lookup Order" >}}
{{< datatable-filtered "output" "layouts" "Kind == term" "Example" "OutputFormat" "Suffix" "Template Lookup Order" >}}

View File

@ -137,8 +137,8 @@ Formats are set based on that.
| `page` | HTML |
| `home` | HTML, RSS |
| `section` | HTML, RSS |
| `taxonomyTerm` | HTML, RSS |
| `taxonomy` | HTML, RSS |
| `taxonomy` | HTML, RSS |
| `term` | HTML, RSS |
### Customizing Output Formats
@ -156,10 +156,14 @@ Example from site config file:
Note that in the above examples, the *output formats* for `section`,
`taxonomyTerm` and `taxonomy` will stay at their default value `["HTML",
`taxonomy` and `term` will stay at their default value `["HTML",
"RSS"]`.
* The `outputs` definition is per [`Page` `Kind`][page_kinds] (`page`, `home`, `section`, `taxonomy`, or `taxonomyTerm`).
{{< new-in "0.73.0" >}} We have fixed the before confusing page kinds used for taxonomies (see the listing below) to be in line with the terms used when we talk about taxonomies. We have been careful to avoid site breakage, and you should get an ERROR in the console if you need to adjust your `outputs` section.
{{% page-kinds %}}
* The `outputs` definition is per [`Page` `Kind`][page_kinds] (`page`, `home`, `section`, `taxonomy`, or `term`).
* The names (e.g. `HTML`, `AMP`) used must match the `Name` of a defined *Output Format*.
* These names are case insensitive.
* These can be overridden per `Page` in the front matter of content files.

View File

@ -30,13 +30,7 @@ See [Template Lookup](/templates/lookup-order/).
Every `Page` in Hugo has a `.Kind` attribute.
| Kind | Description | Example |
|----------------|--------------------------------------------------------------------|-------------------------------------------------------------------------------|
| `home` | The home page | `/index.html` |
| `page` | A page showing a _regular page_ | `my-post` page (`/posts/my-post/index.html`) |
| `section` | A page listing _regular pages_ from a given [_section_][sections] | `posts` section (`/posts/index.html`) |
| `taxonomy` | A page listing _regular pages_ from a given _taxonomy term_ | page for the term `awesome` from `tags` taxonomy (`/tags/awesome/index.html`) |
| `taxonomyTerm` | A page listing terms from a given _taxonomy_ | page for the `tags` taxonomy (`/tags/index.html`) |
{{% page-kinds %}}
## `.Site.GetPage` with Sections

View File

@ -480,6 +480,17 @@
"genshitext"
]
},
{
"Name": "Gherkin",
"Aliases": [
"Cucumber",
"FEATURE",
"Gherkin",
"cucumber",
"feature",
"gherkin"
]
},
{
"Name": "Gnuplot",
"Aliases": [
@ -528,6 +539,12 @@
"hcl"
]
},
{
"Name": "HLB",
"Aliases": [
"hlb"
]
},
{
"Name": "HTML",
"Aliases": [
@ -998,6 +1015,15 @@
"ragel"
]
},
{
"Name": "ReasonML",
"Aliases": [
"re",
"reason",
"reasonml",
"rei"
]
},
{
"Name": "Rexx",
"Aliases": [
@ -1027,6 +1053,13 @@
"rust"
]
},
{
"Name": "SAS",
"Aliases": [
"SAS",
"sas"
]
},
{
"Name": "SCSS",
"Aliases": [
@ -1250,7 +1283,6 @@
"Name": "TypoScript",
"Aliases": [
"ts",
"txt",
"typoscript"
]
},
@ -1324,6 +1356,12 @@
"yml"
]
},
{
"Name": "YANG",
"Aliases": [
"yang"
]
},
{
"Name": "cfstatement",
"Aliases": [
@ -1466,6 +1504,7 @@
"keepDefaultAttrVals": true,
"keepDocumentTags": true,
"keepEndTags": true,
"keepQuotes": false,
"keepWhitespace": false
},
"css": {
@ -2257,75 +2296,100 @@
]
},
{
"Example": "Taxonomy list in categories",
"Example": "Taxonomy in categories",
"Kind": "taxonomy",
"OutputFormat": "RSS",
"Suffix": "xml",
"Template Lookup Order": [
"layouts/categories/category.rss.xml",
"layouts/categories/category.terms.rss.xml",
"layouts/categories/terms.rss.xml",
"layouts/categories/taxonomy.rss.xml",
"layouts/categories/rss.xml",
"layouts/categories/list.rss.xml",
"layouts/categories/category.xml",
"layouts/categories/category.terms.xml",
"layouts/categories/terms.xml",
"layouts/categories/taxonomy.xml",
"layouts/categories/list.xml",
"layouts/taxonomy/category.rss.xml",
"layouts/taxonomy/taxonomy.rss.xml",
"layouts/taxonomy/rss.xml",
"layouts/taxonomy/list.rss.xml",
"layouts/taxonomy/category.xml",
"layouts/taxonomy/taxonomy.xml",
"layouts/taxonomy/list.xml",
"layouts/category/category.rss.xml",
"layouts/category/category.terms.rss.xml",
"layouts/category/terms.rss.xml",
"layouts/category/taxonomy.rss.xml",
"layouts/category/rss.xml",
"layouts/category/list.rss.xml",
"layouts/category/category.xml",
"layouts/category/category.terms.xml",
"layouts/category/terms.xml",
"layouts/category/taxonomy.xml",
"layouts/category/list.xml",
"layouts/_default/category.rss.xml",
"layouts/taxonomy/category.terms.rss.xml",
"layouts/taxonomy/terms.rss.xml",
"layouts/taxonomy/taxonomy.rss.xml",
"layouts/taxonomy/rss.xml",
"layouts/taxonomy/list.rss.xml",
"layouts/taxonomy/category.terms.xml",
"layouts/taxonomy/terms.xml",
"layouts/taxonomy/taxonomy.xml",
"layouts/taxonomy/list.xml",
"layouts/_default/category.terms.rss.xml",
"layouts/_default/terms.rss.xml",
"layouts/_default/taxonomy.rss.xml",
"layouts/_default/rss.xml",
"layouts/_default/list.rss.xml",
"layouts/_default/category.xml",
"layouts/_default/category.terms.xml",
"layouts/_default/terms.xml",
"layouts/_default/taxonomy.xml",
"layouts/_default/list.xml",
"layouts/_internal/_default/rss.xml"
]
},
{
"Example": "Taxonomy terms in categories",
"Kind": "taxonomyTerm",
"Example": "Term in categories",
"Kind": "term",
"OutputFormat": "RSS",
"Suffix": "xml",
"Template Lookup Order": [
"layouts/categories/category.terms.rss.xml",
"layouts/categories/terms.rss.xml",
"layouts/categories/term.rss.xml",
"layouts/categories/category.rss.xml",
"layouts/categories/taxonomy.rss.xml",
"layouts/categories/rss.xml",
"layouts/categories/list.rss.xml",
"layouts/categories/category.terms.xml",
"layouts/categories/terms.xml",
"layouts/categories/term.xml",
"layouts/categories/category.xml",
"layouts/categories/taxonomy.xml",
"layouts/categories/list.xml",
"layouts/taxonomy/category.terms.rss.xml",
"layouts/taxonomy/terms.rss.xml",
"layouts/term/term.rss.xml",
"layouts/term/category.rss.xml",
"layouts/term/taxonomy.rss.xml",
"layouts/term/rss.xml",
"layouts/term/list.rss.xml",
"layouts/term/term.xml",
"layouts/term/category.xml",
"layouts/term/taxonomy.xml",
"layouts/term/list.xml",
"layouts/taxonomy/term.rss.xml",
"layouts/taxonomy/category.rss.xml",
"layouts/taxonomy/taxonomy.rss.xml",
"layouts/taxonomy/rss.xml",
"layouts/taxonomy/list.rss.xml",
"layouts/taxonomy/category.terms.xml",
"layouts/taxonomy/terms.xml",
"layouts/taxonomy/term.xml",
"layouts/taxonomy/category.xml",
"layouts/taxonomy/taxonomy.xml",
"layouts/taxonomy/list.xml",
"layouts/category/category.terms.rss.xml",
"layouts/category/terms.rss.xml",
"layouts/category/term.rss.xml",
"layouts/category/category.rss.xml",
"layouts/category/taxonomy.rss.xml",
"layouts/category/rss.xml",
"layouts/category/list.rss.xml",
"layouts/category/category.terms.xml",
"layouts/category/terms.xml",
"layouts/category/term.xml",
"layouts/category/category.xml",
"layouts/category/taxonomy.xml",
"layouts/category/list.xml",
"layouts/_default/category.terms.rss.xml",
"layouts/_default/terms.rss.xml",
"layouts/_default/term.rss.xml",
"layouts/_default/category.rss.xml",
"layouts/_default/taxonomy.rss.xml",
"layouts/_default/rss.xml",
"layouts/_default/list.rss.xml",
"layouts/_default/category.terms.xml",
"layouts/_default/terms.xml",
"layouts/_default/term.xml",
"layouts/_default/category.xml",
"layouts/_default/taxonomy.xml",
"layouts/_default/list.xml",
"layouts/_internal/_default/rss.xml"
]
@ -2426,61 +2490,85 @@
"OutputFormat": "HTML",
"Suffix": "html",
"Template Lookup Order": [
"layouts/categories/category.html.html",
"layouts/categories/category.terms.html.html",
"layouts/categories/terms.html.html",
"layouts/categories/taxonomy.html.html",
"layouts/categories/list.html.html",
"layouts/categories/category.html",
"layouts/categories/category.terms.html",
"layouts/categories/terms.html",
"layouts/categories/taxonomy.html",
"layouts/categories/list.html",
"layouts/taxonomy/category.html.html",
"layouts/taxonomy/taxonomy.html.html",
"layouts/taxonomy/list.html.html",
"layouts/taxonomy/category.html",
"layouts/taxonomy/taxonomy.html",
"layouts/taxonomy/list.html",
"layouts/category/category.html.html",
"layouts/category/category.terms.html.html",
"layouts/category/terms.html.html",
"layouts/category/taxonomy.html.html",
"layouts/category/list.html.html",
"layouts/category/category.html",
"layouts/category/category.terms.html",
"layouts/category/terms.html",
"layouts/category/taxonomy.html",
"layouts/category/list.html",
"layouts/_default/category.html.html",
"layouts/taxonomy/category.terms.html.html",
"layouts/taxonomy/terms.html.html",
"layouts/taxonomy/taxonomy.html.html",
"layouts/taxonomy/list.html.html",
"layouts/taxonomy/category.terms.html",
"layouts/taxonomy/terms.html",
"layouts/taxonomy/taxonomy.html",
"layouts/taxonomy/list.html",
"layouts/_default/category.terms.html.html",
"layouts/_default/terms.html.html",
"layouts/_default/taxonomy.html.html",
"layouts/_default/list.html.html",
"layouts/_default/category.html",
"layouts/_default/category.terms.html",
"layouts/_default/terms.html",
"layouts/_default/taxonomy.html",
"layouts/_default/list.html"
]
},
{
"Example": "Taxonomy term in categories",
"Kind": "taxonomyTerm",
"Kind": "term",
"OutputFormat": "HTML",
"Suffix": "html",
"Template Lookup Order": [
"layouts/categories/category.terms.html.html",
"layouts/categories/terms.html.html",
"layouts/categories/term.html.html",
"layouts/categories/category.html.html",
"layouts/categories/taxonomy.html.html",
"layouts/categories/list.html.html",
"layouts/categories/category.terms.html",
"layouts/categories/terms.html",
"layouts/categories/term.html",
"layouts/categories/category.html",
"layouts/categories/taxonomy.html",
"layouts/categories/list.html",
"layouts/taxonomy/category.terms.html.html",
"layouts/taxonomy/terms.html.html",
"layouts/term/term.html.html",
"layouts/term/category.html.html",
"layouts/term/taxonomy.html.html",
"layouts/term/list.html.html",
"layouts/term/term.html",
"layouts/term/category.html",
"layouts/term/taxonomy.html",
"layouts/term/list.html",
"layouts/taxonomy/term.html.html",
"layouts/taxonomy/category.html.html",
"layouts/taxonomy/taxonomy.html.html",
"layouts/taxonomy/list.html.html",
"layouts/taxonomy/category.terms.html",
"layouts/taxonomy/terms.html",
"layouts/taxonomy/term.html",
"layouts/taxonomy/category.html",
"layouts/taxonomy/taxonomy.html",
"layouts/taxonomy/list.html",
"layouts/category/category.terms.html.html",
"layouts/category/terms.html.html",
"layouts/category/term.html.html",
"layouts/category/category.html.html",
"layouts/category/taxonomy.html.html",
"layouts/category/list.html.html",
"layouts/category/category.terms.html",
"layouts/category/terms.html",
"layouts/category/term.html",
"layouts/category/category.html",
"layouts/category/taxonomy.html",
"layouts/category/list.html",
"layouts/_default/category.terms.html.html",
"layouts/_default/terms.html.html",
"layouts/_default/term.html.html",
"layouts/_default/category.html.html",
"layouts/_default/taxonomy.html.html",
"layouts/_default/list.html.html",
"layouts/_default/category.terms.html",
"layouts/_default/terms.html",
"layouts/_default/term.html",
"layouts/_default/category.html",
"layouts/_default/taxonomy.html",
"layouts/_default/list.html"
]
}
@ -3011,6 +3099,23 @@
}
},
"crypto": {
"HMAC": {
"Description": "HMAC returns a cryptographic hash that uses a key to sign a message.",
"Args": [
"h",
"k",
"m"
],
"Aliases": [
"hmac"
],
"Examples": [
[
"{{ hmac \"sha256\" \"Secret key\" \"Hello world, gophers!\" }}",
"b6d11b6c53830b9d87036272ca9fe9d19306b8f9d8aa07b15da27d89e6e34f40"
]
]
},
"MD5": {
"Description": "MD5 hashes the given input and returns its MD5 checksum.",
"Args": [
@ -3059,23 +3164,6 @@
"6ec43b78da9669f50e4e422575c54bf87536954ccd58280219c393f2ce352b46"
]
]
},
"HMAC": {
"Description": "HMAC hashes the concatenation of a message and a secret key with the given hash function and returns its checksum.",
"Args": [
"hash function",
"message",
"key"
],
"Aliases": [
"hmac"
],
"Examples": [
[
"{{ hmac \"sha256\" \"Hello Gopher!\" \"Hello world, gophers!\" }}",
"32aea97d5688891fb35175c5518012323a3079994b909dd6f1bc481e4d0e7ce9"
]
]
}
},
"data": {
@ -3588,6 +3676,22 @@
]
]
},
"Pow": {
"Description": "Pow returns a raised to the power of b.",
"Args": [
"a",
"b"
],
"Aliases": [
"pow"
],
"Examples": [
[
"{{math.Pow 2 3}}",
"8"
]
]
},
"Round": {
"Description": "Round returns the nearest integer, rounding half away from zero.",
"Args": [
@ -3819,6 +3923,16 @@
}
},
"resources": {
"Babel": {
"Description": "Babel processes the given Resource with Babel.",
"Args": [
"args"
],
"Aliases": [
"babel"
],
"Examples": []
},
"Concat": {
"Description": "",
"Args": null,

View File

@ -0,0 +1,14 @@
<div class="code">
<pre><code>
├── blog
│   ├── _index.md [section]
│   ├── first-post.md [page]
│   └── second-post
│   ├── index.md [page bundle]
│   └── photo.jpg [page resource]
└── tags
├── _index.md [taxonomy]
└── funny
└── _index.md [term]
</code></pre>
</div>

View File

@ -0,0 +1,7 @@
| Kind | Description | Example |
|----------------|--------------------------------------------------------------------|-------------------------------------------------------------------------------|
| `home` | The landing page for the home page | `/index.html` |
| `page` | The landing page for a given page | `my-post` page (`/posts/my-post/index.html`) |
| `section` | The landing page of a given section | `posts` section (`/posts/index.html`) |
| `taxonomy` | The landing page for a taxonomy | `tags` taxonomy (`/tags/index.html`) |
| `term ` | The landing page for one taxonomy's term | term `awesome` in `tags` taxonomy (`/tags/awesome/index.html`) |

View File

@ -0,0 +1,141 @@
// Copyright 2020 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.
// You may obtain a copy of the License at
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
package hugolib
import (
"fmt"
"testing"
qt "github.com/frankban/quicktest"
)
func Test073(t *testing.T) {
asertDisabledTaxonomyAndTerm := func(b *sitesBuilder, taxonomy, term bool) {
b.Assert(b.CheckExists("public/tags/index.html"), qt.Equals, taxonomy)
b.Assert(b.CheckExists("public/tags/tag1/index.html"), qt.Equals, term)
}
assertOutputTaxonomyAndTerm := func(b *sitesBuilder, taxonomy, term bool) {
b.Assert(b.CheckExists("public/tags/index.json"), qt.Equals, taxonomy)
b.Assert(b.CheckExists("public/tags/tag1/index.json"), qt.Equals, term)
}
for _, this := range []struct {
name string
config string
assert func(err error, out string, b *sitesBuilder)
}{
{
"Outputs for both taxonomy and taxonomyTerm",
`[outputs]
taxonomy = ["JSON"]
taxonomyTerm = ["JSON"]
`,
func(err error, out string, b *sitesBuilder) {
b.Assert(err, qt.IsNil)
assertOutputTaxonomyAndTerm(b, true, true)
},
},
{
"Outputs for taxonomyTerm",
`[outputs]
taxonomyTerm = ["JSON"]
`,
func(err error, out string, b *sitesBuilder) {
b.Assert(err, qt.IsNil)
assertOutputTaxonomyAndTerm(b, true, false)
},
},
{
"Outputs for taxonomy only",
`[outputs]
taxonomy = ["JSON"]
`,
func(err error, out string, b *sitesBuilder) {
b.Assert(err, qt.Not(qt.IsNil))
b.Assert(out, qt.Contains, `ignoreErrors = ["error-output-taxonomy"]`)
},
},
{
"Outputs for taxonomy only, ignore error",
`
ignoreErrors = ["error-output-taxonomy"]
[outputs]
taxonomy = ["JSON"]
`,
func(err error, out string, b *sitesBuilder) {
b.Assert(err, qt.IsNil)
assertOutputTaxonomyAndTerm(b, true, false)
},
},
{
"Disable both taxonomy and taxonomyTerm",
`disableKinds = ["taxonomy", "taxonomyTerm"]`,
func(err error, out string, b *sitesBuilder) {
b.Assert(err, qt.IsNil)
asertDisabledTaxonomyAndTerm(b, false, false)
},
},
{
"Disable only taxonomyTerm",
`disableKinds = ["taxonomyTerm"]`,
func(err error, out string, b *sitesBuilder) {
b.Assert(err, qt.IsNil)
asertDisabledTaxonomyAndTerm(b, false, true)
},
},
{
"Disable only taxonomy",
`disableKinds = ["taxonomy"]`,
func(err error, out string, b *sitesBuilder) {
b.Assert(err, qt.Not(qt.IsNil))
b.Assert(out, qt.Contains, `ignoreErrors = ["error-disable-taxonomy"]`)
},
},
{
"Disable only taxonomy, ignore error",
`disableKinds = ["taxonomy"]
ignoreErrors = ["error-disable-taxonomy"]`,
func(err error, out string, b *sitesBuilder) {
b.Assert(err, qt.IsNil)
asertDisabledTaxonomyAndTerm(b, false, true)
},
},
} {
t.Run(this.name, func(t *testing.T) {
b := newTestSitesBuilder(t).WithConfigFile("toml", this.config)
b.WithTemplatesAdded("_default/list.json", "JSON")
out, err := captureStdout(func() error {
return b.BuildE(BuildCfg{})
})
fmt.Println(out)
this.assert(err, out, b)
})
}
}

View File

@ -61,13 +61,13 @@ func TestCascade(t *testing.T) {
b.Build(BuildCfg{})
b.AssertFileContent("public/index.html", `
12|taxonomy|categories/cool/_index.md|Cascade Category|cat.png|categories|HTML-|
12|taxonomy|categories/catsect1|catsect1|cat.png|categories|HTML-|
12|taxonomy|categories/funny|funny|cat.png|categories|HTML-|
12|taxonomyTerm|categories/_index.md|My Categories|cat.png|categories|HTML-|
32|taxonomy|categories/sad/_index.md|Cascade Category|sad.png|categories|HTML-|
42|taxonomy|tags/blue|blue|home.png|tags|HTML-|
42|taxonomyTerm|tags|Cascade Home|home.png|tags|HTML-|
12|term|categories/cool/_index.md|Cascade Category|cat.png|categories|HTML-|
12|term|categories/catsect1|catsect1|cat.png|categories|HTML-|
12|term|categories/funny|funny|cat.png|categories|HTML-|
12|taxonomy|categories/_index.md|My Categories|cat.png|categories|HTML-|
32|term|categories/sad/_index.md|Cascade Category|sad.png|categories|HTML-|
42|term|tags/blue|blue|home.png|tags|HTML-|
42|taxonomy|tags|Cascade Home|home.png|tags|HTML-|
42|section|sectnocontent|Cascade Home|home.png|sectnocontent|HTML-|
42|section|sect3|Cascade Home|home.png|sect3|HTML-|
42|page|bundle1/index.md|Cascade Home|home.png|page|HTML-|
@ -77,7 +77,7 @@ func TestCascade(t *testing.T) {
42|page|sect3/p1.md|Cascade Home|home.png|sect3|HTML-|
42|page|sectnocontent/p1.md|Cascade Home|home.png|sectnocontent|HTML-|
42|section|sectnofrontmatter/_index.md|Cascade Home|home.png|sectnofrontmatter|HTML-|
42|taxonomy|tags/green|green|home.png|tags|HTML-|
42|term|tags/green|green|home.png|tags|HTML-|
42|home|_index.md|Home|home.png|page|HTML-|
42|page|p1.md|p1|home.png|page|HTML-|
42|section|sect1/_index.md|Sect1|sect1.png|stype|HTML-|

View File

@ -274,13 +274,13 @@ type contentBundleViewInfo struct {
func (c *contentBundleViewInfo) kind() string {
if c.termKey != "" {
return page.KindTaxonomy
return page.KindTerm
}
return page.KindTaxonomyTerm
return page.KindTaxonomy
}
func (c *contentBundleViewInfo) sections() []string {
if c.kind() == page.KindTaxonomyTerm {
if c.kind() == page.KindTaxonomy {
return []string{c.name.plural}
}

View File

@ -106,7 +106,7 @@ func (m *pageMap) newPageFromContentNode(n *contentNode, parentBucket *pagesMapB
sections := s.sectionsFromFile(f)
kind := s.kindFromFileInfoOrSections(f, sections)
if kind == page.KindTaxonomy {
if kind == page.KindTerm {
s.PathSpec.MakePathsSanitized(sections)
}
@ -535,7 +535,7 @@ func (m *pageMap) assembleTaxonomies() error {
}
} else {
title := ""
if kind == page.KindTaxonomy {
if kind == page.KindTerm {
title = n.viewInfo.term()
}
n.p = m.s.newPage(n, parent.p.bucket, kind, title, sections...)

View File

@ -451,8 +451,8 @@ Draft5: {{ if (.Site.GetPage "blog/draftsection/sub/page") }}FOUND{{ end }}|
Pages: /blog/page3/|/blog/subsection/|/blog/page2/|/blog/page1/|/blog/bundle/|
Sections: /blog/|/docs/|
Categories: /categories/funny/; funny; 11|
Category Terms: taxonomyTerm: /categories/funny/; funny; 11|
Category Funny: taxonomy; funny: /blog/subsection/page4/;|/blog/page3/;|/blog/subsection/;|/blog/page2/;|/blog/page1/;|/blog/subsection/page5/;|/docs/page6/;|/blog/bundle/;|;|
Category Terms: taxonomy: /categories/funny/; funny; 11|
Category Funny: term; funny: /blog/subsection/page4/;|/blog/page3/;|/blog/subsection/;|/blog/page2/;|/blog/page1/;|/blog/subsection/page5/;|/docs/page6/;|/blog/bundle/;|;|
Pag Num Pages: 7
Pag Blog Num Pages: 4
Blog Num RegularPages: 4

View File

@ -28,6 +28,7 @@ func TestDisable(t *testing.T) {
config := fmt.Sprintf(`
baseURL = "http://example.com/blog"
enableRobotsTXT = true
ignoreErrors = ["error-disable-taxonomy"]
disableKinds = [%q]
`, disableKind)
@ -141,7 +142,7 @@ title: Headless Local Lists Sub
b.Assert(len(s.Taxonomies()["categories"]), qt.Equals, 0)
})
disableKind = page.KindTaxonomy
disableKind = page.KindTerm
c.Run("Disable "+disableKind, func(c *qt.C) {
b := newSitesBuilder(c, disableKind)
b.Build(BuildCfg{})
@ -153,7 +154,7 @@ title: Headless Local Lists Sub
b.Assert(getPage(b, "/categories/mycat"), qt.IsNil)
})
disableKind = page.KindTaxonomyTerm
disableKind = page.KindTaxonomy
c.Run("Disable "+disableKind, func(c *qt.C) {
b := newSitesBuilder(c, disableKind)
b.Build(BuildCfg{})
@ -319,7 +320,7 @@ title: Headless Local Lists Sub
// https://github.com/gohugoio/hugo/issues/6897#issuecomment-587947078
func TestDisableRSSWithRSSInCustomOutputs(t *testing.T) {
b := newTestSitesBuilder(t).WithConfigFile("toml", `
disableKinds = ["taxonomy", "taxonomyTerm", "RSS"]
disableKinds = ["term", "taxonomy", "RSS"]
[outputs]
home = [ "HTML", "RSS" ]
`).Build(BuildCfg{})

View File

@ -443,8 +443,8 @@ func applyDeps(cfg deps.DepsCfg, sites ...*Site) error {
contentMap: newContentMap(contentMapConfig{
lang: s.Lang(),
taxonomyConfig: s.siteCfg.taxonomiesConfig.Values(),
taxonomyDisabled: !s.isEnabled(page.KindTaxonomy),
taxonomyTermDisabled: !s.isEnabled(page.KindTaxonomyTerm),
taxonomyDisabled: !s.isEnabled(page.KindTerm),
taxonomyTermDisabled: !s.isEnabled(page.KindTaxonomy),
pageDisabled: !s.isEnabled(page.KindPage),
}),
s: s,
@ -493,6 +493,9 @@ func applyDeps(cfg deps.DepsCfg, sites ...*Site) error {
// NewHugoSites creates HugoSites from the given config.
func NewHugoSites(cfg deps.DepsCfg) (*HugoSites, error) {
if cfg.Logger == nil {
cfg.Logger = loggers.NewErrorLogger()
}
sites, err := createSitesFromConfig(cfg)
if err != nil {
return nil, errors.Wrap(err, "from config")

View File

@ -339,14 +339,14 @@ func doTestMultiSitesBuild(t *testing.T, configTemplate, configSuffix string) {
nnSite := sites[2]
c.Assert(nnSite.language.Lang, qt.Equals, "nn")
taxNn := nnSite.getPage(page.KindTaxonomyTerm, "lag")
taxNn := nnSite.getPage(page.KindTaxonomy, "lag")
c.Assert(taxNn, qt.Not(qt.IsNil))
c.Assert(len(taxNn.Translations()), qt.Equals, 1)
c.Assert(taxNn.Translations()[0].Language().Lang, qt.Equals, "nb")
taxTermNn := nnSite.getPage(page.KindTaxonomy, "lag", "sogndal")
taxTermNn := nnSite.getPage(page.KindTerm, "lag", "sogndal")
c.Assert(taxTermNn, qt.Not(qt.IsNil))
c.Assert(nnSite.getPage(page.KindTaxonomy, "LAG", "SOGNDAL"), qt.Equals, taxTermNn)
c.Assert(nnSite.getPage(page.KindTerm, "LAG", "SOGNDAL"), qt.Equals, taxTermNn)
c.Assert(len(taxTermNn.Translations()), qt.Equals, 1)
c.Assert(taxTermNn.Translations()[0].Language().Lang, qt.Equals, "nb")

View File

@ -27,7 +27,7 @@ func TestHello(t *testing.T) {
b := newTestSitesBuilder(t)
b.WithConfigFile("toml", `
baseURL="https://example.org"
disableKinds = ["taxonomy", "taxonomyTerm", "section", "page"]
disableKinds = ["term", "taxonomy", "section", "page"]
`)
b.WithContent("p1", `
---

View File

@ -212,9 +212,9 @@ func (p *pageState) RegularPages() page.Pages {
switch p.Kind() {
case page.KindPage:
case page.KindSection, page.KindHome, page.KindTaxonomyTerm:
case page.KindSection, page.KindHome, page.KindTaxonomy:
pages = p.getPages()
case page.KindTaxonomy:
case page.KindTerm:
all := p.Pages()
for _, p := range all {
if p.IsPage() {
@ -240,9 +240,9 @@ func (p *pageState) Pages() page.Pages {
case page.KindPage:
case page.KindSection, page.KindHome:
pages = p.getPagesAndSections()
case page.KindTaxonomy:
case page.KindTerm:
pages = p.bucket.getTaxonomyEntries()
case page.KindTaxonomyTerm:
case page.KindTaxonomy:
pages = p.bucket.getTaxonomies()
default:
pages = p.s.Pages()
@ -436,7 +436,7 @@ func (p *pageState) getLayoutDescriptor() output.LayoutDescriptor {
if len(sections) > 0 {
section = sections[0]
}
case page.KindTaxonomyTerm, page.KindTaxonomy:
case page.KindTaxonomy, page.KindTerm:
b := p.getTreeRef().n
section = b.viewInfo.name.singular
default:

View File

@ -35,7 +35,7 @@ func (p *pageData) Data() interface{} {
}
switch p.Kind() {
case page.KindTaxonomy:
case page.KindTerm:
b := p.treeRef.n
name := b.viewInfo.name
termKey := b.viewInfo.termKey
@ -46,7 +46,7 @@ func (p *pageData) Data() interface{} {
p.data["Singular"] = name.singular
p.data["Plural"] = name.plural
p.data["Term"] = b.viewInfo.term()
case page.KindTaxonomyTerm:
case page.KindTaxonomy:
b := p.treeRef.n
name := b.viewInfo.name

View File

@ -52,7 +52,7 @@ type pageMeta struct {
// in the different page collections. This can, as an example, be used
// to to filter regular pages, find sections etc.
// Kind will, for the pages available to the templates, be one of:
// page, home, section, taxonomy and taxonomyTerm.
// page, home, section, taxonomy and term.
// It is of string type to make it easy to reason about in
// the templates.
kind string
@ -678,11 +678,11 @@ func (p *pageMeta) applyDefaultValues(n *contentNode) error {
} else {
p.title = sectionName
}
case page.KindTaxonomy:
case page.KindTerm:
// TODO(bep) improve
key := p.sections[len(p.sections)-1]
p.title = strings.Replace(p.s.titleFunc(key), "-", " ", -1)
case page.KindTaxonomyTerm:
case page.KindTaxonomy:
p.title = p.s.titleFunc(p.sections[0])
case kind404:
p.title = "404 Page not found"

View File

@ -89,7 +89,7 @@ func (p *pagePaginator) Paginator(options ...interface{}) (*page.Pager, error) {
// section. To avoid the default paginators for the home page
// changing in the wild, we make this a special case.
pages = p.source.s.RegularPages()
case page.KindTaxonomy, page.KindTaxonomyTerm:
case page.KindTerm, page.KindTaxonomy:
pages = p.source.Pages()
default:
pages = p.source.RegularPages()

View File

@ -147,7 +147,7 @@ func createTargetPathDescriptor(s *Site, p page.Page, pm *pageMeta) (page.Target
// the permalink configuration values are likely to be redundant, e.g.
// naively expanding /category/:slug/ would give /category/categories/ for
// the "categories" page.KindTaxonomyTerm.
if p.Kind() == page.KindPage || p.Kind() == page.KindTaxonomy {
if p.Kind() == page.KindPage || p.Kind() == page.KindTerm {
opath, err := d.ResourceSpec.Permalinks.Expand(p.Section(), p)
if err != nil {
return desc, err

View File

@ -171,7 +171,7 @@ func (pt pageTree) Parent() page.Page {
tree := p.getTreeRef()
if tree == nil || pt.p.Kind() == page.KindTaxonomyTerm {
if tree == nil || pt.p.Kind() == page.KindTaxonomy {
return pt.p.s.home
}

View File

@ -22,7 +22,7 @@ import (
var (
// This is all the kinds we can expect to find in .Site.Pages.
allKindsInPages = []string{page.KindPage, page.KindHome, page.KindSection, page.KindTaxonomy, page.KindTaxonomyTerm}
allKindsInPages = []string{page.KindPage, page.KindHome, page.KindSection, page.KindTerm, page.KindTaxonomy}
)
const (

View File

@ -1145,7 +1145,7 @@ func TestPageBundlerPartialTranslations(t *testing.T) {
baseURL = "https://example.org"
defaultContentLanguage = "en"
defaultContentLanguageInSubDir = true
disableKinds = ["taxonomyTerm", "taxonomy"]
disableKinds = ["taxonomy", "term"]
[languages]
[languages.nn]
languageName = "Nynorsk"

View File

@ -279,8 +279,8 @@ func TestGetPage(t *testing.T) {
{"Abs, ignore context, page deep", "NoPage", sec3, []string{"/subsect/deep.md"}, ""},
// Taxonomies
{"Taxonomy term", page.KindTaxonomyTerm, nil, []string{"categories"}, "Categories"},
{"Taxonomy", page.KindTaxonomy, nil, []string{"categories/hugo", "categories/Hugo"}, "Hugo"},
{"Taxonomy term", page.KindTaxonomy, nil, []string{"categories"}, "Categories"},
{"Taxonomy", page.KindTerm, nil, []string{"categories/hugo", "categories/Hugo"}, "Hugo"},
// Bundle variants
{"Bundle regular", page.KindPage, nil, []string{"sect3/b1", "sect3/b1/index.md", "sect3/b1/index.en.md"}, "b1 bundle"},

View File

@ -82,7 +82,7 @@ class Car {
v := viper.New()
v.Set("workingDir", workDir)
v.Set("disableKinds", []string{"taxonomyTerm", "taxonomy", "page"})
v.Set("disableKinds", []string{"taxonomy", "term", "page"})
b := newTestSitesBuilder(t).WithLogger(loggers.NewWarningLogger())
// Need to use OS fs for this.

View File

@ -895,7 +895,7 @@ h1 {
newTestBuilder := func(v *viper.Viper) *sitesBuilder {
v.Set("workingDir", workDir)
v.Set("disableKinds", []string{"taxonomyTerm", "taxonomy", "page"})
v.Set("disableKinds", []string{"taxonomy", "term", "page"})
b := newTestSitesBuilder(t).WithLogger(loggers.NewWarningLogger())
// Need to use OS fs for this.
b.Fs = hugofs.NewDefault(v)

View File

@ -626,7 +626,7 @@ baseURL = "http://example.com/blog"
paginate = 1
disableKinds = ["section", "taxonomy", "taxonomyTerm", "RSS", "sitemap", "robotsTXT", "404"]
disableKinds = ["section", "term", "taxonomy", "RSS", "sitemap", "robotsTXT", "404"]
[outputs]
home = [ "HTML", "AMP", "Calendar" ]

View File

@ -28,6 +28,10 @@ import (
"strings"
"time"
"github.com/gohugoio/hugo/common/constants"
"github.com/gohugoio/hugo/common/loggers"
"github.com/gohugoio/hugo/resources"
"github.com/gohugoio/hugo/identity"
@ -397,12 +401,34 @@ func newSite(cfg deps.DepsCfg) (*Site, error) {
if cfg.Language == nil {
cfg.Language = langs.NewDefaultLanguage(cfg.Cfg)
}
if cfg.Logger == nil {
panic("logger must be set")
}
ignoreErrors := cast.ToStringSlice(cfg.Language.Get("ignoreErrors"))
ignorableLogger := loggers.NewIgnorableLogger(cfg.Logger, ignoreErrors...)
disabledKinds := make(map[string]bool)
for _, disabled := range cast.ToStringSlice(cfg.Language.Get("disableKinds")) {
disabledKinds[disabled] = true
}
if disabledKinds["taxonomyTerm"] {
// Correct from the value it had before Hugo 0.73.0.
if disabledKinds[page.KindTaxonomy] {
disabledKinds[page.KindTerm] = true
} else {
disabledKinds[page.KindTaxonomy] = true
}
delete(disabledKinds, "taxonomyTerm")
} else if disabledKinds[page.KindTaxonomy] && !disabledKinds[page.KindTerm] {
// This is a potentially ambigous situation. It may be correct.
ignorableLogger.Errorf(constants.ErrIDAmbigousDisableKindTaxonomy, `You have the value 'taxonomy' in the disabledKinds list. In Hugo 0.73.0 we fixed these to be what most people expect (taxonomy and term).
But this also means that your site configuration may not do what you expect. If it is correct, you can suppress this message by following the instructions below.`)
}
var (
mediaTypesConfig []map[string]interface{}
outputFormatsConfig []map[string]interface{}
@ -444,7 +470,30 @@ func newSite(cfg deps.DepsCfg) (*Site, error) {
siteOutputFormatsConfig = tmp
}
outputFormats, err := createSiteOutputFormats(siteOutputFormatsConfig, cfg.Language, rssDisabled)
var siteOutputs map[string]interface{}
if cfg.Language.IsSet("outputs") {
siteOutputs = cfg.Language.GetStringMap("outputs")
// Check and correct taxonomy kinds vs pre Hugo 0.73.0.
v1, hasTaxonomyTerm := siteOutputs["taxonomyterm"]
v2, hasTaxonomy := siteOutputs[page.KindTaxonomy]
_, hasTerm := siteOutputs[page.KindTerm]
if hasTaxonomy && hasTaxonomyTerm {
siteOutputs[page.KindTaxonomy] = v1
siteOutputs[page.KindTerm] = v2
delete(siteOutputs, "taxonomyTerm")
} else if hasTaxonomy && !hasTerm {
// This is a potentially ambigous situation. It may be correct.
ignorableLogger.Errorf(constants.ErrIDAmbigousOutputKindTaxonomy, `You have configured output formats for 'taxonomy' in your site configuration. In Hugo 0.73.0 we fixed these to be what most people expect (taxonomy and term).
But this also means that your site configuration may not do what you expect. If it is correct, you can suppress this message by following the instructions below.`)
}
if !hasTaxonomy && hasTaxonomyTerm {
siteOutputs[page.KindTaxonomy] = v1
delete(siteOutputs, "taxonomyterm")
}
}
outputFormats, err := createSiteOutputFormats(siteOutputFormatsConfig, siteOutputs, rssDisabled)
if err != nil {
return nil, err
}
@ -1708,11 +1757,11 @@ func (s *Site) kindFromSections(sections []string) string {
func (s *Site) kindFromSectionPath(sectionPath string) string {
for _, plural := range s.siteCfg.taxonomiesConfig {
if plural == sectionPath {
return page.KindTaxonomyTerm
return page.KindTaxonomy
}
if strings.HasPrefix(sectionPath, plural) {
return page.KindTaxonomy
return page.KindTerm
}
}

View File

@ -17,13 +17,12 @@ import (
"fmt"
"strings"
"github.com/gohugoio/hugo/config"
"github.com/gohugoio/hugo/output"
"github.com/gohugoio/hugo/resources/page"
"github.com/spf13/cast"
)
func createDefaultOutputFormats(allFormats output.Formats, cfg config.Provider) map[string]output.Formats {
func createDefaultOutputFormats(allFormats output.Formats) map[string]output.Formats {
rssOut, rssFound := allFormats.GetByName(output.RSSFormat.Name)
htmlOut, _ := allFormats.GetByName(output.HTMLFormat.Name)
robotsOut, _ := allFormats.GetByName(output.RobotsTxtFormat.Name)
@ -35,11 +34,11 @@ func createDefaultOutputFormats(allFormats output.Formats, cfg config.Provider)
}
m := map[string]output.Formats{
page.KindPage: {htmlOut},
page.KindHome: defaultListTypes,
page.KindSection: defaultListTypes,
page.KindTaxonomy: defaultListTypes,
page.KindTaxonomyTerm: defaultListTypes,
page.KindPage: {htmlOut},
page.KindHome: defaultListTypes,
page.KindSection: defaultListTypes,
page.KindTerm: defaultListTypes,
page.KindTaxonomy: defaultListTypes,
// Below are for consistency. They are currently not used during rendering.
kindSitemap: {sitemapOut},
kindRobotsTXT: {robotsOut},
@ -55,17 +54,15 @@ func createDefaultOutputFormats(allFormats output.Formats, cfg config.Provider)
}
func createSiteOutputFormats(allFormats output.Formats, cfg config.Provider, rssDisabled bool) (map[string]output.Formats, error) {
defaultOutputFormats := createDefaultOutputFormats(allFormats, cfg)
func createSiteOutputFormats(allFormats output.Formats, outputs map[string]interface{}, rssDisabled bool) (map[string]output.Formats, error) {
defaultOutputFormats := createDefaultOutputFormats(allFormats)
if !cfg.IsSet("outputs") {
if outputs == nil {
return defaultOutputFormats, nil
}
outFormats := make(map[string]output.Formats)
outputs := cfg.GetStringMap("outputs")
if len(outputs) == 0 {
return outFormats, nil
}

View File

@ -49,7 +49,7 @@ baseURL = "http://example.com/blog"
paginate = 1
defaultContentLanguage = "en"
disableKinds = ["section", "taxonomy", "taxonomyTerm", "RSS", "sitemap", "robotsTXT", "404"]
disableKinds = ["section", "term", "taxonomy", "RSS", "sitemap", "robotsTXT", "404"]
[Taxonomies]
tag = "tags"
@ -226,7 +226,7 @@ baseURL = "http://example.com/blog"
paginate = 1
defaultContentLanguage = "en"
disableKinds = ["page", "section", "taxonomy", "taxonomyTerm", "sitemap", "robotsTXT", "404"]
disableKinds = ["page", "section", "term", "taxonomy", "sitemap", "robotsTXT", "404"]
[outputFormats]
[outputFormats.RSS]
@ -263,7 +263,7 @@ baseURL = "http://example.com/blog"
paginate = 1
defaultContentLanguage = "en"
disableKinds = ["page", "section", "taxonomy", "taxonomyTerm", "sitemap", "robotsTXT", "404"]
disableKinds = ["page", "section", "term", "taxonomy", "sitemap", "robotsTXT", "404"]
[mediaTypes]
[mediaTypes."text/nodot"]
@ -341,14 +341,14 @@ func TestCreateSiteOutputFormats(t *testing.T) {
cfg := viper.New()
cfg.Set("outputs", outputsConfig)
outputs, err := createSiteOutputFormats(output.DefaultFormats, cfg, false)
outputs, err := createSiteOutputFormats(output.DefaultFormats, cfg.GetStringMap("outputs"), false)
c.Assert(err, qt.IsNil)
c.Assert(outputs[page.KindSection], deepEqualsOutputFormats, output.Formats{output.JSONFormat})
c.Assert(outputs[page.KindHome], deepEqualsOutputFormats, output.Formats{output.HTMLFormat, output.JSONFormat})
// Defaults
c.Assert(outputs[page.KindTerm], deepEqualsOutputFormats, output.Formats{output.HTMLFormat, output.RSSFormat})
c.Assert(outputs[page.KindTaxonomy], deepEqualsOutputFormats, output.Formats{output.HTMLFormat, output.RSSFormat})
c.Assert(outputs[page.KindTaxonomyTerm], deepEqualsOutputFormats, output.Formats{output.HTMLFormat, output.RSSFormat})
c.Assert(outputs[page.KindPage], deepEqualsOutputFormats, output.Formats{output.HTMLFormat})
// These aren't (currently) in use when rendering in Hugo,
@ -367,13 +367,15 @@ func TestCreateSiteOutputFormats(t *testing.T) {
cfg := viper.New()
outputsConfig := map[string]interface{}{
// Note that we in Hugo 0.53.0 renamed this Kind to "taxonomy",
// but keep this test to test the legacy mapping.
"taxonomyterm": []string{"JSON"},
}
cfg.Set("outputs", outputsConfig)
outputs, err := createSiteOutputFormats(output.DefaultFormats, cfg, false)
outputs, err := createSiteOutputFormats(output.DefaultFormats, cfg.GetStringMap("outputs"), false)
c.Assert(err, qt.IsNil)
c.Assert(outputs[page.KindTaxonomyTerm], deepEqualsOutputFormats, output.Formats{output.JSONFormat})
c.Assert(outputs[page.KindTaxonomy], deepEqualsOutputFormats, output.Formats{output.JSONFormat})
})
@ -389,7 +391,7 @@ func TestCreateSiteOutputFormatsInvalidConfig(t *testing.T) {
cfg := viper.New()
cfg.Set("outputs", outputsConfig)
_, err := createSiteOutputFormats(output.DefaultFormats, cfg, false)
_, err := createSiteOutputFormats(output.DefaultFormats, cfg.GetStringMap("outputs"), false)
c.Assert(err, qt.Not(qt.IsNil))
}
@ -403,7 +405,7 @@ func TestCreateSiteOutputFormatsEmptyConfig(t *testing.T) {
cfg := viper.New()
cfg.Set("outputs", outputsConfig)
outputs, err := createSiteOutputFormats(output.DefaultFormats, cfg, false)
outputs, err := createSiteOutputFormats(output.DefaultFormats, cfg.GetStringMap("outputs"), false)
c.Assert(err, qt.IsNil)
c.Assert(outputs[page.KindHome], deepEqualsOutputFormats, output.Formats{output.HTMLFormat, output.RSSFormat})
}
@ -423,7 +425,7 @@ func TestCreateSiteOutputFormatsCustomFormats(t *testing.T) {
customHTML = output.Format{Name: "HTML", BaseName: "customHTML"}
)
outputs, err := createSiteOutputFormats(output.Formats{customRSS, customHTML}, cfg, false)
outputs, err := createSiteOutputFormats(output.Formats{customRSS, customHTML}, cfg.GetStringMap("outputs"), false)
c.Assert(err, qt.IsNil)
c.Assert(outputs[page.KindHome], deepEqualsOutputFormats, output.Formats{customHTML, customRSS})
}

View File

@ -1066,7 +1066,7 @@ func TestClassCollectorStress(t *testing.T) {
b := newTestSitesBuilder(t)
b.WithConfigFile("toml", `
disableKinds = ["home", "section", "taxonomy", "taxonomyTerm" ]
disableKinds = ["home", "section", "term", "taxonomy" ]
[languages]
[languages.en]

View File

@ -167,16 +167,16 @@ permalinkeds:
for taxonomy, count := range taxonomyTermPageCounts {
msg := qt.Commentf(taxonomy)
term := s.getPage(page.KindTaxonomyTerm, taxonomy)
term := s.getPage(page.KindTaxonomy, taxonomy)
b.Assert(term, qt.Not(qt.IsNil), msg)
b.Assert(len(term.Pages()), qt.Equals, count, msg)
for _, p := range term.Pages() {
b.Assert(p.Kind(), qt.Equals, page.KindTaxonomy)
b.Assert(p.Kind(), qt.Equals, page.KindTerm)
}
}
cat1 := s.getPage(page.KindTaxonomy, "categories", "cat1")
cat1 := s.getPage(page.KindTerm, "categories", "cat1")
b.Assert(cat1, qt.Not(qt.IsNil))
if uglyURLs {
b.Assert(cat1.RelPermalink(), qt.Equals, "/blog/categories/cat1.html")
@ -184,8 +184,8 @@ permalinkeds:
b.Assert(cat1.RelPermalink(), qt.Equals, "/blog/categories/cat1/")
}
pl1 := s.getPage(page.KindTaxonomy, "permalinkeds", "pl1")
permalinkeds := s.getPage(page.KindTaxonomyTerm, "permalinkeds")
pl1 := s.getPage(page.KindTerm, "permalinkeds", "pl1")
permalinkeds := s.getPage(page.KindTaxonomy, "permalinkeds")
b.Assert(pl1, qt.Not(qt.IsNil))
b.Assert(permalinkeds, qt.Not(qt.IsNil))
if uglyURLs {
@ -196,7 +196,7 @@ permalinkeds:
b.Assert(permalinkeds.RelPermalink(), qt.Equals, "/blog/permalinkeds/")
}
helloWorld := s.getPage(page.KindTaxonomy, "others", "hello-hugo-world")
helloWorld := s.getPage(page.KindTerm, "others", "hello-hugo-world")
b.Assert(helloWorld, qt.Not(qt.IsNil))
b.Assert(helloWorld.Title(), qt.Equals, "Hello Hugo world")
@ -269,8 +269,8 @@ title: "This is S3s"
return pages
}
ta := filterbyKind(page.KindTaxonomy)
te := filterbyKind(page.KindTaxonomyTerm)
ta := filterbyKind(page.KindTerm)
te := filterbyKind(page.KindTaxonomy)
b.Assert(len(te), qt.Equals, 4)
b.Assert(len(ta), qt.Equals, 7)
@ -637,7 +637,7 @@ Cats Paginator {{ range $cats.Paginator.Pages }}{{ .RelPermalink }}|{{ end }}:EN
b.Assert(funny, qt.Not(qt.IsNil))
b.Assert(cat.Parent().IsHome(), qt.Equals, true)
b.Assert(funny.Kind(), qt.Equals, "taxonomy")
b.Assert(funny.Kind(), qt.Equals, "term")
b.Assert(funny.Parent(), qt.Equals, cat)
b.AssertFileContent("public/index.html", `
@ -697,13 +697,13 @@ abcdefgs: {{ template "print-page" $abcdefgs }}|IsAncestor: {{ $abcdefgs.IsAnces
Page: /abcdefgh/|abcdefgh|section|Parent: /|CurrentSection: /abcdefgh/|
Page: /abcdefgh/p1/|abcdefgh-p|page|Parent: /abcdefgh/|CurrentSection: /abcdefgh/|
Page: /abcdefghijk/|abcdefghijk|page|Parent: /|CurrentSection: /|
Page: /abcdefghis/|Abcdefghis|taxonomyTerm|Parent: /|CurrentSection: /|
Page: /abcdefgs/|Abcdefgs|taxonomyTerm|Parent: /|CurrentSection: /|
Page: /abcdefs/|Abcdefs|taxonomyTerm|Parent: /|CurrentSection: /|
abc: /abcdefgs/abc/|abc|taxonomy|Parent: /abcdefgs/|CurrentSection: /abcdefgs/|
abcdefgs: /abcdefgs/|Abcdefgs|taxonomyTerm|Parent: /|CurrentSection: /|
abc: /abcdefgs/abc/|abc|taxonomy|Parent: /abcdefgs/|CurrentSection: /abcdefgs/|FirstSection: /|IsAncestor: false|IsDescendant: true
abcdefgs: /abcdefgs/|Abcdefgs|taxonomyTerm|Parent: /|CurrentSection: /|FirstSection: /|IsAncestor: true|IsDescendant: false
Page: /abcdefghis/|Abcdefghis|taxonomy|Parent: /|CurrentSection: /|
Page: /abcdefgs/|Abcdefgs|taxonomy|Parent: /|CurrentSection: /|
Page: /abcdefs/|Abcdefs|taxonomy|Parent: /|CurrentSection: /|
abc: /abcdefgs/abc/|abc|term|Parent: /abcdefgs/|CurrentSection: /abcdefgs/|
abcdefgs: /abcdefgs/|Abcdefgs|taxonomy|Parent: /|CurrentSection: /|
abc: /abcdefgs/abc/|abc|term|Parent: /abcdefgs/|CurrentSection: /abcdefgs/|FirstSection: /|IsAncestor: false|IsDescendant: true
abcdefgs: /abcdefgs/|Abcdefgs|taxonomy|Parent: /|CurrentSection: /|FirstSection: /|IsAncestor: true|IsDescendant: false
`)
}

View File

@ -1070,3 +1070,18 @@ func captureStderr(f func() error) (string, error) {
io.Copy(&buf, r)
return buf.String(), err
}
func captureStdout(f func() error) (string, error) {
old := os.Stdout
r, w, _ := os.Pipe()
os.Stdout = w
err := f()
w.Close()
os.Stdout = old
var buf bytes.Buffer
io.Copy(&buf, r)
return buf.String(), err
}

View File

@ -60,14 +60,14 @@ func createLayoutExamples() interface{} {
{"JSON home", LayoutDescriptor{Kind: "home", Type: "page"}, JSONFormat},
{"RSS home", LayoutDescriptor{Kind: "home", Type: "page"}, RSSFormat},
{"RSS section posts", LayoutDescriptor{Kind: "section", Type: "posts"}, RSSFormat},
{"Taxonomy list in categories", LayoutDescriptor{Kind: "taxonomy", Type: "categories", Section: "category"}, RSSFormat},
{"Taxonomy terms in categories", LayoutDescriptor{Kind: "taxonomyTerm", Type: "categories", Section: "category"}, RSSFormat},
{"Taxonomy in categories", LayoutDescriptor{Kind: "taxonomy", Type: "categories", Section: "category"}, RSSFormat},
{"Term in categories", LayoutDescriptor{Kind: "term", Type: "categories", Section: "category"}, RSSFormat},
{"Section list for \"posts\" section", LayoutDescriptor{Kind: "section", Type: "posts", Section: "posts"}, HTMLFormat},
{"Section list for \"posts\" section with type set to \"blog\"", LayoutDescriptor{Kind: "section", Type: "blog", Section: "posts"}, HTMLFormat},
{"Section list for \"posts\" section with layout set to \"demoLayout\"", LayoutDescriptor{Kind: "section", Layout: demoLayout, Section: "posts"}, HTMLFormat},
{"Taxonomy list in categories", LayoutDescriptor{Kind: "taxonomy", Type: "categories", Section: "category"}, HTMLFormat},
{"Taxonomy term in categories", LayoutDescriptor{Kind: "taxonomyTerm", Type: "categories", Section: "category"}, HTMLFormat},
{"Taxonomy term in categories", LayoutDescriptor{Kind: "term", Type: "categories", Section: "category"}, HTMLFormat},
} {
l := NewLayoutHandler()

View File

@ -160,20 +160,22 @@ func resolvePageTemplate(d LayoutDescriptor, f Format) []string {
}
b.addSectionType()
b.addKind()
case "taxonomy":
case "term":
b.addKind()
if d.Section != "" {
b.addLayoutVariations(d.Section)
}
b.addKind()
b.addLayoutVariations("taxonomy")
b.addTypeVariations("taxonomy")
b.addSectionType()
case "taxonomyTerm":
case "taxonomy":
if d.Section != "" {
b.addLayoutVariations(d.Section + ".terms")
}
b.addTypeVariations("taxonomy")
b.addSectionType()
b.addLayoutVariations("terms")
// For legacy reasons this is deliberately put last.
b.addKind()
case "404":
b.addLayoutVariations("404")
b.addTypeVariations("")

View File

@ -88,10 +88,10 @@ func TestLayout(t *testing.T) {
[]string{"sect1/sect1-baseof.amp.html", "sect1/section-baseof.amp.html", "sect1/list-baseof.amp.html", "sect1/baseof.amp.html", "sect1/sect1-baseof.html", "sect1/section-baseof.html", "sect1/list-baseof.html", "sect1/baseof.html"}, 24},
{"Section with layout", LayoutDescriptor{Kind: "section", Section: "sect1", Layout: "mylayout"}, "", ampType,
[]string{"sect1/mylayout.amp.html", "sect1/sect1.amp.html", "sect1/section.amp.html", "sect1/list.amp.html", "sect1/mylayout.html", "sect1/sect1.html"}, 24},
{"Taxonomy", LayoutDescriptor{Kind: "taxonomy", Section: "tag"}, "", ampType,
[]string{"taxonomy/tag.amp.html", "taxonomy/taxonomy.amp.html", "taxonomy/list.amp.html", "taxonomy/tag.html", "taxonomy/taxonomy.html"}, 18},
{"Taxonomy term", LayoutDescriptor{Kind: "taxonomyTerm", Section: "categories"}, "", ampType,
[]string{"taxonomy/categories.terms.amp.html", "taxonomy/terms.amp.html", "taxonomy/list.amp.html", "taxonomy/categories.terms.html", "taxonomy/terms.html"}, 18},
{"Term", LayoutDescriptor{Kind: "term", Section: "tags"}, "", ampType,
[]string{"term/term.amp.html", "term/tags.amp.html", "term/taxonomy.amp.html", "term/list.amp.html", "term/term.html", "term/tags.html", "term/taxonomy.html", "term/list.html", "taxonomy/term.amp.html", "taxonomy/tags.amp.html", "taxonomy/taxonomy.amp.html", "taxonomy/list.amp.html", "taxonomy/term.html", "taxonomy/tags.html", "taxonomy/taxonomy.html", "taxonomy/list.html", "tags/term.amp.html", "tags/tags.amp.html", "tags/taxonomy.amp.html", "tags/list.amp.html", "tags/term.html", "tags/tags.html", "tags/taxonomy.html", "tags/list.html", "_default/term.amp.html", "_default/tags.amp.html", "_default/taxonomy.amp.html", "_default/list.amp.html", "_default/term.html", "_default/tags.html", "_default/taxonomy.html", "_default/list.html"}, 32},
{"Taxonomy", LayoutDescriptor{Kind: "taxonomy", Section: "categories"}, "", ampType,
[]string{"categories/categories.terms.amp.html", "categories/terms.amp.html", "categories/taxonomy.amp.html", "categories/list.amp.html", "categories/categories.terms.html", "categories/terms.html", "categories/taxonomy.html", "categories/list.html", "taxonomy/categories.terms.amp.html", "taxonomy/terms.amp.html", "taxonomy/taxonomy.amp.html", "taxonomy/list.amp.html", "taxonomy/categories.terms.html", "taxonomy/terms.html", "taxonomy/taxonomy.html", "taxonomy/list.html", "_default/categories.terms.amp.html", "_default/terms.amp.html", "_default/taxonomy.amp.html", "_default/list.amp.html", "_default/categories.terms.html", "_default/terms.html", "_default/taxonomy.html", "_default/list.html"}, 24},
{"Page", LayoutDescriptor{Kind: "page"}, "", ampType,
[]string{"_default/single.amp.html", "_default/single.html"}, 2},
{"Page, baseof", LayoutDescriptor{Kind: "page", Baseof: true}, "", ampType,
@ -111,10 +111,10 @@ func TestLayout(t *testing.T) {
[]string{"index-baseof.rss.xml", "home-baseof.rss.xml", "list-baseof.rss.xml", "baseof.rss.xml"}, 16},
{"RSS Section", LayoutDescriptor{Kind: "section", Section: "sect1"}, "", RSSFormat,
[]string{"sect1/sect1.rss.xml", "sect1/section.rss.xml", "sect1/rss.xml", "sect1/list.rss.xml", "sect1/sect1.xml", "sect1/section.xml"}, 22},
{"RSS Term", LayoutDescriptor{Kind: "term", Section: "tag"}, "", RSSFormat,
[]string{"term/term.rss.xml", "term/tag.rss.xml", "term/taxonomy.rss.xml", "term/rss.xml", "term/list.rss.xml", "term/term.xml", "term/tag.xml", "term/taxonomy.xml", "term/list.xml"}, 37},
{"RSS Taxonomy", LayoutDescriptor{Kind: "taxonomy", Section: "tag"}, "", RSSFormat,
[]string{"taxonomy/tag.rss.xml", "taxonomy/taxonomy.rss.xml", "taxonomy/rss.xml", "taxonomy/list.rss.xml", "taxonomy/tag.xml", "taxonomy/taxonomy.xml"}, 22},
{"RSS Taxonomy term", LayoutDescriptor{Kind: "taxonomyTerm", Section: "tag"}, "", RSSFormat,
[]string{"taxonomy/tag.terms.rss.xml", "taxonomy/terms.rss.xml", "taxonomy/rss.xml", "taxonomy/list.rss.xml", "taxonomy/tag.terms.xml"}, 22},
[]string{"tag/tag.terms.rss.xml", "tag/terms.rss.xml", "tag/taxonomy.rss.xml", "tag/rss.xml", "tag/list.rss.xml", "tag/tag.terms.xml", "tag/terms.xml", "tag/taxonomy.xml", "tag/list.xml", "taxonomy/tag.terms.rss.xml", "taxonomy/terms.rss.xml", "taxonomy/taxonomy.rss.xml", "taxonomy/rss.xml", "taxonomy/list.rss.xml", "taxonomy/tag.terms.xml", "taxonomy/terms.xml", "taxonomy/taxonomy.xml", "taxonomy/list.xml", "_default/tag.terms.rss.xml", "_default/terms.rss.xml", "_default/taxonomy.rss.xml", "_default/rss.xml", "_default/list.rss.xml", "_default/tag.terms.xml", "_default/terms.xml", "_default/taxonomy.xml", "_default/list.xml", "_internal/_default/rss.xml"}, 28},
{"Home plain text", LayoutDescriptor{Kind: "home"}, "", JSONFormat,
[]string{"index.json.json", "home.json.json"}, 12},
{"Page plain text", LayoutDescriptor{Kind: "page"}, "", JSONFormat,
@ -157,7 +157,7 @@ func TestLayout(t *testing.T) {
func BenchmarkLayout(b *testing.B) {
c := qt.New(b)
descriptor := LayoutDescriptor{Kind: "taxonomyTerm", Section: "categories"}
descriptor := LayoutDescriptor{Kind: "taxonomy", Section: "categories"}
l := NewLayoutHandler()
for i := 0; i < b.N; i++ {

View File

@ -151,7 +151,7 @@ type PageMetaProvider interface {
// Configured keywords.
Keywords() []string
// The Page Kind. One of page, home, section, taxonomy, taxonomyTerm.
// The Page Kind. One of page, home, section, taxonomy, term.
Kind() string
// The configured layout to use to render this page. Typically set in front matter.

View File

@ -20,18 +20,25 @@ const (
// The rest are node types; home page, sections etc.
KindHome = "home"
KindSection = "section"
KindTaxonomy = "taxonomy"
KindTaxonomyTerm = "taxonomyTerm"
KindHome = "home"
KindSection = "section"
// Note tha before Hugo 0.73 these were confusingly named
// taxonomy (now: term)
// taxonomyTerm (now: taxonomy)
KindTaxonomy = "taxonomy"
KindTerm = "term"
)
var kindMap = map[string]string{
strings.ToLower(KindPage): KindPage,
strings.ToLower(KindHome): KindHome,
strings.ToLower(KindSection): KindSection,
strings.ToLower(KindTaxonomy): KindTaxonomy,
strings.ToLower(KindTaxonomyTerm): KindTaxonomyTerm,
strings.ToLower(KindPage): KindPage,
strings.ToLower(KindHome): KindHome,
strings.ToLower(KindSection): KindSection,
strings.ToLower(KindTaxonomy): KindTaxonomy,
strings.ToLower(KindTerm): KindTerm,
// Legacy, pre v0.53.0.
"taxonomyterm": KindTaxonomy,
}
// GetKind gets the page kind given a string, empty if not found.

View File

@ -27,9 +27,9 @@ func TestKind(t *testing.T) {
c.Assert(KindHome, qt.Equals, "home")
c.Assert(KindSection, qt.Equals, "section")
c.Assert(KindTaxonomy, qt.Equals, "taxonomy")
c.Assert(KindTaxonomyTerm, qt.Equals, "taxonomyTerm")
c.Assert(KindTerm, qt.Equals, "term")
c.Assert(GetKind("TAXONOMYTERM"), qt.Equals, KindTaxonomyTerm)
c.Assert(GetKind("TAXONOMYTERM"), qt.Equals, KindTaxonomy)
c.Assert(GetKind("Taxonomy"), qt.Equals, KindTaxonomy)
c.Assert(GetKind("Page"), qt.Equals, KindPage)
c.Assert(GetKind("Home"), qt.Equals, KindHome)

View File

@ -58,12 +58,12 @@ func TestPageTargetPath(t *testing.T) {
Sections: []string{"sect1"},
BaseName: "_index",
Type: output.HTMLFormat}, TargetPaths{TargetFilename: "/sect1/index.html", SubResourceBaseTarget: "/sect1", Link: "/sect1/"}},
{"HTML taxonomy list", TargetPathDescriptor{
Kind: KindTaxonomy,
{"HTML taxonomy term", TargetPathDescriptor{
Kind: KindTerm,
Sections: []string{"tags", "hugo"},
BaseName: "_index",
Type: output.HTMLFormat}, TargetPaths{TargetFilename: "/tags/hugo/index.html", SubResourceBaseTarget: "/tags/hugo", Link: "/tags/hugo/"}},
{"HTML taxonomy term", TargetPathDescriptor{
{"HTML taxonomy", TargetPathDescriptor{
Kind: KindTaxonomy,
Sections: []string{"tags"},
BaseName: "_index",
@ -143,8 +143,8 @@ func TestPageTargetPath(t *testing.T) {
Type: output.HTMLFormat,
Addends: "page/3"}, TargetPaths{TargetFilename: "/page/3/index.html", SubResourceBaseTarget: "/page/3", Link: "/page/3/"}},
{
"Paginated Taxonomy list", TargetPathDescriptor{
Kind: KindTaxonomy,
"Paginated Taxonomy terms list", TargetPathDescriptor{
Kind: KindTerm,
BaseName: "_index",
Sections: []string{"tags", "hugo"},
Type: output.HTMLFormat,