mirror of
https://github.com/gohugoio/hugo.git
synced 2026-09-02 11:42:37 +00:00
Compare commits
1 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| 8d7a77737c |
@@ -4,7 +4,7 @@ parameters:
|
||||
defaults: &defaults
|
||||
resource_class: large
|
||||
docker:
|
||||
- image: bepsays/ci-hugoreleaser:1.22100.20100
|
||||
- image: bepsays/ci-hugoreleaser:1.22000.20100
|
||||
environment: &buildenv
|
||||
GOMODCACHE: /root/project/gomodcache
|
||||
version: 2
|
||||
@@ -60,7 +60,7 @@ jobs:
|
||||
environment:
|
||||
<<: [*buildenv]
|
||||
docker:
|
||||
- image: bepsays/ci-hugoreleaser-linux-arm64:1.22100.20100
|
||||
- image: bepsays/ci-hugoreleaser-linux-arm64:1.22000.20100
|
||||
steps:
|
||||
- *restore-cache
|
||||
- &attach-workspace
|
||||
|
||||
@@ -14,7 +14,7 @@ jobs:
|
||||
test:
|
||||
strategy:
|
||||
matrix:
|
||||
go-version: [1.21.x]
|
||||
go-version: [1.20.x]
|
||||
os: [ubuntu-latest]
|
||||
runs-on: ${{ matrix.os }}
|
||||
steps:
|
||||
|
||||
@@ -16,7 +16,7 @@ jobs:
|
||||
test:
|
||||
strategy:
|
||||
matrix:
|
||||
go-version: [1.20.x,1.21.x]
|
||||
go-version: [1.19.x,1.20.x]
|
||||
os: [ubuntu-latest, macos-latest, windows-latest]
|
||||
runs-on: ${{ matrix.os }}
|
||||
steps:
|
||||
@@ -34,7 +34,7 @@ jobs:
|
||||
- name: Install Ruby
|
||||
uses: ruby/setup-ruby@ee2113536afb7f793eed4ce60e8d3b26db912da4
|
||||
with:
|
||||
ruby-version: '2.7'
|
||||
ruby-version: '2.7'
|
||||
bundler-cache: true #
|
||||
- name: Install Python
|
||||
uses: actions/setup-python@3105fb18c05ddd93efea5f9e0bef7a03a6e9e7df
|
||||
@@ -64,7 +64,7 @@ jobs:
|
||||
run: |
|
||||
Choco-Install -PackageName mingw -ArgumentList "--version","12.2.0","--allow-downgrade"
|
||||
- if: matrix.os == 'ubuntu-latest'
|
||||
name: Install dart-sass Linux
|
||||
name: Install dart-sass-embedded Linux
|
||||
run: |
|
||||
echo "Install Dart Sass version ${SASS_VERSION} ..."
|
||||
curl -LJO "https://github.com/sass/dart-sass/releases/download/${SASS_VERSION}/dart-sass-${SASS_VERSION}-linux-x64.tar.gz";
|
||||
@@ -73,7 +73,7 @@ jobs:
|
||||
echo "$GOBIN"
|
||||
echo "$GITHUB_WORKSPACE/dart-sass/" >> $GITHUB_PATH
|
||||
- if: matrix.os == 'macos-latest'
|
||||
name: Install dart-sass MacOS
|
||||
name: Install dart-sass-embedded MacOS
|
||||
run: |
|
||||
echo "Install Dart Sass version ${SASS_VERSION} ..."
|
||||
curl -LJO "https://github.com/sass/dart-sass/releases/download/${SASS_VERSION}/dart-sass-${SASS_VERSION}-macos-x64.tar.gz";
|
||||
@@ -81,7 +81,7 @@ jobs:
|
||||
tar -xvf "dart-sass-${SASS_VERSION}-macos-x64.tar.gz";
|
||||
echo "$GITHUB_WORKSPACE/dart-sass/" >> $GITHUB_PATH
|
||||
- if: matrix.os == 'windows-latest'
|
||||
name: Install dart-sass Windows
|
||||
name: Install dart-sass-embedded Windows
|
||||
run: |
|
||||
echo "Install Dart Sass version ${env:SASS_VERSION} ..."
|
||||
curl -LJO "https://github.com/sass/dart-sass/releases/download/${env:SASS_VERSION}/dart-sass-${env:SASS_VERSION}-windows-x64.zip";
|
||||
|
||||
@@ -122,6 +122,8 @@ cd hugo
|
||||
go install
|
||||
```
|
||||
|
||||
>Note: Some Go tools may not be fully updated to support Go Modules yet. One example would be LiteIDE. Follow [this workaround](https://github.com/visualfc/liteide/issues/986#issuecomment-428117702) for how to continue to work with Hugo below `GOPATH`.
|
||||
|
||||
For some convenient build and test targets, you also will want to install Mage:
|
||||
|
||||
```bash
|
||||
|
||||
+2
-2
@@ -2,7 +2,7 @@
|
||||
# Twitter: https://twitter.com/gohugoio
|
||||
# Website: https://gohugo.io/
|
||||
|
||||
FROM golang:1.21-alpine AS build
|
||||
FROM golang:1.19-alpine AS build
|
||||
|
||||
# Optionally set HUGO_BUILD_TAGS to "extended" or "nodeploy" when building like so:
|
||||
# docker build --build-arg HUGO_BUILD_TAGS=extended .
|
||||
@@ -26,7 +26,7 @@ RUN mage hugo && mage install
|
||||
|
||||
# ---
|
||||
|
||||
FROM alpine:3.18
|
||||
FROM alpine:3.16
|
||||
|
||||
COPY --from=build /go/bin/hugo /usr/bin/hugo
|
||||
|
||||
|
||||
@@ -33,7 +33,7 @@ A fast and flexible static site generator built with love by [bep], [spf13], and
|
||||
[](https://github.com/gohugoio/hugo/actions?query=workflow%3ATest)
|
||||
[](https://goreportcard.com/report/github.com/gohugoio/hugo)
|
||||
|
||||
[Website] | [Installation] | [Documentation] | [Support] | [Contributing] | <a rel="me" href="https://fosstodon.org/@gohugoio">Mastodon</a>
|
||||
[Website] | [Installation] | [Documentation] | [Support] | [Contributing] | [Twitter]
|
||||
|
||||
## Overview
|
||||
|
||||
|
||||
Vendored
+4
-33
@@ -51,9 +51,6 @@ type Cache struct {
|
||||
pruneAllRootDir string
|
||||
|
||||
nlocker *lockTracker
|
||||
|
||||
initOnce sync.Once
|
||||
initErr error
|
||||
}
|
||||
|
||||
type lockTracker struct {
|
||||
@@ -106,23 +103,9 @@ func (l *lockedFile) Close() error {
|
||||
return l.File.Close()
|
||||
}
|
||||
|
||||
func (c *Cache) init() error {
|
||||
c.initOnce.Do(func() {
|
||||
// Create the base dir if it does not exist.
|
||||
if err := c.Fs.MkdirAll("", 0777); err != nil && !os.IsExist(err) {
|
||||
c.initErr = err
|
||||
}
|
||||
})
|
||||
return c.initErr
|
||||
}
|
||||
|
||||
// WriteCloser returns a transactional writer into the cache.
|
||||
// It's important that it's closed when done.
|
||||
func (c *Cache) WriteCloser(id string) (ItemInfo, io.WriteCloser, error) {
|
||||
if err := c.init(); err != nil {
|
||||
return ItemInfo{}, nil, err
|
||||
}
|
||||
|
||||
id = cleanID(id)
|
||||
c.nlocker.Lock(id)
|
||||
|
||||
@@ -147,10 +130,6 @@ func (c *Cache) WriteCloser(id string) (ItemInfo, io.WriteCloser, error) {
|
||||
func (c *Cache) ReadOrCreate(id string,
|
||||
read func(info ItemInfo, r io.ReadSeeker) error,
|
||||
create func(info ItemInfo, w io.WriteCloser) error) (info ItemInfo, err error) {
|
||||
if err := c.init(); err != nil {
|
||||
return ItemInfo{}, err
|
||||
}
|
||||
|
||||
id = cleanID(id)
|
||||
|
||||
c.nlocker.Lock(id)
|
||||
@@ -184,9 +163,6 @@ func (c *Cache) ReadOrCreate(id string,
|
||||
// be invoked and the result cached.
|
||||
// This method is protected by a named lock using the given id as identifier.
|
||||
func (c *Cache) GetOrCreate(id string, create func() (io.ReadCloser, error)) (ItemInfo, io.ReadCloser, error) {
|
||||
if err := c.init(); err != nil {
|
||||
return ItemInfo{}, nil, err
|
||||
}
|
||||
id = cleanID(id)
|
||||
|
||||
c.nlocker.Lock(id)
|
||||
@@ -221,9 +197,6 @@ func (c *Cache) GetOrCreate(id string, create func() (io.ReadCloser, error)) (It
|
||||
|
||||
// GetOrCreateBytes is the same as GetOrCreate, but produces a byte slice.
|
||||
func (c *Cache) GetOrCreateBytes(id string, create func() ([]byte, error)) (ItemInfo, []byte, error) {
|
||||
if err := c.init(); err != nil {
|
||||
return ItemInfo{}, nil, err
|
||||
}
|
||||
id = cleanID(id)
|
||||
|
||||
c.nlocker.Lock(id)
|
||||
@@ -259,9 +232,6 @@ func (c *Cache) GetOrCreateBytes(id string, create func() ([]byte, error)) (Item
|
||||
|
||||
// GetBytes gets the file content with the given id from the cache, nil if none found.
|
||||
func (c *Cache) GetBytes(id string) (ItemInfo, []byte, error) {
|
||||
if err := c.init(); err != nil {
|
||||
return ItemInfo{}, nil, err
|
||||
}
|
||||
id = cleanID(id)
|
||||
|
||||
c.nlocker.Lock(id)
|
||||
@@ -280,9 +250,6 @@ func (c *Cache) GetBytes(id string) (ItemInfo, []byte, error) {
|
||||
|
||||
// Get gets the file with the given id from the cache, nil if none found.
|
||||
func (c *Cache) Get(id string) (ItemInfo, io.ReadCloser, error) {
|
||||
if err := c.init(); err != nil {
|
||||
return ItemInfo{}, nil, err
|
||||
}
|
||||
id = cleanID(id)
|
||||
|
||||
c.nlocker.Lock(id)
|
||||
@@ -380,6 +347,10 @@ func NewCaches(p *helpers.PathSpec) (Caches, error) {
|
||||
|
||||
baseDir := v.DirCompiled
|
||||
|
||||
if err := cfs.MkdirAll(baseDir, 0777); err != nil && !os.IsExist(err) {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
bfs := afero.NewBasePathFs(cfs, baseDir)
|
||||
|
||||
var pruneAllRootDir string
|
||||
|
||||
Vendored
-6
@@ -53,9 +53,6 @@ func (c *Cache) Prune(force bool) (int, error) {
|
||||
if c.pruneAllRootDir != "" {
|
||||
return c.pruneRootDir(force)
|
||||
}
|
||||
if err := c.init(); err != nil {
|
||||
return 0, err
|
||||
}
|
||||
|
||||
counter := 0
|
||||
|
||||
@@ -120,9 +117,6 @@ func (c *Cache) Prune(force bool) (int, error) {
|
||||
}
|
||||
|
||||
func (c *Cache) pruneRootDir(force bool) (int, error) {
|
||||
if err := c.init(); err != nil {
|
||||
return 0, err
|
||||
}
|
||||
info, err := c.Fs.Stat(c.pruneAllRootDir)
|
||||
if err != nil {
|
||||
if herrors.IsNotExist(err) {
|
||||
|
||||
+13
-6
@@ -38,7 +38,6 @@ import (
|
||||
|
||||
"github.com/gohugoio/hugo/common/hstrings"
|
||||
"github.com/gohugoio/hugo/common/htime"
|
||||
"github.com/gohugoio/hugo/common/hugo"
|
||||
"github.com/gohugoio/hugo/common/loggers"
|
||||
"github.com/gohugoio/hugo/common/paths"
|
||||
"github.com/gohugoio/hugo/config"
|
||||
@@ -51,7 +50,9 @@ import (
|
||||
"github.com/spf13/cobra"
|
||||
)
|
||||
|
||||
var errHelp = errors.New("help requested")
|
||||
var (
|
||||
errHelp = errors.New("help requested")
|
||||
)
|
||||
|
||||
// Execute executes a command.
|
||||
func Execute(args []string) error {
|
||||
@@ -181,9 +182,11 @@ func (r *rootCommand) ConfigFromConfig(key int32, oldConf *commonConfig) (*commo
|
||||
cfg: oldConf.cfg,
|
||||
fs: fs,
|
||||
}, nil
|
||||
|
||||
})
|
||||
|
||||
return cc, err
|
||||
|
||||
}
|
||||
|
||||
func (r *rootCommand) ConfigFromProvider(key int32, cfg config.Provider) (*commonConfig, error) {
|
||||
@@ -208,7 +211,7 @@ func (r *rootCommand) ConfigFromProvider(key int32, cfg config.Provider) (*commo
|
||||
if !cfg.IsSet("workingDir") {
|
||||
cfg.Set("workingDir", dir)
|
||||
} else {
|
||||
if err := os.MkdirAll(cfg.GetString("workingDir"), 0o777); err != nil {
|
||||
if err := os.MkdirAll(cfg.GetString("workingDir"), 0777); err != nil {
|
||||
return nil, fmt.Errorf("failed to create workingDir: %w", err)
|
||||
}
|
||||
}
|
||||
@@ -300,6 +303,7 @@ func (r *rootCommand) ConfigFromProvider(key int32, cfg config.Provider) (*commo
|
||||
})
|
||||
|
||||
return cc, err
|
||||
|
||||
}
|
||||
|
||||
func (r *rootCommand) HugFromConfig(conf *commonConfig) (*hugolib.HugoSites, error) {
|
||||
@@ -344,6 +348,7 @@ func (r *rootCommand) Run(ctx context.Context, cd *simplecobra.Commandeer, args
|
||||
err := b.build()
|
||||
return err
|
||||
}()
|
||||
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
@@ -429,13 +434,12 @@ func (r *rootCommand) createLogger(running bool) (loggers.Logger, error) {
|
||||
}
|
||||
} else {
|
||||
if r.verbose {
|
||||
hugo.Deprecate("--verbose", "use --logLevel info", "v0.114.0")
|
||||
hugo.Deprecate("--verbose", "use --logLevel info", "v0.114.0")
|
||||
helpers.Deprecated("--verbose", "use --logLevel info", false)
|
||||
level = logg.LevelInfo
|
||||
}
|
||||
|
||||
if r.debug {
|
||||
hugo.Deprecate("--debug", "use --logLevel debug", "v0.114.0")
|
||||
helpers.Deprecated("--debug", "use --logLevel debug", false)
|
||||
level = logg.LevelDebug
|
||||
}
|
||||
}
|
||||
@@ -449,6 +453,7 @@ func (r *rootCommand) createLogger(running bool) (loggers.Logger, error) {
|
||||
}
|
||||
|
||||
return loggers.New(optsLogger), nil
|
||||
|
||||
}
|
||||
|
||||
func (r *rootCommand) Reset() {
|
||||
@@ -514,6 +519,7 @@ func applyLocalFlagsBuildConfig(cmd *cobra.Command, r *rootCommand) {
|
||||
_ = cmd.Flags().SetAnnotation("cacheDir", cobra.BashCompSubdirsInDir, []string{})
|
||||
cmd.Flags().StringP("contentDir", "c", "", "filesystem path to content directory")
|
||||
_ = cmd.Flags().SetAnnotation("theme", cobra.BashCompSubdirsInDir, []string{"themes"})
|
||||
|
||||
}
|
||||
|
||||
// Flags needed to do a build (used by hugo and hugo server commands)
|
||||
@@ -552,6 +558,7 @@ func applyLocalFlagsBuild(cmd *cobra.Command, r *rootCommand) {
|
||||
cmd.Flags().StringSlice("disableKinds", []string{}, "disable different kind of pages (home, RSS etc.)")
|
||||
cmd.Flags().Bool("minify", false, "minify any supported output format (HTML, XML etc.)")
|
||||
_ = cmd.Flags().SetAnnotation("destination", cobra.BashCompSubdirsInDir, []string{})
|
||||
|
||||
}
|
||||
|
||||
func (r *rootCommand) timeTrack(start time.Time, name string) {
|
||||
|
||||
+2
-2
@@ -76,7 +76,7 @@ See https://xyproto.github.io/splash/docs/all.html for a preview of the availabl
|
||||
},
|
||||
withc: func(cmd *cobra.Command, r *rootCommand) {
|
||||
cmd.PersistentFlags().StringVar(&style, "style", "friendly", "highlighter style (see https://xyproto.github.io/splash/docs/)")
|
||||
cmd.PersistentFlags().StringVar(&highlightStyle, "highlightStyle", "", "style used for highlighting lines (see https://github.com/alecthomas/chroma)")
|
||||
cmd.PersistentFlags().StringVar(&highlightStyle, "highlightStyle", "bg:#ffffcc", "style used for highlighting lines (see https://github.com/alecthomas/chroma)")
|
||||
cmd.PersistentFlags().StringVar(&linesStyle, "linesStyle", "", "style used for line numbers (see https://github.com/alecthomas/chroma)")
|
||||
},
|
||||
}
|
||||
@@ -136,7 +136,7 @@ url: %s
|
||||
long: `Generate Markdown documentation for the Hugo CLI.
|
||||
This command is, mostly, used to create up-to-date documentation
|
||||
of Hugo's command-line interface for https://gohugo.io/.
|
||||
|
||||
|
||||
It creates one Markdown file per command with front matter suitable
|
||||
for rendering in Hugo.`,
|
||||
run: func(ctx context.Context, cd *simplecobra.Commandeer, r *rootCommand, args []string) error {
|
||||
|
||||
@@ -25,9 +25,9 @@ func init() {
|
||||
// This message to show to Windows users if Hugo is opened from explorer.exe
|
||||
cobra.MousetrapHelpText = `
|
||||
|
||||
Hugo is a command-line tool for generating static websites.
|
||||
|
||||
You need to open PowerShell and run Hugo from there.
|
||||
Hugo is a command-line tool for generating static website.
|
||||
|
||||
You need to open cmd.exe and run Hugo from there.
|
||||
|
||||
Visit https://gohugo.io/ for more information.`
|
||||
}
|
||||
|
||||
+3
-7
@@ -211,12 +211,7 @@ Install a specific version:
|
||||
|
||||
hugo mod get github.com/gohugoio/testshortcodes@v0.3.0
|
||||
|
||||
Install the latest versions of all direct module dependencies:
|
||||
|
||||
hugo mod get
|
||||
hugo mod get ./... (recursive)
|
||||
|
||||
Install the latest versions of all module dependencies (direct and indirect):
|
||||
Install the latest versions of all module dependencies:
|
||||
|
||||
hugo mod get -u
|
||||
hugo mod get -u ./... (recursive)
|
||||
@@ -286,6 +281,7 @@ Run "go help get" for more information. All flags available for "go get" is also
|
||||
npmCommand,
|
||||
},
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
type modCommands struct {
|
||||
@@ -307,7 +303,7 @@ func (c *modCommands) Run(ctx context.Context, cd *simplecobra.Commandeer, args
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
// config := conf.configs.Base
|
||||
//config := conf.configs.Base
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
+6
-7
@@ -20,7 +20,6 @@ import (
|
||||
"strings"
|
||||
|
||||
"github.com/bep/simplecobra"
|
||||
"github.com/gohugoio/hugo/common/paths"
|
||||
"github.com/gohugoio/hugo/config"
|
||||
"github.com/gohugoio/hugo/create"
|
||||
"github.com/gohugoio/hugo/create/skeletons"
|
||||
@@ -63,6 +62,7 @@ Ensure you run this within the root directory of your site.`,
|
||||
cmd.Flags().StringVarP(&contentType, "kind", "k", "", "content type to create")
|
||||
cmd.Flags().String("editor", "", "edit new content with this editor, if provided")
|
||||
cmd.Flags().BoolVarP(&force, "force", "f", false, "overwrite file if it already exists")
|
||||
cmd.Flags().StringVar(&format, "format", "toml", "preferred file format (toml, yaml or json)")
|
||||
applyLocalFlagsBuildConfig(cmd, r)
|
||||
|
||||
},
|
||||
@@ -120,15 +120,14 @@ according to your needs.`,
|
||||
if len(args) < 1 {
|
||||
return newUserError("theme name needs to be provided")
|
||||
}
|
||||
cfg := config.New()
|
||||
cfg.Set("publishDir", "public")
|
||||
|
||||
conf, err := r.ConfigFromProvider(r.configVersionID.Load(), flagsToCfg(cd, cfg))
|
||||
h, err := r.Hugo(flagsToCfg(cd, nil))
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
sourceFs := conf.fs.Source
|
||||
createpath := paths.AbsPathify(conf.configs.Base.WorkingDir, filepath.Join(conf.configs.Base.ThemesDir, args[0]))
|
||||
ps := h.PathSpec
|
||||
sourceFs := ps.Fs.Source
|
||||
themesDir := h.Configs.LoadingInfo.BaseConfig.ThemesDir
|
||||
createpath := ps.AbsPathify(filepath.Join(themesDir, args[0]))
|
||||
r.Println("Creating new theme in", createpath)
|
||||
|
||||
err = skeletons.CreateTheme(createpath, sourceFs)
|
||||
|
||||
+1
-1
@@ -954,7 +954,7 @@ func (c *serverCommand) serve() error {
|
||||
mu.HandleFunc(u.Path+"/livereload.js", livereload.ServeJS)
|
||||
mu.HandleFunc(u.Path+"/livereload", livereload.Handler)
|
||||
}
|
||||
c.r.Printf("Web Server is available at %s (bind address %s) %s\n", serverURL, c.serverInterface, roots[i])
|
||||
c.r.Printf("Web Server is available at %s (bind address %s)\n", serverURL, c.serverInterface)
|
||||
wg1.Go(func() error {
|
||||
if c.tlsCertFile != "" && c.tlsKeyFile != "" {
|
||||
err = srv.ServeTLS(listener, c.tlsCertFile, c.tlsKeyFile)
|
||||
|
||||
@@ -16,6 +16,9 @@ package constants
|
||||
// Error IDs.
|
||||
// Do not change these values.
|
||||
const (
|
||||
ErrIDAmbigousDisableKindTaxonomy = "error-disable-taxonomy"
|
||||
ErrIDAmbigousOutputKindTaxonomy = "error-output-taxonomy"
|
||||
|
||||
// IDs for remote errors in tpl/data.
|
||||
ErrRemoteGetJSON = "error-remote-getjson"
|
||||
ErrRemoteGetCSV = "error-remote-getcsv"
|
||||
|
||||
@@ -99,26 +99,3 @@ var reCache = regexpCache{re: make(map[string]*regexp.Regexp)}
|
||||
func GetOrCompileRegexp(pattern string) (re *regexp.Regexp, err error) {
|
||||
return reCache.getOrCompileRegexp(pattern)
|
||||
}
|
||||
|
||||
// InSlice checks if a string is an element of a slice of strings
|
||||
// and returns a boolean value.
|
||||
func InSlice(arr []string, el string) bool {
|
||||
for _, v := range arr {
|
||||
if v == el {
|
||||
return true
|
||||
}
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
// InSlicEqualFold checks if a string is an element of a slice of strings
|
||||
// and returns a boolean value.
|
||||
// It uses strings.EqualFold to compare.
|
||||
func InSlicEqualFold(arr []string, el string) bool {
|
||||
for _, v := range arr {
|
||||
if strings.EqualFold(v, el) {
|
||||
return true
|
||||
}
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
+6
-63
@@ -22,15 +22,14 @@ import (
|
||||
"sort"
|
||||
"strings"
|
||||
"sync"
|
||||
"time"
|
||||
|
||||
godartsassv1 "github.com/bep/godartsass"
|
||||
"github.com/bep/logg"
|
||||
"github.com/mitchellh/mapstructure"
|
||||
|
||||
"time"
|
||||
|
||||
"github.com/bep/godartsass/v2"
|
||||
"github.com/gohugoio/hugo/common/hexec"
|
||||
"github.com/gohugoio/hugo/common/loggers"
|
||||
"github.com/gohugoio/hugo/hugofs/files"
|
||||
|
||||
"github.com/spf13/afero"
|
||||
@@ -79,22 +78,10 @@ func (i HugoInfo) Generator() template.HTML {
|
||||
return template.HTML(fmt.Sprintf(`<meta name="generator" content="Hugo %s">`, CurrentVersion.String()))
|
||||
}
|
||||
|
||||
// IsDevelopment reports whether the current running environment is "development".
|
||||
func (i HugoInfo) IsDevelopment() bool {
|
||||
return i.Environment == EnvironmentDevelopment
|
||||
}
|
||||
|
||||
// IsProduction reports whether the current running environment is "production".
|
||||
func (i HugoInfo) IsProduction() bool {
|
||||
return i.Environment == EnvironmentProduction
|
||||
}
|
||||
|
||||
// IsServer reports whether the built-in server is running.
|
||||
func (i HugoInfo) IsServer() bool {
|
||||
return i.conf.Running()
|
||||
}
|
||||
|
||||
// IsExtended reports whether the Hugo binary is the extended version.
|
||||
func (i HugoInfo) IsExtended() bool {
|
||||
return IsExtended
|
||||
}
|
||||
@@ -112,7 +99,6 @@ func (i HugoInfo) Deps() []*Dependency {
|
||||
// ConfigProvider represents the config options that are relevant for HugoInfo.
|
||||
type ConfigProvider interface {
|
||||
Environment() string
|
||||
Running() bool
|
||||
WorkingDir() string
|
||||
}
|
||||
|
||||
@@ -184,10 +170,8 @@ type buildInfo struct {
|
||||
*debug.BuildInfo
|
||||
}
|
||||
|
||||
var (
|
||||
bInfo *buildInfo
|
||||
bInfoInit sync.Once
|
||||
)
|
||||
var bInfo *buildInfo
|
||||
var bInfoInit sync.Once
|
||||
|
||||
func getBuildInfo() *buildInfo {
|
||||
bInfoInit.Do(func() {
|
||||
@@ -214,6 +198,7 @@ func getBuildInfo() *buildInfo {
|
||||
bInfo.GoArch = s.Value
|
||||
}
|
||||
}
|
||||
|
||||
})
|
||||
|
||||
return bInfo
|
||||
@@ -257,7 +242,7 @@ func GetDependencyListNonGo() []string {
|
||||
}
|
||||
|
||||
if dartSass := dartSassVersion(); dartSass.ProtocolVersion != "" {
|
||||
dartSassPath := "github.com/sass/dart-sass-embedded"
|
||||
var dartSassPath = "github.com/sass/dart-sass-embedded"
|
||||
if IsDartSassV2() {
|
||||
dartSassPath = "github.com/sass/dart-sass"
|
||||
}
|
||||
@@ -348,45 +333,3 @@ var (
|
||||
func IsDartSassV2() bool {
|
||||
return !strings.Contains(DartSassBinaryName, "embedded")
|
||||
}
|
||||
|
||||
// Deprecate informs about a deprecation starting at the given version.
|
||||
//
|
||||
// A deprecation typically needs a simple change in the template, but doing so will make the template incompatible with older versions.
|
||||
// Theme maintainers generally want
|
||||
// 1. No warnings or errors in the console when building a Hugo site.
|
||||
// 2. Their theme to work for at least the last few Hugo versions.
|
||||
func Deprecate(item, alternative string, version string) {
|
||||
level := deprecationLogLevelFromVersion(version)
|
||||
DeprecateLevel(item, alternative, version, level)
|
||||
}
|
||||
|
||||
// DeprecateLevel informs about a deprecation logging at the given level.
|
||||
func DeprecateLevel(item, alternative, version string, level logg.Level) {
|
||||
var msg string
|
||||
if level == logg.LevelError {
|
||||
msg = fmt.Sprintf("%s was deprecated in Hugo %s and will be removed in Hugo %s. %s", item, version, CurrentVersion.Next().ReleaseVersion(), alternative)
|
||||
} else {
|
||||
msg = fmt.Sprintf("%s was deprecated in Hugo %s and will be removed in a future release. %s", item, version, alternative)
|
||||
}
|
||||
|
||||
loggers.Log().Logger().WithLevel(level).Logf(msg)
|
||||
}
|
||||
|
||||
// We ususally do about one minor version a month.
|
||||
// We want people to run at least the current and previous version without any warnings.
|
||||
// We want people who don't update Hugo that often to see the warnings and errors before we remove the feature.
|
||||
func deprecationLogLevelFromVersion(ver string) logg.Level {
|
||||
from := MustParseVersion(ver)
|
||||
to := CurrentVersion
|
||||
minorDiff := to.Minor - from.Minor
|
||||
switch {
|
||||
case minorDiff >= 12:
|
||||
// Start failing the build after about a year.
|
||||
return logg.LevelError
|
||||
case minorDiff >= 6:
|
||||
// Start printing warnings after about six months.
|
||||
return logg.LevelWarn
|
||||
default:
|
||||
return logg.LevelInfo
|
||||
}
|
||||
}
|
||||
|
||||
@@ -17,14 +17,13 @@ import (
|
||||
"fmt"
|
||||
"testing"
|
||||
|
||||
"github.com/bep/logg"
|
||||
qt "github.com/frankban/quicktest"
|
||||
)
|
||||
|
||||
func TestHugoInfo(t *testing.T) {
|
||||
c := qt.New(t)
|
||||
|
||||
conf := testConfig{environment: "production", workingDir: "/mywork", running: false}
|
||||
conf := testConfig{environment: "production", workingDir: "/mywork"}
|
||||
hugoInfo := NewInfo(conf, nil)
|
||||
|
||||
c.Assert(hugoInfo.Version(), qt.Equals, CurrentVersion.Version())
|
||||
@@ -39,34 +38,15 @@ func TestHugoInfo(t *testing.T) {
|
||||
}
|
||||
c.Assert(hugoInfo.Environment, qt.Equals, "production")
|
||||
c.Assert(string(hugoInfo.Generator()), qt.Contains, fmt.Sprintf("Hugo %s", hugoInfo.Version()))
|
||||
c.Assert(hugoInfo.IsDevelopment(), qt.Equals, false)
|
||||
c.Assert(hugoInfo.IsProduction(), qt.Equals, true)
|
||||
c.Assert(hugoInfo.IsExtended(), qt.Equals, IsExtended)
|
||||
c.Assert(hugoInfo.IsServer(), qt.Equals, false)
|
||||
|
||||
devHugoInfo := NewInfo(testConfig{environment: "development", running: true}, nil)
|
||||
c.Assert(devHugoInfo.IsDevelopment(), qt.Equals, true)
|
||||
devHugoInfo := NewInfo(testConfig{environment: "development"}, nil)
|
||||
c.Assert(devHugoInfo.IsProduction(), qt.Equals, false)
|
||||
c.Assert(devHugoInfo.IsServer(), qt.Equals, true)
|
||||
}
|
||||
|
||||
func TestDeprecationLogLevelFromVersion(t *testing.T) {
|
||||
c := qt.New(t)
|
||||
|
||||
c.Assert(deprecationLogLevelFromVersion("0.55.0"), qt.Equals, logg.LevelError)
|
||||
ver := CurrentVersion
|
||||
c.Assert(deprecationLogLevelFromVersion(ver.String()), qt.Equals, logg.LevelInfo)
|
||||
ver.Minor -= 1
|
||||
c.Assert(deprecationLogLevelFromVersion(ver.String()), qt.Equals, logg.LevelInfo)
|
||||
ver.Minor -= 6
|
||||
c.Assert(deprecationLogLevelFromVersion(ver.String()), qt.Equals, logg.LevelWarn)
|
||||
ver.Minor -= 6
|
||||
c.Assert(deprecationLogLevelFromVersion(ver.String()), qt.Equals, logg.LevelError)
|
||||
}
|
||||
|
||||
type testConfig struct {
|
||||
environment string
|
||||
running bool
|
||||
workingDir string
|
||||
}
|
||||
|
||||
@@ -74,10 +54,6 @@ func (c testConfig) Environment() string {
|
||||
return c.environment
|
||||
}
|
||||
|
||||
func (c testConfig) Running() bool {
|
||||
return c.running
|
||||
}
|
||||
|
||||
func (c testConfig) WorkingDir() string {
|
||||
return c.workingDir
|
||||
}
|
||||
|
||||
@@ -67,11 +67,8 @@ func (h VersionString) String() string {
|
||||
|
||||
// Compare implements the compare.Comparer interface.
|
||||
func (h VersionString) Compare(other any) int {
|
||||
return compareVersions(h.Version(), other)
|
||||
}
|
||||
|
||||
func (h VersionString) Version() Version {
|
||||
return MustParseVersion(h.String())
|
||||
v := MustParseVersion(h.String())
|
||||
return compareVersions(v, other)
|
||||
}
|
||||
|
||||
// Eq implements the compare.Eqer interface.
|
||||
@@ -267,6 +264,7 @@ func compareFloatWithVersion(v1 float64, v2 Version) int {
|
||||
|
||||
if v1maj > v2.Major {
|
||||
return 1
|
||||
|
||||
}
|
||||
|
||||
if v1maj < v2.Major {
|
||||
@@ -278,6 +276,7 @@ func compareFloatWithVersion(v1 float64, v2 Version) int {
|
||||
}
|
||||
|
||||
return -1
|
||||
|
||||
}
|
||||
|
||||
func GoMinorVersion() int {
|
||||
|
||||
@@ -17,7 +17,7 @@ package hugo
|
||||
// This should be the only one.
|
||||
var CurrentVersion = Version{
|
||||
Major: 0,
|
||||
Minor: 120,
|
||||
Minor: 117,
|
||||
PatchLevel: 0,
|
||||
Suffix: "",
|
||||
Suffix: "-DEV",
|
||||
}
|
||||
|
||||
@@ -37,13 +37,13 @@ var (
|
||||
|
||||
// Options defines options for the logger.
|
||||
type Options struct {
|
||||
Level logg.Level
|
||||
Stdout io.Writer
|
||||
Stderr io.Writer
|
||||
Distinct bool
|
||||
StoreErrors bool
|
||||
HandlerPost func(e *logg.Entry) error
|
||||
SuppressStatements map[string]bool
|
||||
Level logg.Level
|
||||
Stdout io.Writer
|
||||
Stderr io.Writer
|
||||
Distinct bool
|
||||
StoreErrors bool
|
||||
HandlerPost func(e *logg.Entry) error
|
||||
SuppresssStatements map[string]bool
|
||||
}
|
||||
|
||||
// New creates a new logger with the given options.
|
||||
@@ -97,8 +97,8 @@ func New(opts Options) Logger {
|
||||
logHandler = newStopHandler(logOnce, logHandler)
|
||||
}
|
||||
|
||||
if opts.SuppressStatements != nil && len(opts.SuppressStatements) > 0 {
|
||||
logHandler = newStopHandler(newSuppressStatementsHandler(opts.SuppressStatements), logHandler)
|
||||
if opts.SuppresssStatements != nil && len(opts.SuppresssStatements) > 0 {
|
||||
logHandler = newStopHandler(newSuppressStatementsHandler(opts.SuppresssStatements), logHandler)
|
||||
}
|
||||
|
||||
logger := logg.New(
|
||||
|
||||
@@ -110,7 +110,7 @@ func TestSuppressStatements(t *testing.T) {
|
||||
|
||||
opts := loggers.Options{
|
||||
StoreErrors: true,
|
||||
SuppressStatements: map[string]bool{
|
||||
SuppresssStatements: map[string]bool{
|
||||
"error-1": true,
|
||||
},
|
||||
}
|
||||
|
||||
+9
-12
@@ -51,10 +51,9 @@ var pb pathBridge
|
||||
|
||||
// MakePermalink combines base URL with content path to create full URL paths.
|
||||
// Example
|
||||
//
|
||||
// base: http://spf13.com/
|
||||
// path: post/how-i-blog
|
||||
// result: http://spf13.com/post/how-i-blog
|
||||
// base: http://spf13.com/
|
||||
// path: post/how-i-blog
|
||||
// result: http://spf13.com/post/how-i-blog
|
||||
func MakePermalink(host, plink string) *url.URL {
|
||||
base, err := url.Parse(host)
|
||||
if err != nil {
|
||||
@@ -118,19 +117,17 @@ func PrettifyURL(in string) string {
|
||||
|
||||
// PrettifyURLPath takes a URL path to a content and converts it
|
||||
// to enable pretty URLs.
|
||||
//
|
||||
// /section/name.html becomes /section/name/index.html
|
||||
// /section/name/ becomes /section/name/index.html
|
||||
// /section/name/index.html becomes /section/name/index.html
|
||||
// /section/name.html becomes /section/name/index.html
|
||||
// /section/name/ becomes /section/name/index.html
|
||||
// /section/name/index.html becomes /section/name/index.html
|
||||
func PrettifyURLPath(in string) string {
|
||||
return prettifyPath(in, pb)
|
||||
}
|
||||
|
||||
// Uglify does the opposite of PrettifyURLPath().
|
||||
//
|
||||
// /section/name/index.html becomes /section/name.html
|
||||
// /section/name/ becomes /section/name.html
|
||||
// /section/name.html becomes /section/name.html
|
||||
// /section/name/index.html becomes /section/name.html
|
||||
// /section/name/ becomes /section/name.html
|
||||
// /section/name.html becomes /section/name.html
|
||||
func Uglify(in string) string {
|
||||
if path.Ext(in) == "" {
|
||||
if len(in) < 2 {
|
||||
|
||||
@@ -27,7 +27,6 @@ import (
|
||||
"time"
|
||||
|
||||
"github.com/gohugoio/hugo/cache/filecache"
|
||||
"github.com/gohugoio/hugo/common/hugo"
|
||||
"github.com/gohugoio/hugo/common/loggers"
|
||||
"github.com/gohugoio/hugo/common/maps"
|
||||
"github.com/gohugoio/hugo/common/urls"
|
||||
@@ -785,7 +784,7 @@ func fromLoadConfigResult(fs afero.Fs, logger loggers.Logger, res config.LoadCon
|
||||
// We accidentally allowed it in the past, so we need to support it a little longer,
|
||||
// But log a warning.
|
||||
if _, found := params[kk]; !found {
|
||||
hugo.Deprecate(fmt.Sprintf("config: languages.%s.%s: custom params on the language top level", k, kk), fmt.Sprintf("Put the value below [languages.%s.params]. See https://gohugo.io/content-management/multilingual/#changes-in-hugo-01120", k), "v0.112.0")
|
||||
helpers.Deprecated(fmt.Sprintf("config: languages.%s.%s: custom params on the language top level", k, kk), fmt.Sprintf("Put the value below [languages.%s.params]. See https://gohugo.io/content-management/multilingual/#changes-in-hugo-01120", k), false)
|
||||
params[kk] = vv
|
||||
}
|
||||
}
|
||||
|
||||
@@ -140,7 +140,7 @@ func (c ConfigLanguage) GetConfigSection(s string) any {
|
||||
return c.config.Permalinks
|
||||
case "minify":
|
||||
return c.config.Minify
|
||||
case "allModules":
|
||||
case "activeModules":
|
||||
return c.m.Modules
|
||||
case "deployment":
|
||||
return c.config.Deployment
|
||||
@@ -228,7 +228,3 @@ func (c ConfigLanguage) PaginatePath() string {
|
||||
func (c ConfigLanguage) StaticDirs() []string {
|
||||
return c.config.staticDirs()
|
||||
}
|
||||
|
||||
func (c ConfigLanguage) EnableEmoji() bool {
|
||||
return c.config.EnableEmoji
|
||||
}
|
||||
|
||||
@@ -84,7 +84,7 @@ func LoadConfig(d ConfigSourceDescriptor) (*Configs, error) {
|
||||
return nil, fmt.Errorf("failed to create config: %w", err)
|
||||
}
|
||||
|
||||
configs.Modules = moduleConfig.AllModules
|
||||
configs.Modules = moduleConfig.ActiveModules
|
||||
configs.ModulesClient = modulesClient
|
||||
|
||||
if err := configs.Init(); err != nil {
|
||||
@@ -471,7 +471,7 @@ func (l *configLoader) loadModules(configs *Configs) (modules.ModulesConfig, *mo
|
||||
ex := hexec.New(conf.Security)
|
||||
|
||||
hook := func(m *modules.ModulesConfig) error {
|
||||
for _, tc := range m.AllModules {
|
||||
for _, tc := range m.ActiveModules {
|
||||
if len(tc.ConfigFilenames()) > 0 {
|
||||
if tc.Watch() {
|
||||
l.ModulesConfigFiles = append(l.ModulesConfigFiles, tc.ConfigFilenames()...)
|
||||
|
||||
@@ -66,7 +66,6 @@ type AllProvider interface {
|
||||
StaticDirs() []string
|
||||
IgnoredErrors() map[string]bool
|
||||
WorkingDir() string
|
||||
EnableEmoji() bool
|
||||
}
|
||||
|
||||
// Provider provides the configuration settings for Hugo.
|
||||
|
||||
@@ -0,0 +1,4 @@
|
||||
[module]
|
||||
[module.hugoVersion]
|
||||
extended = false
|
||||
min = "0.116.0"
|
||||
@@ -0,0 +1,14 @@
|
||||
[[main]]
|
||||
name = 'Home'
|
||||
pageRef = '/'
|
||||
weight = 10
|
||||
|
||||
[[main]]
|
||||
name = 'Posts'
|
||||
pageRef = '/posts'
|
||||
weight = 20
|
||||
|
||||
[[main]]
|
||||
name = 'Tags'
|
||||
pageRef = '/tags'
|
||||
weight = 30
|
||||
@@ -1,23 +0,0 @@
|
||||
baseURL = 'https://example.org/'
|
||||
languageCode = 'en-us'
|
||||
title = 'My New Hugo Site'
|
||||
|
||||
[[menus.main]]
|
||||
name = 'Home'
|
||||
pageRef = '/'
|
||||
weight = 10
|
||||
|
||||
[[menus.main]]
|
||||
name = 'Posts'
|
||||
pageRef = '/posts'
|
||||
weight = 20
|
||||
|
||||
[[menus.main]]
|
||||
name = 'Tags'
|
||||
pageRef = '/tags'
|
||||
weight = 30
|
||||
|
||||
[module]
|
||||
[module.hugoVersion]
|
||||
extended = false
|
||||
min = "0.116.0"
|
||||
@@ -1,5 +1,5 @@
|
||||
<meta charset="utf-8">
|
||||
<meta name="viewport" content="width=device-width">
|
||||
<meta name="viewport" content="width=device-width, minimum-scale=1.0, initial-scale=1.0">
|
||||
<title>{{ if .IsHome }}{{ site.Title }}{{ else }}{{ printf "%s | %s" .Title site.Title }}{{ end }}</title>
|
||||
{{ partialCached "head/css.html" . }}
|
||||
{{ partialCached "head/js.html" . }}
|
||||
|
||||
@@ -27,12 +27,6 @@ Renders a menu for the given menu ID.
|
||||
{{- else if $page.HasMenuCurrent .Menu .}}
|
||||
{{- $attrs = merge $attrs (dict "class" "ancestor" "aria-current" "true") }}
|
||||
{{- end }}
|
||||
{{- $name := .Name }}
|
||||
{{- with .Identifier }}
|
||||
{{- with T . }}
|
||||
{{- $name = . }}
|
||||
{{- end }}
|
||||
{{- end }}
|
||||
<li>
|
||||
<a
|
||||
{{- range $k, $v := $attrs }}
|
||||
@@ -40,7 +34,7 @@ Renders a menu for the given menu ID.
|
||||
{{- printf " %s=%q" $k $v | safeHTMLAttr }}
|
||||
{{- end }}
|
||||
{{- end -}}
|
||||
>{{ $name }}</a>
|
||||
>{{ or (T .Identifier) .Name | safeHTML }}</a>
|
||||
{{- with .Children }}
|
||||
<ul>
|
||||
{{- partial "inline/menu/walk.html" (dict "page" $page "menuEntries" .) }}
|
||||
|
||||
+12
-10
@@ -18,27 +18,29 @@ package deploy
|
||||
|
||||
import (
|
||||
"context"
|
||||
"net/url"
|
||||
"time"
|
||||
|
||||
"github.com/aws/aws-sdk-go/aws"
|
||||
"github.com/aws/aws-sdk-go/aws/session"
|
||||
"github.com/aws/aws-sdk-go/service/cloudfront"
|
||||
gcaws "gocloud.dev/aws"
|
||||
)
|
||||
|
||||
// InvalidateCloudFront invalidates the CloudFront cache for distributionID.
|
||||
// Uses AWS credentials config from the bucket URL.
|
||||
func InvalidateCloudFront(ctx context.Context, target *Target) error {
|
||||
u, err := url.Parse(target.URL)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
sess, _, err := gcaws.NewSessionFromURLParams(u.Query())
|
||||
// It uses the default AWS credentials from the environment.
|
||||
func InvalidateCloudFront(ctx context.Context, distributionID string) error {
|
||||
// SharedConfigEnable enables loading "shared config (~/.aws/config) and
|
||||
// shared credentials (~/.aws/credentials) files".
|
||||
// See https://docs.aws.amazon.com/sdk-for-go/api/aws/session/ for more
|
||||
// details.
|
||||
// This is the same codepath used by Go CDK when creating an s3 URL.
|
||||
// TODO: Update this to a Go CDK helper once available
|
||||
// (https://github.com/google/go-cloud/issues/2003).
|
||||
sess, err := session.NewSessionWithOptions(session.Options{SharedConfigState: session.SharedConfigEnable})
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
req := &cloudfront.CreateInvalidationInput{
|
||||
DistributionId: aws.String(target.CloudFrontDistributionID),
|
||||
DistributionId: aws.String(distributionID),
|
||||
InvalidationBatch: &cloudfront.InvalidationBatch{
|
||||
CallerReference: aws.String(time.Now().Format("20060102150405")),
|
||||
Paths: &cloudfront.Paths{
|
||||
|
||||
+1
-1
@@ -271,7 +271,7 @@ func (d *Deployer) Deploy(ctx context.Context) error {
|
||||
}
|
||||
} else {
|
||||
d.logger.Println("Invalidating CloudFront CDN...")
|
||||
if err := InvalidateCloudFront(ctx, d.target); err != nil {
|
||||
if err := InvalidateCloudFront(ctx, d.target.CloudFrontDistributionID); err != nil {
|
||||
d.logger.Printf("Failed to invalidate CloudFront CDN: %v\n", err)
|
||||
return err
|
||||
}
|
||||
|
||||
Vendored
+2
-7
@@ -33,6 +33,7 @@ import (
|
||||
// There will be normally only one instance of deps in play
|
||||
// at a given time, i.e. one per Site built.
|
||||
type Deps struct {
|
||||
|
||||
// The logger to use.
|
||||
Log loggers.Logger `json:"-"`
|
||||
|
||||
@@ -76,9 +77,6 @@ type Deps struct {
|
||||
// BuildStartListeners will be notified before a build starts.
|
||||
BuildStartListeners *Listeners
|
||||
|
||||
// BuildEndListeners will be notified after a build finishes.
|
||||
BuildEndListeners *Listeners
|
||||
|
||||
// Resources that gets closed when the build is done or the server shuts down.
|
||||
BuildClosers *Closers
|
||||
|
||||
@@ -99,6 +97,7 @@ func (d Deps) Clone(s page.Site, conf config.AllProvider) (*Deps, error) {
|
||||
}
|
||||
|
||||
return &d, nil
|
||||
|
||||
}
|
||||
|
||||
func (d *Deps) SetTempl(t *tpl.TemplateHandlers) {
|
||||
@@ -133,10 +132,6 @@ func (d *Deps) Init() error {
|
||||
d.BuildStartListeners = &Listeners{}
|
||||
}
|
||||
|
||||
if d.BuildEndListeners == nil {
|
||||
d.BuildEndListeners = &Listeners{}
|
||||
}
|
||||
|
||||
if d.BuildClosers == nil {
|
||||
d.BuildClosers = &Closers{}
|
||||
}
|
||||
|
||||
@@ -12,18 +12,6 @@
|
||||
color: white;
|
||||
}
|
||||
|
||||
.prose-glossary h3 {
|
||||
margin-top: 0;
|
||||
font-size: 1.125rem;
|
||||
}
|
||||
|
||||
.prose-glossary h3:first-of-type {
|
||||
margin-top: 3em;
|
||||
}
|
||||
|
||||
.prose-glossary h3 ~ p {
|
||||
margin: 0.5em 0 2em 0;
|
||||
}
|
||||
|
||||
body {
|
||||
|
||||
|
||||
+4
-33
@@ -1,8 +1,5 @@
|
||||
.facebook,
|
||||
.twitter,
|
||||
.instagram,
|
||||
.youtube {
|
||||
fill: #bababa;
|
||||
.facebook, .twitter, .instagram, .youtube {
|
||||
fill: #BABABA;
|
||||
}
|
||||
.facebook:hover {
|
||||
fill: #3b5998;
|
||||
@@ -13,9 +10,10 @@
|
||||
}
|
||||
|
||||
.twitter:hover {
|
||||
fill: #bababa;
|
||||
fill: #BABABA;
|
||||
}
|
||||
|
||||
|
||||
.instagram:hover {
|
||||
fill: #e95950;
|
||||
}
|
||||
@@ -23,30 +21,3 @@
|
||||
.youtube:hover {
|
||||
fill: #bb0000;
|
||||
}
|
||||
|
||||
.mstdn {
|
||||
display: inline-block;
|
||||
background-color: #282c37;
|
||||
color: #d9e1e8;
|
||||
text-decoration: none;
|
||||
padding: 4px 10px 4px 30px;
|
||||
border-radius: 4px;
|
||||
font-size: 16px;
|
||||
background-image: url("data:image/svg+xml;charset=utf8,%3Csvg%20xmlns%3D%22http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg%22%20width%3D%2261.076954mm%22%20height%3D%2265.47831mm%22%20viewBox%3D%220%200%20216.4144%20232.00976%22%3E%3Cpath%20d%3D%22M211.80734%20139.0875c-3.18125%2016.36625-28.4925%2034.2775-57.5625%2037.74875-15.15875%201.80875-30.08375%203.47125-45.99875%202.74125-26.0275-1.1925-46.565-6.2125-46.565-6.2125%200%202.53375.15625%204.94625.46875%207.2025%203.38375%2025.68625%2025.47%2027.225%2046.39125%2027.9425%2021.11625.7225%2039.91875-5.20625%2039.91875-5.20625l.8675%2019.09s-14.77%207.93125-41.08125%209.39c-14.50875.7975-32.52375-.365-53.50625-5.91875C9.23234%20213.82%201.40609%20165.31125.20859%20116.09125c-.365-14.61375-.14-28.39375-.14-39.91875%200-50.33%2032.97625-65.0825%2032.97625-65.0825C49.67234%203.45375%2078.20359.2425%20107.86484%200h.72875c29.66125.2425%2058.21125%203.45375%2074.8375%2011.09%200%200%2032.975%2014.7525%2032.975%2065.0825%200%200%20.41375%2037.13375-4.59875%2062.915%22%20fill%3D%22%233088d4%22%2F%3E%3Cpath%20d%3D%22M177.50984%2080.077v60.94125h-24.14375v-59.15c0-12.46875-5.24625-18.7975-15.74-18.7975-11.6025%200-17.4175%207.5075-17.4175%2022.3525v32.37625H96.20734V85.42325c0-14.845-5.81625-22.3525-17.41875-22.3525-10.49375%200-15.74%206.32875-15.74%2018.7975v59.15H38.90484V80.077c0-12.455%203.17125-22.3525%209.54125-29.675%206.56875-7.3225%2015.17125-11.07625%2025.85-11.07625%2012.355%200%2021.71125%204.74875%2027.8975%2014.2475l6.01375%2010.08125%206.015-10.08125c6.185-9.49875%2015.54125-14.2475%2027.8975-14.2475%2010.6775%200%2019.28%203.75375%2025.85%2011.07625%206.36875%207.3225%209.54%2017.22%209.54%2029.675%22%20fill%3D%22%23fff%22%2F%3E%3C%2Fsvg%3E");
|
||||
background-size: 16px;
|
||||
background-repeat: no-repeat;
|
||||
background-position: top 50% left 8px;
|
||||
transition: all 0.5s;
|
||||
}
|
||||
.mstdn:hover {
|
||||
background-color: #484c56;
|
||||
}
|
||||
|
||||
.mstdn > span {
|
||||
color: #9baec8;
|
||||
font-size: 12px;
|
||||
padding-left: 3px;
|
||||
}
|
||||
.mstdn > span:before {
|
||||
content: "@";
|
||||
}
|
||||
|
||||
@@ -4926,16 +4926,6 @@ pre {
|
||||
background: #0594CB; /* WebKit/Blink Browsers */
|
||||
color: white;
|
||||
}
|
||||
.prose-glossary h3 {
|
||||
margin-top: 0;
|
||||
font-size: 1.125rem;
|
||||
}
|
||||
.prose-glossary h3:first-of-type {
|
||||
margin-top: 3em;
|
||||
}
|
||||
.prose-glossary h3 ~ p {
|
||||
margin: 0.5em 0 2em 0;
|
||||
}
|
||||
body {
|
||||
|
||||
line-height: 1.45;
|
||||
@@ -5113,11 +5103,8 @@ code, .code, pre code, .highlight pre {
|
||||
-webkit-transition: opacity .15s ease-in;
|
||||
transition: opacity .15s ease-in;
|
||||
}
|
||||
.facebook,
|
||||
.twitter,
|
||||
.instagram,
|
||||
.youtube {
|
||||
fill: #bababa;
|
||||
.facebook, .twitter, .instagram, .youtube {
|
||||
fill: #BABABA;
|
||||
}
|
||||
.facebook:hover {
|
||||
fill: #3b5998;
|
||||
@@ -5126,7 +5113,7 @@ code, .code, pre code, .highlight pre {
|
||||
fill: #55acee;
|
||||
}
|
||||
.twitter:hover {
|
||||
fill: #bababa;
|
||||
fill: #BABABA;
|
||||
}
|
||||
.instagram:hover {
|
||||
fill: #e95950;
|
||||
@@ -5134,32 +5121,6 @@ code, .code, pre code, .highlight pre {
|
||||
.youtube:hover {
|
||||
fill: #bb0000;
|
||||
}
|
||||
.mstdn {
|
||||
display: inline-block;
|
||||
background-color: #282c37;
|
||||
color: #d9e1e8;
|
||||
text-decoration: none;
|
||||
padding: 4px 10px 4px 30px;
|
||||
border-radius: 4px;
|
||||
font-size: 16px;
|
||||
background-image: url("data:image/svg+xml;charset=utf8,%3Csvg%20xmlns%3D%22http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg%22%20width%3D%2261.076954mm%22%20height%3D%2265.47831mm%22%20viewBox%3D%220%200%20216.4144%20232.00976%22%3E%3Cpath%20d%3D%22M211.80734%20139.0875c-3.18125%2016.36625-28.4925%2034.2775-57.5625%2037.74875-15.15875%201.80875-30.08375%203.47125-45.99875%202.74125-26.0275-1.1925-46.565-6.2125-46.565-6.2125%200%202.53375.15625%204.94625.46875%207.2025%203.38375%2025.68625%2025.47%2027.225%2046.39125%2027.9425%2021.11625.7225%2039.91875-5.20625%2039.91875-5.20625l.8675%2019.09s-14.77%207.93125-41.08125%209.39c-14.50875.7975-32.52375-.365-53.50625-5.91875C9.23234%20213.82%201.40609%20165.31125.20859%20116.09125c-.365-14.61375-.14-28.39375-.14-39.91875%200-50.33%2032.97625-65.0825%2032.97625-65.0825C49.67234%203.45375%2078.20359.2425%20107.86484%200h.72875c29.66125.2425%2058.21125%203.45375%2074.8375%2011.09%200%200%2032.975%2014.7525%2032.975%2065.0825%200%200%20.41375%2037.13375-4.59875%2062.915%22%20fill%3D%22%233088d4%22%2F%3E%3Cpath%20d%3D%22M177.50984%2080.077v60.94125h-24.14375v-59.15c0-12.46875-5.24625-18.7975-15.74-18.7975-11.6025%200-17.4175%207.5075-17.4175%2022.3525v32.37625H96.20734V85.42325c0-14.845-5.81625-22.3525-17.41875-22.3525-10.49375%200-15.74%206.32875-15.74%2018.7975v59.15H38.90484V80.077c0-12.455%203.17125-22.3525%209.54125-29.675%206.56875-7.3225%2015.17125-11.07625%2025.85-11.07625%2012.355%200%2021.71125%204.74875%2027.8975%2014.2475l6.01375%2010.08125%206.015-10.08125c6.185-9.49875%2015.54125-14.2475%2027.8975-14.2475%2010.6775%200%2019.28%203.75375%2025.85%2011.07625%206.36875%207.3225%209.54%2017.22%209.54%2029.675%22%20fill%3D%22%23fff%22%2F%3E%3C%2Fsvg%3E");
|
||||
background-size: 16px;
|
||||
background-repeat: no-repeat;
|
||||
background-position: top 50% left 8px;
|
||||
-webkit-transition: all 0.5s;
|
||||
transition: all 0.5s;
|
||||
}
|
||||
.mstdn:hover {
|
||||
background-color: #484c56;
|
||||
}
|
||||
.mstdn > span {
|
||||
color: #9baec8;
|
||||
font-size: 12px;
|
||||
padding-left: 3px;
|
||||
}
|
||||
.mstdn > span:before {
|
||||
content: "@";
|
||||
}
|
||||
@media (min-width: 75em) {
|
||||
|
||||
[data-scrolldir="down"] .sticky {
|
||||
|
||||
@@ -31,7 +31,7 @@
|
||||
<img src="{{ . }}" alt="Featured Image for {{ $.Title }}" class="mw-100">
|
||||
{{ end }}
|
||||
|
||||
<div class="prose prose-{{ .Type }}" id="prose">
|
||||
<div class="prose" id="prose">
|
||||
{{- partial "docs/functions-signature.html" . -}}
|
||||
{{ .Content }}
|
||||
</div>
|
||||
|
||||
+2
-2
@@ -30,9 +30,9 @@
|
||||
{{- partial "site-search.html" . -}}
|
||||
</div>
|
||||
|
||||
<div class="absolute mt1 mt2-l pr3 right-0 top-0 flex items-start">
|
||||
<span class="absolute mt1 mt2-l pr3 right-0 top-0">
|
||||
{{- partialCached "social-follow.html" . -}}
|
||||
</div>
|
||||
</span>
|
||||
|
||||
</div>
|
||||
</nav>
|
||||
|
||||
+4
-6
@@ -1,9 +1,7 @@
|
||||
{{/*
|
||||
Disable Twitter for now as we lost access to the account.
|
||||
with .Site.Social.twitter }}
|
||||
<!-- TODO: Add follow intents where available TODO: Revisit color and hover color -->
|
||||
{{ with .Site.Social.twitter }}
|
||||
<a href="https://twitter.com/intent/follow?screen_name={{ . }}" title="Follow on Twitter" class="link-transition twitter link dib z-999 pt3 pt0-l mr2">
|
||||
{{ partial "svg/twitter.svg" (dict "size" "32px") }}
|
||||
</a>
|
||||
{{ end */}}
|
||||
<a rel="me" class="mstdn mr3" href="https://fosstodon.org/@gohugoio" target="_blank">gohugoio</a>
|
||||
<a class="github-button needs-js link primary-color-dark" href="https://github.com/gohugoio/hugo" data-size="large" data-show-count="false" aria-label="Star gohugoio/hugo on GitHub">Star</a>
|
||||
{{ end }}
|
||||
<a class="github-button needs-js link primary-color-dark" href="https://github.com/gohugoio/hugo" data-size="large" data-show-count="false" aria-label="Star gohugoio/hugo on GitHub">Star</a>
|
||||
|
||||
@@ -1 +1 @@
|
||||
# github.com/gohugoio/gohugoioTheme v0.0.0-20230927165800-342e2c850f18
|
||||
# github.com/gohugoio/gohugoioTheme v0.0.0-20230630055807-9874cd863bc5
|
||||
|
||||
@@ -1,14 +1,11 @@
|
||||
---
|
||||
title: {{ replace .File.ContentBaseName "-" " " | title }}
|
||||
description:
|
||||
title: {{ replace .Name "-" " " | title }}
|
||||
description: ""
|
||||
signature: []
|
||||
categories: [functions]
|
||||
keywords: []
|
||||
menu:
|
||||
docs:
|
||||
parent: functions
|
||||
function:
|
||||
aliases: []
|
||||
returnType:
|
||||
signatures: []
|
||||
relatedFunctions: []
|
||||
relatedfuncs: []
|
||||
---
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
---
|
||||
title: {{ replace .File.ContentBaseName "-" " " | title }}
|
||||
description:
|
||||
title: "{{ replace .Name "-" " " | title }}"
|
||||
description: ""
|
||||
date: {{ .Date }}
|
||||
---
|
||||
|
||||
|
||||
@@ -1,9 +1,9 @@
|
||||
---
|
||||
|
||||
title: {{ replace .File.ContentBaseName "-" " " | title }}
|
||||
title: {{ replace .Name "-" " " | title }}
|
||||
date: {{ now.Format "2006-01-02" }}
|
||||
|
||||
description: A short description of this page.
|
||||
description: "A short description of this page."
|
||||
|
||||
# The URL to the site on the internet.
|
||||
siteURL: https://gohugo.io/
|
||||
@@ -34,3 +34,4 @@ bio.md
|
||||
|
||||
featured.png
|
||||
: A reasonably sized screenshot of your website. It can be named anything, but the name must start with "featured". The sample image is `1500x750` (2:1 aspect ratio).
|
||||
|
||||
|
||||
@@ -8,6 +8,8 @@ ghrepo = "https://github.com/gohugoio/hugoDocs/"
|
||||
github_repo = "https://github.com/gohugoio/hugo/issues/new"
|
||||
### Edit content repo (set to automatically enter "edit" mode; this is good for "improve this page" links)
|
||||
ghdocsrepo = "https://github.com/gohugoio/hugoDocs/tree/master/docs"
|
||||
## Gitter URL
|
||||
gitter = "https://gitter.im/spf13/hugo"
|
||||
## Discuss Forum URL
|
||||
forum = "https://discourse.gohugo.io/"
|
||||
## Google Tag Manager
|
||||
@@ -18,7 +20,4 @@ images = ["images/gohugoio-card.png"]
|
||||
|
||||
flex_box_interior_classes = "flex-auto w-100 w-40-l mr3 mb3 bg-white ba b--moon-gray nested-copy-line-height"
|
||||
|
||||
#sidebar_direction = "sidebar_left"
|
||||
|
||||
[social]
|
||||
twitter = "GoHugoIO"
|
||||
#sidebar_direction = "sidebar_left"
|
||||
@@ -131,4 +131,4 @@ enableDNT
|
||||
: Enabling this for the vimeo shortcode, the Vimeo player will be blocked from tracking any session data, including all cookies and stats.
|
||||
|
||||
simple
|
||||
: If simple mode is enabled, the video thumbnail is fetched from Vimeo's servers and it is overlaid with a play button. If the user clicks to play the video, it will open in a new tab directly on Vimeo's website.
|
||||
: If simple mode is enabled, the video thumbnail is fetched from Vimeo's servers and it is overlayed with a play button. If the user clicks to play the video, it will open in a new tab directly on Vimeo's website.
|
||||
|
||||
Binary file not shown.
|
After Width: | Height: | Size: 83 KiB |
@@ -36,13 +36,13 @@ Hugo is for people building a blog, a company site, a portfolio site, documentat
|
||||
[@spf13]: https://twitter.com/spf13
|
||||
[Amazon S3]: https://aws.amazon.com/s3/
|
||||
[Azure]: https://docs.microsoft.com/en-us/azure/storage/blobs/storage-blob-static-website
|
||||
[CloudFront]: https://aws.amazon.com/cloudfront/
|
||||
[CloudFront]: https://aws.amazon.com/cloudfront/ "Amazon CloudFront"
|
||||
[DreamHost]: https://www.dreamhost.com/
|
||||
[Firebase]: https://firebase.google.com/docs/hosting/
|
||||
[Firebase]: https://firebase.google.com/docs/hosting/ "Firebase static hosting"
|
||||
[GitHub Pages]: https://pages.github.com/
|
||||
[GitLab Pages]: https://about.gitlab.com/features/pages/
|
||||
[Go language]: https://go.dev/
|
||||
[GoDaddy]: https://www.godaddy.com/
|
||||
[GoDaddy]: https://www.godaddy.com/ "GoDaddy.com Hosting"
|
||||
[Google Cloud Storage]: https://cloud.google.com/storage/
|
||||
[Heroku]: https://www.heroku.com/
|
||||
[Jekyll]: https://jekyllrb.com/
|
||||
|
||||
@@ -21,7 +21,7 @@ hugo gen chromastyles [flags] [args]
|
||||
|
||||
```
|
||||
-h, --help help for chromastyles
|
||||
--highlightStyle string style used for highlighting lines (see https://github.com/alecthomas/chroma)
|
||||
--highlightStyle string style used for highlighting lines (see https://github.com/alecthomas/chroma) (default "bg:#ffffcc")
|
||||
--linesStyle string style used for line numbers (see https://github.com/alecthomas/chroma)
|
||||
--style string highlighter style (see https://xyproto.github.io/splash/docs/) (default "friendly")
|
||||
```
|
||||
|
||||
@@ -12,7 +12,7 @@ Generate Markdown documentation for the Hugo CLI.
|
||||
Generate Markdown documentation for the Hugo CLI.
|
||||
This command is, mostly, used to create up-to-date documentation
|
||||
of Hugo's command-line interface for https://gohugo.io/.
|
||||
|
||||
|
||||
It creates one Markdown file per command with front matter suitable
|
||||
for rendering in Hugo.
|
||||
|
||||
|
||||
@@ -22,12 +22,7 @@ Install a specific version:
|
||||
|
||||
hugo mod get github.com/gohugoio/testshortcodes@v0.3.0
|
||||
|
||||
Install the latest versions of all direct module dependencies:
|
||||
|
||||
hugo mod get
|
||||
hugo mod get ./... (recursive)
|
||||
|
||||
Install the latest versions of all module dependencies (direct and indirect):
|
||||
Install the latest versions of all module dependencies:
|
||||
|
||||
hugo mod get -u
|
||||
hugo mod get -u ./... (recursive)
|
||||
|
||||
@@ -30,6 +30,7 @@ hugo new content [path] [flags]
|
||||
-c, --contentDir string filesystem path to content directory
|
||||
--editor string edit new content with this editor, if provided
|
||||
-f, --force overwrite file if it already exists
|
||||
--format string preferred file format (toml, yaml or json) (default "toml")
|
||||
-h, --help help for content
|
||||
-k, --kind string content type to create
|
||||
-t, --theme strings themes to use (located in /themes/THEMENAME/)
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
---
|
||||
title: Archetypes
|
||||
description: An archetype is a template for new content.
|
||||
description: Archetypes are templates used when creating new content.
|
||||
keywords: [archetypes,generators,metadata,front matter]
|
||||
categories: [content management]
|
||||
menu:
|
||||
@@ -13,173 +13,78 @@ weight: 140
|
||||
aliases: [/content/archetypes/]
|
||||
---
|
||||
|
||||
## Overview
|
||||
## What are archetypes?
|
||||
|
||||
A content file consists of [front matter] and markup. The markup is typically markdown, but Hugo also supports other [content formats]. Front matter can be TOML, YAML, or JSON.
|
||||
|
||||
The `hugo new content` command creates a new file in the `content` directory, using an archetype as a template. This is the default archetype:
|
||||
|
||||
{{< code-toggle file="archetypes/default.md" copy=false fm=true >}}
|
||||
title = '{{ replace .File.ContentBaseName `-` ` ` | title }}'
|
||||
date = '{{ .Date }}'
|
||||
draft = true
|
||||
{{< /code-toggle >}}
|
||||
|
||||
When you create new content, Hugo evaluates the [template actions] within the archetype. For example:
|
||||
|
||||
```text
|
||||
hugo new content posts/my-first-post.md
|
||||
```
|
||||
|
||||
With the default archetype shown above, Hugo creates this content file:
|
||||
|
||||
{{< code-toggle file="content/posts/my-first-post.md" copy=false fm=true >}}
|
||||
title = 'My First Post'
|
||||
date = '2023-08-24T11:49:46-07:00'
|
||||
draft = true
|
||||
{{< /code-toggle >}}
|
||||
|
||||
You can create an archetype for one or more [content types]. For example, use one archetype for posts, and use the default archetype for everything else:
|
||||
|
||||
```text
|
||||
archetypes/
|
||||
├── default.md
|
||||
└── posts.md
|
||||
```
|
||||
|
||||
## Lookup order
|
||||
|
||||
Hugo looks for archetypes in the `archetypes` directory in the root of your project, falling back to the `archetypes` directory in themes or installed modules. An archetype for a specific content type takes precedence over the default archetype.
|
||||
|
||||
For example, with this command:
|
||||
|
||||
```text
|
||||
hugo new content posts/my-first-post.md
|
||||
```
|
||||
|
||||
The archetype lookup order is:
|
||||
|
||||
1. archetypes/posts.md
|
||||
1. archetypes/default.md
|
||||
1. themes/my-theme/archetypes/posts.md
|
||||
1. themes/my-theme/archetypes/default.md
|
||||
|
||||
If none of these exists, Hugo uses a built-in default archetype.
|
||||
|
||||
## Functions and context
|
||||
|
||||
You can use any [template function] within an archetype. As shown above, the default archetype uses the [`replace`](/functions/strings/replace) function to replace hyphens with spaces when populating the title in front matter.
|
||||
|
||||
Archetypes receive the following objects and values in [context]:
|
||||
|
||||
- `.Date`
|
||||
- `.Type`
|
||||
- `.Site` (see [details](/variables/site/))
|
||||
- `.File` (see [details](/variables/files/))
|
||||
|
||||
As shown above, the default archetype passes `.File.ContentBaseName` as the argument to the `replace` function when populating the title in front matter.
|
||||
|
||||
## Include content
|
||||
|
||||
Although typically used as a front matter template, you can also use an archetype to populate content.
|
||||
|
||||
For example, in a documentation site you might have a section (content type) for functions. Every page within this section should follow the same format: a brief description, the function signature, examples, and notes. We can pre-populate the page to remind content authors of the standard format.
|
||||
**Archetypes** are content template files in the [archetypes directory] of your project that contain preconfigured [front matter] and possibly also a content disposition for your website's [content types]. These will be used when you run `hugo new`.
|
||||
|
||||
|
||||
{{< code file="archetypes/functions.md" copy=false >}}
|
||||
---
|
||||
date: '{{ .Date }}'
|
||||
draft: true
|
||||
title: '{{ replace .File.ContentBaseName `-` ` ` | title }}'
|
||||
---
|
||||
The `hugo new` uses the `content-section` to find the most suitable archetype template in your project. If your project does not contain any archetype files, it will also look in the theme.
|
||||
|
||||
A brief description of what the function does, using simple present tense in the third person singular form. For example:
|
||||
|
||||
`someFunction` returns the string `s` repeated `n` times.
|
||||
|
||||
## Signature
|
||||
|
||||
```text
|
||||
func someFunction(s string, n int) string
|
||||
```
|
||||
|
||||
## Examples
|
||||
|
||||
One or more practical examples, each within a fenced code block.
|
||||
|
||||
## Notes
|
||||
|
||||
Additional information to clarify as needed.
|
||||
{{< code file="archetype-example.sh" >}}
|
||||
hugo new posts/my-first-post.md
|
||||
{{< /code >}}
|
||||
|
||||
Although you can include [template actions] within the content body, remember that Hugo evaluates these once---at the time of content creation. In most cases, place template actions in a [template] where Hugo evaluates the actions every time you [build](/getting-started/glossary/#build) the site.
|
||||
The above will create a new content file in `content/posts/my-first-post.md` using the first archetype file found of these:
|
||||
|
||||
## Leaf bundles
|
||||
1. `archetypes/posts.md`
|
||||
2. `archetypes/default.md`
|
||||
3. `themes/my-theme/archetypes/posts.md`
|
||||
4. `themes/my-theme/archetypes/default.md`
|
||||
|
||||
You can also create archetypes for [leaf bundles](/getting-started/glossary/#leaf-bundle).
|
||||
The last two list items are only applicable if you use a theme and it uses the `my-theme` theme name as an example.
|
||||
|
||||
For example, in a photography site you might have a section (content type) for galleries. Each gallery is leaf bundle with content and images.
|
||||
## Create a new archetype template
|
||||
|
||||
Create an archetype for galleries:
|
||||
A fictional example for the section `newsletter` and the archetype file `archetypes/newsletter.md`. Create a new file in `archetypes/newsletter.md` and open it in a text editor.
|
||||
|
||||
```text
|
||||
archetypes/
|
||||
├── galleries/
|
||||
│ ├── images/
|
||||
│ │ └── .gitkeep
|
||||
│ └── index.md <-- same format as default.md
|
||||
└── default.md
|
||||
{{< code file="archetypes/newsletter.md" >}}
|
||||
---
|
||||
title: "{{ replace .Name "-" " " | title }}"
|
||||
date: {{ .Date }}
|
||||
draft: true
|
||||
---
|
||||
|
||||
**Insert Lead paragraph here.**
|
||||
|
||||
## New cool posts
|
||||
|
||||
{{ range first 10 ( where .Site.RegularPages "Type" "cool" ) }}
|
||||
* {{ .Title }}
|
||||
{{ end }}
|
||||
{{< /code >}}
|
||||
|
||||
When you create a new newsletter with:
|
||||
|
||||
```bash
|
||||
hugo new newsletter/the-latest-cool.stuff.md
|
||||
```
|
||||
|
||||
Subdirectories within an archetype must contain at least one file. Without a file, Hugo will not create the subdirectory when you create new content. The name and size of the file are irrelevant. The example above includes a `.gitkeep` file, an empty file commonly used to preserve otherwise empty directories in a Git repository.
|
||||
It will create a new newsletter type of content file based on the archetype template.
|
||||
|
||||
**Note:** the site will only be built if the `.Site` is in use in the archetype file, and this can be time consuming for big sites.
|
||||
|
||||
To create a new gallery:
|
||||
```text
|
||||
hugo new galleries/bryce-canyon
|
||||
```
|
||||
The above _newsletter type archetype_ illustrates the possibilities: The full Hugo `.Site` and all of Hugo's template funcs can be used in the archetype file.
|
||||
|
||||
This produces:
|
||||
## Directory based archetypes
|
||||
|
||||
```text
|
||||
content/
|
||||
├── galleries/
|
||||
│ └── bryce-canyon/
|
||||
│ ├── images/
|
||||
│ │ └── .gitkeep
|
||||
│ └── index.md
|
||||
└── _index.md
|
||||
```
|
||||
Since Hugo `0.49` you can use complete directories as archetype templates. Given this archetype directory:
|
||||
|
||||
## Use alternate archetype
|
||||
|
||||
Use the `--kind` command line flag to specify an alternate archetype when creating content.
|
||||
|
||||
For example, let's say your site has two sections: articles and tutorials. Create an archetype for each content type:
|
||||
|
||||
```text
|
||||
archetypes/
|
||||
├── articles.md
|
||||
```bash
|
||||
archetypes
|
||||
├── default.md
|
||||
└── tutorials.md
|
||||
└── post-bundle
|
||||
├── bio.md
|
||||
├── images
|
||||
│ └── featured.jpg
|
||||
└── index.md
|
||||
```
|
||||
|
||||
To create an article using the articles archetype:
|
||||
|
||||
```text
|
||||
hugo new content articles/something.md
|
||||
```bash
|
||||
hugo new --kind post-bundle posts/my-post
|
||||
```
|
||||
|
||||
To create an article using the tutorials archetype:
|
||||
Will create a new folder in `/content/posts/my-post` with the same set of files as in the `post-bundle` archetypes folder. All content files (`index.md` etc.) can contain template logic, and will receive the correct `.Site` for the content's language.
|
||||
|
||||
```text
|
||||
hugo new content --kind tutorials articles/something.md
|
||||
```
|
||||
|
||||
[content formats]: /getting-started/glossary/#content-format
|
||||
[content types]: /getting-started/glossary/#content-type
|
||||
[context]: /getting-started/glossary/#context
|
||||
[front matter]: /getting-started/glossary/#front-matter
|
||||
[template actions]: /getting-started/glossary/#template-action
|
||||
[template]: /getting-started/glossary/#template
|
||||
[template function]: /getting-started/glossary/#function
|
||||
[archetypes directory]: /getting-started/directory-structure/
|
||||
[content types]: /content-management/types/
|
||||
[front matter]: /content-management/front-matter/
|
||||
|
||||
@@ -24,9 +24,8 @@ Hugo comes with all the code you need to load Disqus into your templates. Before
|
||||
|
||||
Disqus comments require you set a single value in your [site's configuration file][configuration] like so:
|
||||
|
||||
{{< code-toggle file="hugo" >}}
|
||||
[services.disqus]
|
||||
shortname = 'your-disqus-shortname'
|
||||
{{< code-toggle copy=false >}}
|
||||
disqusShortname = "yourDisqusShortname"
|
||||
{{</ code-toggle >}}
|
||||
|
||||
For many websites, this is enough configuration. However, you also have the option to set the following in the [front matter] of a single content file:
|
||||
@@ -49,7 +48,6 @@ These are some alternatives to Disqus:
|
||||
|
||||
* [Cactus Comments](https://cactus.chat/docs/integrations/hugo/) (Open Source, Matrix appservice, Docker install)
|
||||
* [Commento](https://commento.io/) (Open Source, available as a service, local install, or docker image)
|
||||
* [Giscus](https://giscus.app/) (Open source, comments system powered by GitHub Discussions)
|
||||
* [Graph Comment](https://graphcomment.com/)
|
||||
* [Hyvor Talk](https://talk.hyvor.com/) (Available as a service)
|
||||
* [IntenseDebate](https://intensedebate.com/)
|
||||
|
||||
@@ -49,7 +49,7 @@ Hugo passes reasonable default arguments to these external helpers by default:
|
||||
Because additional formats are external commands, generation performance will rely heavily on the performance of the external tool you are using. As this feature is still in its infancy, feedback is welcome.
|
||||
{{% /note %}}
|
||||
|
||||
### Asciidoctor
|
||||
### External helper Asciidoctor
|
||||
|
||||
The Asciidoctor community offers a wide set of tools for the AsciiDoc format that can be installed additionally to Hugo.
|
||||
[See the Asciidoctor docs for installation instructions](https://asciidoctor.org/docs/install-toolchain/). Make sure that also all
|
||||
@@ -59,9 +59,52 @@ optional extensions like `asciidoctor-diagram` or `asciidoctor-html5s` are insta
|
||||
External `asciidoctor` command requires Hugo rendering to _disk_ to a specific destination directory. It is required to run Hugo with the command option `--destination`.
|
||||
{{% /note %}}
|
||||
|
||||
Some Asciidoctor parameters can be customized in Hugo. See [details].
|
||||
Some [Asciidoctor](https://asciidoctor.org/man/asciidoctor/) parameters can be customized in Hugo:
|
||||
|
||||
[details]: /getting-started/configuration-markup/#asciidoc
|
||||
Parameter | Comment
|
||||
--- | ---
|
||||
backend | Don't change this unless you know what you are doing.
|
||||
doctype | Currently, the only document type supported in Hugo is `article`.
|
||||
extensions | Possible extensions are `asciidoctor-html5s`, `asciidoctor-bibtex`, `asciidoctor-diagram`, `asciidoctor-interdoc-reftext`, `asciidoctor-katex`, `asciidoctor-latex`, `asciidoctor-mathematical`, `asciidoctor-question`, `asciidoctor-rouge`.
|
||||
attributes | Variables to be referenced in your AsciiDoc file. This is a list of variable name/value maps. See [Asciidoctor's attributes](https://asciidoctor.org/docs/asciidoc-syntax-quick-reference/#attributes-and-substitutions).
|
||||
noHeaderOrFooter | Output an embeddable document, which excludes the header, the footer, and everything outside the body of the document. Don't change this unless you know what you are doing.
|
||||
safeMode | Safe mode level `unsafe`, `safe`, `server` or `secure`. Don't change this unless you know what you are doing.
|
||||
sectionNumbers | Auto-number section titles.
|
||||
verbose | Verbosely print processing information and configuration file checks to stderr.
|
||||
trace | Include backtrace information on errors.
|
||||
failureLevel | The minimum logging level that triggers a non-zero exit code (failure).
|
||||
|
||||
Hugo provides additional settings that don't map directly to Asciidoctor's CLI options:
|
||||
|
||||
workingFolderCurrent
|
||||
: Sets the working directory to be the same as that of the AsciiDoc file being processed, so that [include](https://asciidoctor.org/docs/asciidoc-syntax-quick-reference/#include-files) will work with relative paths. This setting uses the `asciidoctor` cli parameter `--base-dir` and attribute `outdir=`. For rendering diagrams with [asciidoctor-diagram](https://asciidoctor.org/docs/asciidoctor-diagram/), `workingFolderCurrent` must be set to `true`.
|
||||
|
||||
preserveTOC
|
||||
: By default, Hugo removes the table of contents generated by Asciidoctor and provides it through the built-in variable [`.TableOfContents`](/content-management/toc/) to enable further customization and better integration with the various Hugo themes. This option can be set to `true` to preserve Asciidoctor's TOC in the generated page.
|
||||
|
||||
Below are all the AsciiDoc related settings in Hugo with their default values:
|
||||
|
||||
{{< code-toggle config="markup.asciidocExt" />}}
|
||||
|
||||
Notice that for security concerns only extensions that do not have path separators (either `\`, `/` or `.`) are allowed. That means that extensions can only be invoked if they are in one's ruby's `$LOAD_PATH` (ie. most likely, the extension has been installed by the user). Any extension declared relative to the website's path will not be accepted.
|
||||
|
||||
Example of how to set extensions and attributes:
|
||||
|
||||
```yml
|
||||
[markup.asciidocExt]
|
||||
extensions = ["asciidoctor-html5s", "asciidoctor-diagram"]
|
||||
workingFolderCurrent = true
|
||||
[markup.asciidocExt.attributes]
|
||||
my-base-url = "https://example.com/"
|
||||
my-attribute-name = "my value"
|
||||
```
|
||||
|
||||
In a complex Asciidoctor environment it is sometimes helpful to debug the exact call to your external helper with all
|
||||
parameters. Run Hugo with `-v`. You will get an output like
|
||||
|
||||
```txt
|
||||
INFO 2019/12/22 09:08:48 Rendering book-as-pdf.adoc with C:\Ruby26-x64\bin\asciidoctor.bat using asciidoc args [--no-header-footer -r asciidoctor-html5s -b html5s -r asciidoctor-diagram --base-dir D:\prototypes\hugo_asciidoc_ddd\docs -a outdir=D:\prototypes\hugo_asciidoc_ddd\build -] ...
|
||||
```
|
||||
|
||||
## Learn markdown
|
||||
|
||||
@@ -72,6 +115,7 @@ Markdown syntax is simple enough to learn in a single sitting. The following are
|
||||
* [Markdown Tutorial (Interactive), Garen Torikian][mdtutorial]
|
||||
* [The Markdown Guide, Matt Cone][mdguide]
|
||||
|
||||
[`emojify` function]: /functions/emojify/
|
||||
[ascii]: https://asciidoctor.org/
|
||||
[config]: /getting-started/configuration/
|
||||
[developer tools]: /tools/
|
||||
|
||||
@@ -12,9 +12,9 @@ weight: 90
|
||||
---
|
||||
## Image resources
|
||||
|
||||
To process an image you must access the file as a page resource, global resource, or remote resource.
|
||||
To process an image, you must access the image as either a page resource or a global resource.
|
||||
|
||||
### Page resource
|
||||
### Page resources
|
||||
|
||||
A page resource is a file within a [page bundle]. A page bundle is a directory with an `index.md` or `_index.md` file at its root.
|
||||
|
||||
@@ -26,15 +26,13 @@ content/
|
||||
└── sunset.jpg <-- page resource
|
||||
```
|
||||
|
||||
To access an image as a page resource:
|
||||
### Global resources
|
||||
|
||||
```go-html-template
|
||||
{{ $image := .Resources.Get "sunset.jpg" }}
|
||||
```
|
||||
A global resource is a file:
|
||||
|
||||
### Global resource
|
||||
|
||||
A global resource is a file within the `assets` directory, or within any directory [mounted] to the `assets` directory.
|
||||
- Within the `assets` directory, or
|
||||
- Within any directory [mounted] to the `assets` directory, or
|
||||
- Located on a remote server accessible via `http` or `https`
|
||||
|
||||
```text
|
||||
assets/
|
||||
@@ -42,15 +40,13 @@ assets/
|
||||
└── sunset.jpg <-- global resource
|
||||
```
|
||||
|
||||
To access an image as a global resource:
|
||||
To access a local image as a global resource:
|
||||
|
||||
```go-html-template
|
||||
{{ $image := resources.Get "images/sunset.jpg" }}
|
||||
```
|
||||
|
||||
### Remote resource
|
||||
|
||||
A remote resource is a file on a remote server, accessible via http or https. To access an image as a remote resource:
|
||||
To access a remote image as a global resource:
|
||||
|
||||
```go-html-template
|
||||
{{ $image := resources.GetRemote "https://gohugo.io/img/hugo-logo.png" }}
|
||||
@@ -84,62 +80,14 @@ Example 3: A more concise way to skip image rendering if the resource is not fou
|
||||
{{ end }}
|
||||
```
|
||||
|
||||
Example 4: Skips rendering if there's problem accessing a remote resource.
|
||||
|
||||
```go-html-template
|
||||
{{ $u := "https://gohugo.io/img/hugo-logo.png" }}
|
||||
{{ with resources.GetRemote $u }}
|
||||
{{ with .Err }}
|
||||
{{ errorf "%s" . }}
|
||||
{{ else }}
|
||||
<img src="{{ .RelPermalink }}" width="{{ .Width }}" height="{{ .Height }}">
|
||||
{{ end }}
|
||||
{{ else }}
|
||||
{{ errorf "Unable to get remote resource %q" $u }}
|
||||
{{ end }}
|
||||
```
|
||||
|
||||
## Image processing methods
|
||||
|
||||
The `image` resource implements the [`Process`], [`Resize`], [`Fit`], [`Fill`], [`Crop`], [`Filter`], [`Colors`] and [`Exif`] methods.
|
||||
The `image` resource implements the [`Resize`], [`Fit`], [`Fill`], [`Crop`], [`Filter`], [`Colors`] and [`Exif`] methods.
|
||||
|
||||
{{% note %}}
|
||||
Metadata (EXIF, IPTC, XMP, etc.) is not preserved during image transformation. Use the [`Exif`] method with the _original_ image to extract EXIF metadata from JPEG or TIFF images.
|
||||
{{% /note %}}
|
||||
|
||||
### Process
|
||||
|
||||
{{< new-in "0.119.0" >}}
|
||||
|
||||
{{% note %}}
|
||||
The `Process` method is also available as a filter, which is more effective if need to apply multiple filters to an image. See [Process filter](/functions/images/#process).
|
||||
{{% /note %}}
|
||||
|
||||
Process processes the image with the given specification. The specification can contain an optional action, one of `resize`, `crop`, `fit` or `fill`. This means that you can use this method instead of [`Resize`], [`Fit`], [`Fill`], or [`Crop`].
|
||||
|
||||
See [Options](#image-processing-options) for available options.
|
||||
|
||||
You can also use this method apply image processing that does not need any scaling, e.g. format conversions:
|
||||
|
||||
```go-html-template
|
||||
{{/* Convert the image from JPG to PNG. */}}
|
||||
{{ $png := $jpg.Process "png" }}
|
||||
```
|
||||
|
||||
Some more examples:
|
||||
|
||||
```go-html-template
|
||||
{{/* Rotate the image 90 degrees counter-clockwise. */}}
|
||||
{{ $image := $image.Process "r90" }}
|
||||
|
||||
{{/* Scaling actions. */}}
|
||||
{{ $image := $image.Process "resize 600x" }}
|
||||
{{ $image := $image.Process "crop 600x400" }}
|
||||
{{ $image := $image.Process "fit 600x400" }}
|
||||
{{ $image := $image.Process "fill 600x400" }}
|
||||
```
|
||||
|
||||
|
||||
### Resize
|
||||
|
||||
Resize an image to the specified width and/or height.
|
||||
@@ -305,7 +253,7 @@ In the example above, on the second line, we have reversed width and height to r
|
||||
|
||||
### Anchor
|
||||
|
||||
When using the [`Crop`] or [`Fill`] method, the _anchor_ determines the placement of the crop box. You may specify `TopLeft`, `Top`, `TopRight`, `Left`, `Center`, `Right`, `BottomLeft`, `Bottom`, `BottomRight`, or `Smart`.
|
||||
When using the [`Crop`] or [`Fill`] method, the _anchor_ determines the placement of the crop box. You may specify `TopLeft`, `Top`, `TopRight`, `Left`, `Center`,`Right`, `BottomLeft`, `Bottom`, `BottomRight`, or `Smart`.
|
||||
|
||||
The default value is `Smart`, which uses [Smartcrop] image analysis to determine the optimal placement of the crop box. You may override the default value in the [site configuration].
|
||||
|
||||
@@ -436,7 +384,14 @@ Note the self-closing shortcode syntax above. You may call the `imgproc` shortco
|
||||
|
||||
Define an `imaging` section in your site configuration to set the default [image processing options](#image-processing-options).
|
||||
|
||||
{{< code-toggle config="imaging" />}}
|
||||
{{< code-toggle file="hugo" copy=true >}}
|
||||
[imaging]
|
||||
resampleFilter = "Box"
|
||||
quality = 75
|
||||
hint = "photo"
|
||||
anchor = "Smart"
|
||||
bgColor = "#ffffff"
|
||||
{{< /code-toggle >}}
|
||||
|
||||
anchor
|
||||
: See image processing options: [anchor](#anchor).
|
||||
@@ -501,16 +456,15 @@ If you change image processing methods or options, or if you rename or remove im
|
||||
hugo --gc
|
||||
```
|
||||
|
||||
[time.Format]: /functions/time/format
|
||||
[time.Format]: /functions/dateformat
|
||||
[`anchor`]: /content-management/image-processing#anchor
|
||||
[mounted]: /hugo-modules/configuration#module-configuration-mounts
|
||||
[page bundle]: /content-management/page-bundles
|
||||
[`lang.FormatNumber`]: /functions/lang/formatnumber
|
||||
[`lang.FormatNumber`]: /functions/lang
|
||||
[filters]: /functions/images
|
||||
[github.com/disintegration/imaging]: <https://github.com/disintegration/imaging#image-resizing>
|
||||
[Smartcrop]: <https://github.com/muesli/smartcrop#smartcrop>
|
||||
[Exif]: <https://en.wikipedia.org/wiki/Exif>
|
||||
[`Process`]: #process
|
||||
[`Colors`]: #colors
|
||||
[`Crop`]: #crop
|
||||
[`Exif`]: #exif
|
||||
@@ -519,4 +473,4 @@ hugo --gc
|
||||
[`Fit`]: #fit
|
||||
[`Resize`]: #resize
|
||||
[site configuration]: #processing-options
|
||||
[`with`]: /functions/go-template/with/
|
||||
[`with`]: /functions/with/
|
||||
|
||||
@@ -19,10 +19,6 @@ Also See [Hugo Multilingual Part 1: Content translation].
|
||||
|
||||
## Configure languages
|
||||
|
||||
This is the default language configuration:
|
||||
|
||||
{{< code-toggle config="languages" />}}
|
||||
|
||||
This is an example of a site configuration for a multilingual project. Any key not defined in a `languages` object will fall back to the global value in the root of your site configuration.
|
||||
|
||||
{{< code-toggle file="hugo" >}}
|
||||
@@ -102,10 +98,9 @@ subtitle = 'Reference, Tutorials, and Explanations'
|
||||
In Hugo `v0.112.0` we consolidated all configuration options, and improved how the languages and their parameters are merged with the main configuration. But while testing this on Hugo sites out there, we received some error reports and reverted some of the changes in favor of deprecation warnings:
|
||||
|
||||
1. `site.Language.Params` is deprecated. Use `site.Params` directly.
|
||||
1. Adding custom parameters to the top level language configuration is deprecated. Define custom parameters within `languages.xx.params`. See `color` in the example below.
|
||||
|
||||
{{< code-toggle file=hugo copy=false >}}
|
||||
1. Adding custom parameters to the top level language configuration is deprecated, add all of these below `[params]`, see `color` in the example below.
|
||||
|
||||
```toml
|
||||
title = "My blog"
|
||||
languageCode = "en-us"
|
||||
|
||||
@@ -115,7 +110,7 @@ title = "Min blogg"
|
||||
languageCode = "sv"
|
||||
[languages.en.params]
|
||||
color = "blue"
|
||||
{{< /code-toggle >}}
|
||||
```
|
||||
|
||||
In the example above, all settings except `color` below `params` map to predefined configuration options in Hugo for the site and its language, and should be accessed via the documented accessors:
|
||||
|
||||
@@ -391,7 +386,7 @@ This article has 101 words.
|
||||
|
||||
### Query a singular/plural translation
|
||||
|
||||
To enable pluralization when translating, pass a map with a numeric `.Count` property to the `i18n` function. The example below uses `.ReadingTime` variable which has a built-in `.Count` property.
|
||||
In other to meet singular/plural requirement, you must pass a dictionary (map) with a numeric `.Count` property to the `i18n` function. The below example uses `.ReadingTime` variable which has a built-in `.Count` property.
|
||||
|
||||
```go-html-template
|
||||
{{ i18n "readingTime" .ReadingTime }}
|
||||
@@ -468,7 +463,7 @@ English|Wednesday, November 3, 2021
|
||||
Français|mercredi 3 novembre 2021
|
||||
Deutsch|Mittwoch, 3. November 2021
|
||||
|
||||
See [`time.Format`] for details.
|
||||
See [time.Format] for details.
|
||||
|
||||
### Currency
|
||||
|
||||
@@ -511,7 +506,7 @@ See [lang.FormatNumber] and [lang.FormatNumberCustom] for details.
|
||||
With this template code:
|
||||
|
||||
```go-html-template
|
||||
{{ 512.5032 | lang.FormatPercent 2 }}
|
||||
{{ 512.5032 | lang.FormatPercent 2 }} → 512.50%
|
||||
```
|
||||
|
||||
The rendered page displays:
|
||||
@@ -526,86 +521,11 @@ See [lang.FormatPercent] for details.
|
||||
|
||||
## Menus
|
||||
|
||||
Localization of menu entries depends on how you define them:
|
||||
Localization of menu entries depends on the how you define them:
|
||||
|
||||
- When you define menu entries [automatically] using the section pages menu, you must use translation tables to localize each entry.
|
||||
- When you define menu entries [in front matter], they are already localized based on the front matter itself. If the front matter values are insufficient, use translation tables to localize each entry.
|
||||
- When you define menu entries [in site configuration], you must create language-specific menu entries under each language key. If the names of the menu entries are insufficent, use translation tables to localize each entry.
|
||||
|
||||
### Create language-specific menu entries
|
||||
|
||||
#### Method 1 -- Use a single configuration file
|
||||
|
||||
For a simple menu with a small number of entries, use a single configuration file. For example:
|
||||
|
||||
{{< code-toggle file="hugo" copy=false >}}
|
||||
[languages.de]
|
||||
languageCode = 'de-DE'
|
||||
languageName = 'Deutsch'
|
||||
weight = 1
|
||||
|
||||
[[languages.de.menu.main]]
|
||||
name = 'Produkte'
|
||||
pageRef = '/products'
|
||||
weight = 10
|
||||
|
||||
[[languages.de.menu.main]]
|
||||
name = 'Leistungen'
|
||||
pageRef = '/services'
|
||||
weight = 20
|
||||
|
||||
[languages.en]
|
||||
languageCode = 'en-US'
|
||||
languageName = 'English'
|
||||
weight = 2
|
||||
|
||||
[[languages.en.menu.main]]
|
||||
name = 'Products'
|
||||
pageRef = '/products'
|
||||
weight = 10
|
||||
|
||||
[[languages.en.menu.main]]
|
||||
name = 'Services'
|
||||
pageRef = '/services'
|
||||
weight = 20
|
||||
{{< /code-toggle >}}
|
||||
|
||||
#### Method 2 -- Use a configuration directory
|
||||
|
||||
With a more complex menu structure, create a [configuration directory] and split the menu entries into multiple files, one file per language. For example:
|
||||
|
||||
```text
|
||||
config/
|
||||
└── _default/
|
||||
├── menus/
|
||||
│ ├── menu.de.toml
|
||||
│ └── menu.en.toml
|
||||
└── hugo.toml
|
||||
```
|
||||
|
||||
{{< code-toggle file="config/_default/menus/menu.de" copy=false >}}
|
||||
[[main]]
|
||||
name = 'Produkte'
|
||||
pageRef = '/products'
|
||||
weight = 10
|
||||
[[main]]
|
||||
name = 'Leistungen'
|
||||
pageRef = '/services'
|
||||
weight = 20
|
||||
{{< /code-toggle >}}
|
||||
|
||||
{{< code-toggle file="config/_default/menus/menu.en" copy=false >}}
|
||||
[[main]]
|
||||
name = 'Products'
|
||||
pageRef = '/products'
|
||||
weight = 10
|
||||
[[main]]
|
||||
name = 'Services'
|
||||
pageRef = '/services'
|
||||
weight = 20
|
||||
{{< /code-toggle >}}
|
||||
|
||||
[configuration directory]: /getting-started/configuration/#configuration-directory
|
||||
- When you define menu entries [in site configuration], you can (a) use translation tables, or (b) create language-specific menu entries under each language key.
|
||||
|
||||
### Use translation tables
|
||||
|
||||
@@ -649,6 +569,44 @@ services = 'Leistungen'
|
||||
[in front matter]: /content-management/menus/#define-in-front-matter
|
||||
[in site configuration]: /content-management/menus/#define-in-site-configuration
|
||||
|
||||
### Create language-specific menu entries
|
||||
|
||||
For example:
|
||||
|
||||
{{< code-toggle file="hugo" copy=false >}}
|
||||
[languages.de]
|
||||
languageCode = 'de-DE'
|
||||
languageName = 'Deutsch'
|
||||
weight = 1
|
||||
|
||||
[[languages.de.menu.main]]
|
||||
name = 'Produkte'
|
||||
pageRef = '/products'
|
||||
weight = 10
|
||||
|
||||
[[languages.de.menu.main]]
|
||||
name = 'Leistungen'
|
||||
pageRef = '/services'
|
||||
weight = 20
|
||||
|
||||
[languages.en]
|
||||
languageCode = 'en-US'
|
||||
languageName = 'English'
|
||||
weight = 2
|
||||
|
||||
[[languages.en.menu.main]]
|
||||
name = 'Products'
|
||||
pageRef = '/products'
|
||||
weight = 10
|
||||
|
||||
[[languages.en.menu.main]]
|
||||
name = 'Services'
|
||||
pageRef = '/services'
|
||||
weight = 20
|
||||
{{< /code-toggle >}}
|
||||
|
||||
For a simple menu with two languages, these menu entries are easy to create and maintain. For a larger menu, or with more than two languages, using translation tables as described above is preferable.
|
||||
|
||||
## Missing translations
|
||||
|
||||
If a string does not have a translation for the current language, Hugo will use the value from the default language. If no default value is set, an empty string will be shown.
|
||||
@@ -673,44 +631,44 @@ i18n|MISSING_TRANSLATION|en|wordCount
|
||||
To support Multilingual mode in your themes, some considerations must be taken for the URLs in the templates. If there is more than one language, URLs must meet the following criteria:
|
||||
|
||||
* Come from the built-in `.Permalink` or `.RelPermalink`
|
||||
* Be constructed with the [`relLangURL`] or [`absLangURL`] template function, or be prefixed with `{{ .LanguagePrefix }}`
|
||||
* Be constructed with the [`relLangURL` template function][rellangurl] or the [`absLangURL` template function][abslangurl] **OR** be prefixed with `{{ .LanguagePrefix }}`
|
||||
|
||||
If there is more than one language defined, the `LanguagePrefix` variable will equal `/en` (or whatever your `CurrentLanguage` is). If not enabled, it will be an empty string (and is therefore harmless for single-language Hugo websites).
|
||||
|
||||
|
||||
## Generate multilingual content with `hugo new content`
|
||||
## Generate multilingual content with `hugo new`
|
||||
|
||||
If you organize content with translations in the same directory:
|
||||
|
||||
```text
|
||||
hugo new content post/test.en.md
|
||||
hugo new content post/test.de.md
|
||||
hugo new post/test.en.md
|
||||
hugo new post/test.de.md
|
||||
```
|
||||
|
||||
If you organize content with translations in different directories:
|
||||
|
||||
```text
|
||||
hugo new content content/en/post/test.md
|
||||
hugo new content content/de/post/test.md
|
||||
hugo new content/en/post/test.md
|
||||
hugo new content/de/post/test.md
|
||||
```
|
||||
|
||||
[`abslangurl`]: /functions/urls/abslangurl
|
||||
[abslangurl]: /functions/abslangurl
|
||||
[config]: /getting-started/configuration/
|
||||
[contenttemplate]: /templates/single-page-templates/
|
||||
[go-i18n-source]: https://github.com/nicksnyder/go-i18n
|
||||
[go-i18n]: https://github.com/nicksnyder/go-i18n
|
||||
[homepage]: /templates/homepage/
|
||||
[Hugo Multilingual Part 1: Content translation]: https://regisphilibert.com/blog/2018/08/hugo-multilingual-part-1-managing-content-translation/
|
||||
[i18func]: /functions/lang/translate
|
||||
[lang.FormatAccounting]: /functions/lang/formataccounting
|
||||
[lang.FormatCurrency]: /functions/lang/formatcurrency
|
||||
[lang.FormatNumber]: /functions/lang/formatnumber
|
||||
[lang.FormatNumberCustom]: /functions/lang/formatnumbercustom
|
||||
[lang.FormatPercent]: /functions/lang/formatpercent
|
||||
[lang.Merge]: /functions/lang/merge/
|
||||
[i18func]: /functions/i18n/
|
||||
[lang.FormatAccounting]: /functions/lang
|
||||
[lang.FormatCurrency]: /functions/lang
|
||||
[lang.FormatNumber]: /functions/lang
|
||||
[lang.FormatNumberCustom]: /functions/lang
|
||||
[lang.FormatPercent]: /functions/lang
|
||||
[lang.Merge]: /functions/lang.merge/
|
||||
[menus]: /content-management/menus/
|
||||
[OS environment]: /getting-started/configuration/#configure-with-environment-variables
|
||||
[`rellangurl`]: /functions/urls/rellangurl
|
||||
[rellangurl]: /functions/rellangurl
|
||||
[RFC 5646]: https://tools.ietf.org/html/rfc5646
|
||||
[single page templates]: /templates/single-page-templates/
|
||||
[`time.Format`]: /functions/time/format
|
||||
[time.Format]: /functions/dateformat
|
||||
|
||||
@@ -113,7 +113,19 @@ Hugo provides a sensible default configuration of Related Content, but you can f
|
||||
|
||||
Without any `related` configuration set on the project, Hugo's Related Content methods will use the following.
|
||||
|
||||
{{< code-toggle config="related" />}}
|
||||
{{< code-toggle file="hugo" >}}
|
||||
related:
|
||||
threshold: 80
|
||||
includeNewer: false
|
||||
toLower: false
|
||||
indices:
|
||||
- name: keywords
|
||||
weight: 100
|
||||
- name: date
|
||||
weight: 10
|
||||
{{< /code-toggle >}}
|
||||
|
||||
Note that if you have configured `tags` as a taxonomy, `tags` will also be added to the default configuration above with the weight of `80`.
|
||||
|
||||
Custom configuration should be set using the same syntax.
|
||||
|
||||
|
||||
@@ -1,7 +1,6 @@
|
||||
---
|
||||
title: Sections
|
||||
description: Organize content into sections.
|
||||
|
||||
description: Hugo generates a **section tree** that matches your content.
|
||||
categories: [content management]
|
||||
keywords: [lists,sections,content types,organization]
|
||||
menu:
|
||||
@@ -13,112 +12,54 @@ weight: 120
|
||||
aliases: [/content/sections/]
|
||||
---
|
||||
|
||||
## Overview
|
||||
A **Section** is a collection of pages that gets defined based on the
|
||||
organization structure under the `content/` directory.
|
||||
|
||||
By default, all the **first-level** directories under `content/` form their own
|
||||
sections (**root sections**) provided they constitute [Branch Bundles][branch bundles].
|
||||
Directories which are just [Leaf Bundles][leaf bundles] do *not* form
|
||||
their own sections, despite being first-level directories.
|
||||
|
||||
If a user needs to define a section `foo` at a deeper level, they need to create
|
||||
a directory named `foo` with an `_index.md` file (see [Branch Bundles][branch bundles]
|
||||
for more information).
|
||||
|
||||
A section is a top-level content directory, or any content directory with an _index.md file. A content directory with an _index.md file is also known as a [branch bundle](/getting-started/glossary/#branch-bundle). Section templates receive one or more page [collections](/getting-started/glossary/#collection) in [context](/getting-started/glossary/#context).
|
||||
|
||||
{{% note %}}
|
||||
Although top-level directories without _index.md files are sections, we recommend creating _index.md files in _all_ sections.
|
||||
A **section** cannot be defined or overridden by a front matter parameter -- it
|
||||
is strictly derived from the content organization structure.
|
||||
{{% /note %}}
|
||||
|
||||
A typical site consists of one or more sections. For example:
|
||||
## Nested sections
|
||||
|
||||
```text
|
||||
content/
|
||||
├── articles/ <-- section (top-level directory)
|
||||
│ ├── 2022/
|
||||
│ │ ├── article-1/
|
||||
│ │ │ ├── cover.jpg
|
||||
│ │ │ └── index.md
|
||||
│ │ └── article-2.md
|
||||
│ └── 2023/
|
||||
│ ├── article-3.md
|
||||
│ └── article-4.md
|
||||
├── products/ <-- section (top-level directory)
|
||||
│ ├── product-1/ <-- section (has _index.md file)
|
||||
│ │ ├── benefits/ <-- section (has _index.md file)
|
||||
│ │ │ ├── _index.md
|
||||
│ │ │ ├── benefit-1.md
|
||||
│ │ │ └── benefit-2.md
|
||||
│ │ ├── features/ <-- section (has _index.md file)
|
||||
│ │ │ ├── _index.md
|
||||
│ │ │ ├── feature-1.md
|
||||
│ │ │ └── feature-2.md
|
||||
│ │ └── _index.md
|
||||
│ └── product-2/ <-- section (has _index.md file)
|
||||
│ ├── benefits/ <-- section (has _index.md file)
|
||||
│ │ ├── _index.md
|
||||
│ │ ├── benefit-1.md
|
||||
│ │ └── benefit-2.md
|
||||
│ ├── features/ <-- section (has _index.md file)
|
||||
│ │ ├── _index.md
|
||||
│ │ ├── feature-1.md
|
||||
│ │ └── feature-2.md
|
||||
│ └── _index.md
|
||||
├── _index.md
|
||||
└── about.md
|
||||
The sections can be nested as deeply as you need.
|
||||
|
||||
```bash
|
||||
content
|
||||
└── blog <-- Section, because first-level dir under content/
|
||||
├── funny-cats
|
||||
│ ├── mypost.md
|
||||
│ └── kittens <-- Section, because contains _index.md
|
||||
│ └── _index.md
|
||||
└── tech <-- Section, because contains _index.md
|
||||
└── _index.md
|
||||
```
|
||||
|
||||
The example above has two top-level sections: articles and products. None of the directories under articles are sections, while all of the directories under products are sections. A section within a section is a known as a nested section or subsection.
|
||||
**The important part to understand is, that to make the section tree fully navigational, at least the lower-most section needs a content file. (e.g. `_index.md`).**
|
||||
|
||||
## Explanation
|
||||
{{% note %}}
|
||||
When we talk about a **section** in correlation with template selection, it is
|
||||
currently always the *root section* only (`/blog/funny-cats/mypost/ => blog`).
|
||||
|
||||
Sections and non-sections behave differently.
|
||||
If you need a specific template for a sub-section, you need to adjust either the `type` or `layout` in front matter.
|
||||
{{% /note %}}
|
||||
|
||||
||Sections|Non-sections
|
||||
:--|:-:|:-:
|
||||
Directory names become URL segments|:heavy_check_mark:|:heavy_check_mark:
|
||||
Have logical ancestors and descendants|:heavy_check_mark:|:x:
|
||||
Have list pages|:heavy_check_mark:|:x:
|
||||
## Example: breadcrumb navigation
|
||||
|
||||
With the file structure from the [example above](#overview):
|
||||
|
||||
1. The list page for the articles section includes all articles, regardless of directory structure; none of the subdirectories are sections.
|
||||
|
||||
1. The articles/2022 and articles/2023 directories do not have list pages; they are not sections.
|
||||
|
||||
1. The list page for the products section, by default, includes product-1 and product-2, but not their descendant pages. To include descendant pages, use the `.RegularPagesRecursive` collection instead of the `.Pages` collection in the list template. See [details](/variables/page/#page-collections).
|
||||
|
||||
1. All directories in the products section have list pages; each directory is a section.
|
||||
|
||||
## Template selection
|
||||
|
||||
Hugo has a defined [lookup order] to determine which template to use when rendering a page. The [lookup rules] consider the top-level section name; subsection names are not considered when selecting a template.
|
||||
|
||||
With the file structure from the [example above](#overview):
|
||||
|
||||
Content directory|List page template
|
||||
:--|:--
|
||||
content/products|layouts/products/list.html
|
||||
content/products/product-1|layouts/products/list.html
|
||||
content/products/product-1/benefits|layouts/products/list.html
|
||||
|
||||
Content directory|Single page template
|
||||
:--|:--
|
||||
content/products|layouts/products/single.html
|
||||
content/products/product-1|layouts/products/single.html
|
||||
content/products/product-1/benefits|layouts/products/single.html
|
||||
|
||||
If you need to use a different template for a subsection, specify `type` and/or `layout` in front matter.
|
||||
|
||||
[lookup rules]: /templates/lookup-order/#lookup-rules
|
||||
[lookup order]: /templates/lookup-order/
|
||||
|
||||
## Ancestors and descendants
|
||||
|
||||
A section has one or more ancestors (including the home page), and zero or more descendants. With the file structure from the [example above](#overview):
|
||||
|
||||
|
||||
```text
|
||||
content/products/product-1/benefits/benefit-1.md
|
||||
```
|
||||
|
||||
The content file (benefit-1.md) has four ancestors: benefits, product-1, products, and the home page. This logical relationship allows us to use the `.Parent` and `.Ancestors` methods to traverse the site structure.
|
||||
|
||||
For example, use the `.Ancestors` method to render breadcrumb navigation.
|
||||
With the available [section variables and methods](#section-page-variables-and-methods) you can build powerful navigation. One common example would be a partial to show Breadcrumb navigation:
|
||||
|
||||
{{< code file="layouts/partials/breadcrumb.html" >}}
|
||||
<nav aria-label="breadcrumb" class="breadcrumb">
|
||||
<nav aria-label="breadcrumb">
|
||||
<ol>
|
||||
{{ range .Ancestors.Reverse }}
|
||||
<li>
|
||||
@@ -132,28 +73,19 @@ For example, use the `.Ancestors` method to render breadcrumb navigation.
|
||||
</nav>
|
||||
{{< /code >}}
|
||||
|
||||
With this CSS:
|
||||
## Section page variables and methods
|
||||
|
||||
```css
|
||||
.breadcrumb ol {
|
||||
padding-left: 0;
|
||||
}
|
||||
Also see [Page Variables](/variables/page/).
|
||||
|
||||
.breadcrumb li {
|
||||
display: inline;
|
||||
}
|
||||
{{< readfile file="/content/en/readfiles/sectionvars.md" markdown="true" >}}
|
||||
|
||||
.breadcrumb li:not(:last-child)::after {
|
||||
content: "»";
|
||||
}
|
||||
```
|
||||
## Content section lists
|
||||
|
||||
Hugo renders this, where each breadcrumb is a link to the corresponding page:
|
||||
Hugo will automatically create a page for each *root section* that lists all the content in that section. See the documentation on [section templates] for details on customizing the way these pages are rendered.
|
||||
|
||||
```text
|
||||
Home » Products » Product 1 » Benefits » Benefit 1
|
||||
```
|
||||
## Content *section* vs. content *type*
|
||||
|
||||
By default, everything created within a section will use the [content `type`][content type] that matches the *root section* name. For example, Hugo will assume that `posts/post-1.md` has a `posts` content `type`. If you are using an [archetype] for your `posts` section, Hugo will generate front matter according to what it finds in `archetypes/posts.md`.
|
||||
|
||||
[archetype]: /content-management/archetypes/
|
||||
[content type]: /content-management/types/
|
||||
|
||||
@@ -56,8 +56,13 @@ and a new line with a "quoted string".` */>}}
|
||||
|
||||
### Shortcodes with markdown
|
||||
|
||||
Shortcodes using the `%` as the outer-most delimiter will be fully rendered when sent to the content renderer. This means that the rendered output from a shortcode can be part of the page's table of contents, footnotes, etc.
|
||||
In Hugo `0.55` we changed how the `%` delimiter works. Shortcodes using the `%` as the outer-most delimiter will now be fully rendered when sent to the content renderer. They can be part of the generated table of contents, footnotes, etc.
|
||||
|
||||
If you want the old behavior, you can put the following line in the start of your shortcode template:
|
||||
|
||||
```go-html-template
|
||||
{{ $_hugo_config := `{ "version": 1 }` }}
|
||||
```
|
||||
|
||||
### Shortcodes without markdown
|
||||
|
||||
@@ -187,7 +192,7 @@ Rendered:
|
||||
|
||||
To specify one or more [highlighting options], include a quotation-encapsulated, comma-separated list:
|
||||
|
||||
[highlighting options]: /functions/transform/highlight/
|
||||
[highlighting options]: /functions/highlight/
|
||||
|
||||
```text
|
||||
{{</* highlight go-html-template "lineNos=inline, lineNoStart=42" */>}}
|
||||
@@ -391,7 +396,7 @@ To learn more about creating custom shortcodes, see the [shortcode template docu
|
||||
[`figure` shortcode]: #figure
|
||||
[contentmanagementsection]: /content-management/formats/
|
||||
[examplegist]: https://gist.github.com/spf13/7896402
|
||||
[figureelement]: https://html5doctor.com/the-figure-figcaption-elements/
|
||||
[figureelement]: https://html5doctor.com/the-figure-figcaption-elements/ "An article from HTML5 doctor discussing the fig and figcaption elements."
|
||||
[Hugo and the GDPR]: /about/hugo-and-gdpr/
|
||||
[Instagram]: https://www.instagram.com/
|
||||
[pagevariables]: /variables/page/
|
||||
|
||||
@@ -92,7 +92,7 @@ Gives this:
|
||||
|
||||
## Highlight template function
|
||||
|
||||
See [Highlight](/functions/transform/highlight/).
|
||||
See [Highlight](/functions/highlight/).
|
||||
|
||||
## Highlighting in code fences
|
||||
|
||||
|
||||
@@ -82,7 +82,11 @@ Hugo natively supports taxonomies.
|
||||
|
||||
Without adding a single line to your [site configuration] file, Hugo will automatically create taxonomies for `tags` and `categories`. That would be the same as manually [configuring your taxonomies](#configure-taxonomies) as below:
|
||||
|
||||
{{< code-toggle config="taxonomies" />}}
|
||||
{{< code-toggle file="hugo" copy=false >}}
|
||||
[taxonomies]
|
||||
tag = "tags"
|
||||
category = "categories"
|
||||
{{</ code-toggle >}}
|
||||
|
||||
If you do not want Hugo to create any taxonomies, set `disableKinds` in your [site configuration] to the following:
|
||||
|
||||
@@ -191,11 +195,12 @@ title: "Bruce Willis"
|
||||
wikipedia: "https://en.wikipedia.org/wiki/Bruce_Willis"
|
||||
{{< /code-toggle >}}
|
||||
|
||||
[`urlize` template function]: /functions/urlize/
|
||||
[content section]: /content-management/sections/
|
||||
[content type]: /content-management/types/
|
||||
[documentation on archetypes]: /content-management/archetypes/
|
||||
[front matter]: /content-management/front-matter/
|
||||
[taxonomy list templates]: /templates/taxonomy-templates/#taxonomy-list-templates
|
||||
[taxonomy templates]: /templates/taxonomy-templates/
|
||||
[terms within the taxonomy]: /templates/taxonomy-templates/#taxonomy-terms-templates
|
||||
[site configuration]: /getting-started/configuration/
|
||||
[terms within the taxonomy]: /templates/taxonomy-templates/#taxonomy-terms-templates "See how to order terms associated with a taxonomy"
|
||||
[configuration]: /getting-started/configuration/
|
||||
|
||||
@@ -102,11 +102,11 @@ With this content structure:
|
||||
```text
|
||||
content/
|
||||
├── posts/
|
||||
│ ├── bash-in-slow-motion.md
|
||||
│ └── tls-in-a-nutshell.md
|
||||
│ ├── bash-in-slow-motion.md
|
||||
│ └── tls-in-a-nutshell.md
|
||||
├── tutorials/
|
||||
│ ├── git-for-beginners.md
|
||||
│ └── javascript-bundling-with-hugo.md
|
||||
│ ├── git-for-beginners.md
|
||||
│ └── javascript-bundling-with-hugo.md
|
||||
└── _index.md
|
||||
```
|
||||
|
||||
@@ -165,15 +165,15 @@ With this content structure:
|
||||
|
||||
```text
|
||||
content/
|
||||
├── en/
|
||||
│ ├── books/
|
||||
│ │ ├── les-miserables.md
|
||||
│ │ └── the-hunchback-of-notre-dame.md
|
||||
│ └── _index.md
|
||||
└── es/
|
||||
├── de/
|
||||
│ ├── books/
|
||||
│ │ ├── les-miserables.md
|
||||
│ │ └── the-hunchback-of-notre-dame.md
|
||||
│ └── _index.md
|
||||
└── en/
|
||||
├── books/
|
||||
│ ├── les-miserables.md
|
||||
│ └── the-hunchback-of-notre-dame.md
|
||||
│ ├── les-miserables.md
|
||||
│ └── the-hunchback-of-notre-dame.md
|
||||
└── _index.md
|
||||
```
|
||||
|
||||
@@ -197,7 +197,7 @@ books = "/books/:slug/"
|
||||
books = "/books/"
|
||||
|
||||
[languages.es]
|
||||
contentDir = 'content/es'
|
||||
contentDir = 'content/de'
|
||||
languageCode = 'es-ES'
|
||||
languageDirection = 'ltr'
|
||||
languageName = 'Español'
|
||||
@@ -215,21 +215,21 @@ The structure of the published site will be:
|
||||
```text
|
||||
public/
|
||||
├── en/
|
||||
│ ├── books/
|
||||
│ │ ├── les-miserables/
|
||||
│ │ │ └── index.html
|
||||
│ │ ├── the-hunchback-of-notre-dame/
|
||||
│ │ │ └── index.html
|
||||
│ │ └── index.html
|
||||
│ └── index.html
|
||||
│ ├── books/
|
||||
│ │ ├── les-miserables/
|
||||
│ │ │ └── index.html
|
||||
│ │ ├── the-hunchback-of-notre-dame/
|
||||
│ │ │ └── index.html
|
||||
│ │ └── index.html
|
||||
│ └── index.html
|
||||
├── es/
|
||||
│ ├── libros/
|
||||
│ │ ├── les-miserables/
|
||||
│ │ │ └── index.html
|
||||
│ │ ├── the-hunchback-of-notre-dame/
|
||||
│ │ │ └── index.html
|
||||
│ │ └── index.html
|
||||
│ └── index.html
|
||||
│ ├── libros/
|
||||
│ │ ├── les-miserables/
|
||||
│ │ │ └── index.html
|
||||
│ │ ├── the-hunchback-of-notre-dame/
|
||||
│ │ │ └── index.html
|
||||
│ │ └── index.html
|
||||
│ └── index.html
|
||||
└── index.html
|
||||
````
|
||||
|
||||
|
||||
@@ -1,90 +0,0 @@
|
||||
---
|
||||
title: .Format
|
||||
description: Returns a formatted time.Time value.
|
||||
categories: [functions]
|
||||
keywords: []
|
||||
menu:
|
||||
docs:
|
||||
parent: functions
|
||||
function:
|
||||
aliases: []
|
||||
returnType: string
|
||||
signatures: [.Format LAYOUT]
|
||||
relatedFunctions: []
|
||||
toc: true
|
||||
---
|
||||
|
||||
```go-template
|
||||
{{ $t := "2023-01-27T23:44:58-08:00" }}
|
||||
{{ $t = time.AsTime $t }}
|
||||
{{ $format := "2 Jan 2006" }}
|
||||
|
||||
{{ $t.Format $format }} → 27 Jan 2023
|
||||
```
|
||||
|
||||
{{% note %}}
|
||||
To return a formatted and localized `time.Time` value, use the [`time.Format`] function instead.
|
||||
|
||||
[`time.Format`]: /functions/time/format
|
||||
{{% /note %}}
|
||||
|
||||
Use the `.Format` method with any `time.Time` value, including the four predefined front matter dates:
|
||||
|
||||
```go-html-template
|
||||
{{ $format := "2 Jan 2006" }}
|
||||
|
||||
{{ .Date.Format $format }}
|
||||
{{ .PublishDate.Format $format }}
|
||||
{{ .ExpiryDate.Format $format }}
|
||||
{{ .Lastmod.Format $format }}
|
||||
```
|
||||
|
||||
## Layout string
|
||||
|
||||
{{% readfile file="/functions/_common/time-layout-string.md" %}}
|
||||
|
||||
## Examples
|
||||
|
||||
Given this front matter:
|
||||
|
||||
{{< code-toggle fm=true copy=false >}}
|
||||
title = "About time"
|
||||
date = 2023-01-27T23:44:58-08:00
|
||||
{{< /code-toggle >}}
|
||||
|
||||
The examples below were rendered in the `America/Los_Angeles` time zone:
|
||||
|
||||
Format string|Result
|
||||
:--|:--
|
||||
`Monday, January 2, 2006`|`Friday, January 27, 2023`
|
||||
`Mon Jan 2 2006`|`Fri Jan 27 2023`
|
||||
`January 2006`|`January 2023`
|
||||
`2006-01-02`|`2023-01-27`
|
||||
`Monday`|`Friday`
|
||||
`02 Jan 06 15:04 MST`|`27 Jan 23 23:44 PST`
|
||||
`Mon, 02 Jan 2006 15:04:05 MST`|`Fri, 27 Jan 2023 23:44:58 PST`
|
||||
`Mon, 02 Jan 2006 15:04:05 -0700`|`Fri, 27 Jan 2023 23:44:58 -0800`
|
||||
|
||||
## UTC and local time
|
||||
|
||||
Convert and format any `time.Time` value to either Coordinated Universal Time (UTC) or local time.
|
||||
|
||||
```go-html-template
|
||||
{{ $t := "2023-01-27T23:44:58-08:00" }}
|
||||
{{ $t = time.AsTime $t }}
|
||||
{{ $format := "2 Jan 2006 3:04:05 PM MST" }}
|
||||
|
||||
{{ $t.UTC.Format $format }} → 28 Jan 2023 7:44:58 AM UTC
|
||||
{{ $t.Local.Format $format }} → 27 Jan 2023 11:44:58 PM PST
|
||||
```
|
||||
|
||||
## Ordinal representation
|
||||
|
||||
Use the [`humanize`](/functions/inflect/humanize) function to render the day of the month as an ordinal number:
|
||||
|
||||
```go-html-template
|
||||
{{ $t := "2023-01-27T23:44:58-08:00" }}
|
||||
{{ $t = time.AsTime $t }}
|
||||
|
||||
{{ humanize $t.Day }} of {{ $t.Format "January 2006" }} → 27th of January 2023
|
||||
```
|
||||
@@ -1,16 +1,13 @@
|
||||
---
|
||||
title: .GetPage
|
||||
description: Gets a `Page` of a given `path`.
|
||||
description: "Gets a `Page` of a given `path`."
|
||||
categories: [functions]
|
||||
keywords: []
|
||||
menu:
|
||||
docs:
|
||||
parent: functions
|
||||
function:
|
||||
aliases: []
|
||||
returnType:
|
||||
signatures: [.GetPage PATH]
|
||||
relatedFunctions: []
|
||||
keywords: [sections,lists,indexes]
|
||||
signature: [".GetPage PATH"]
|
||||
relatedfuncs: []
|
||||
---
|
||||
|
||||
`.GetPage` returns a page of a given `path`. Both `Site` and `Page` implements this method. The `Page` variant will, if given a relative path -- i.e. a path without a leading `/` -- try look for the page relative to the current page.
|
||||
|
||||
@@ -1,35 +0,0 @@
|
||||
---
|
||||
title: .HasMenuCurrent
|
||||
description: Reports whether the given page object matches the page object associated with one of the child menu entries under the given menu entry in the given menu.
|
||||
categories: [functions]
|
||||
keywords: []
|
||||
menu:
|
||||
docs:
|
||||
parent: functions
|
||||
function:
|
||||
aliases: []
|
||||
returnType: bool
|
||||
signatures: [PAGE.HasMenuCurrent MENU MENUENTRY]
|
||||
relatedFunctions:
|
||||
- .HasMenuCurrent
|
||||
- .IsMenuCurrent
|
||||
---
|
||||
|
||||
If the page object associated with the menu entry is a section, this method also returns `true` for any descendant of that section.
|
||||
|
||||
```go-html-template
|
||||
{{ $currentPage := . }}
|
||||
{{ range site.Menus.main }}
|
||||
{{ if $currentPage.IsMenuCurrent .Menu . }}
|
||||
<a class="active" aria-current="page" href="{{ .URL }}">{{ .Name }}</a>
|
||||
{{ else if $currentPage.HasMenuCurrent .Menu . }}
|
||||
<a class="ancestor" aria-current="true" href="{{ .URL }}">{{ .Name }}</a>
|
||||
{{ else }}
|
||||
<a href="{{ .URL }}">{{ .Name }}</a>
|
||||
{{ end }}
|
||||
{{ end }}
|
||||
```
|
||||
|
||||
See [menu templates] for a complete example.
|
||||
|
||||
[menu templates]: /templates/menu-templates/#example
|
||||
@@ -1,33 +0,0 @@
|
||||
---
|
||||
title: .IsMenuCurrent
|
||||
description: Reports whether the given page object matches the page object associated with the given menu entry in the given menu.
|
||||
categories: [functions]
|
||||
keywords: []
|
||||
menu:
|
||||
docs:
|
||||
parent: functions
|
||||
function:
|
||||
aliases: []
|
||||
returnType: bool
|
||||
signatures: [PAGE.IsMenuCurrent MENU MENUENTRY]
|
||||
relatedFunctions:
|
||||
- .HasMenuCurrent
|
||||
- .IsMenuCurrent
|
||||
---
|
||||
|
||||
```go-html-template
|
||||
{{ $currentPage := . }}
|
||||
{{ range site.Menus.main }}
|
||||
{{ if $currentPage.IsMenuCurrent .Menu . }}
|
||||
<a class="active" aria-current="page" href="{{ .URL }}">{{ .Name }}</a>
|
||||
{{ else if $currentPage.HasMenuCurrent .Menu . }}
|
||||
<a class="ancestor" aria-current="true" href="{{ .URL }}">{{ .Name }}</a>
|
||||
{{ else }}
|
||||
<a href="{{ .URL }}">{{ .Name }}</a>
|
||||
{{ end }}
|
||||
{{ end }}
|
||||
```
|
||||
|
||||
See [menu templates] for a complete example.
|
||||
|
||||
[menu templates]: /templates/menu-templates/#example
|
||||
@@ -1,15 +1,12 @@
|
||||
---
|
||||
title: .RenderString
|
||||
description: Renders markup to HTML.
|
||||
description: "Renders markup to HTML."
|
||||
categories: [functions]
|
||||
keywords: []
|
||||
menu:
|
||||
docs:
|
||||
parent: functions
|
||||
function:
|
||||
aliases: []
|
||||
returnType: template.HTML
|
||||
signatures: ['.RenderString MARKUP [OPTIONS]']
|
||||
keywords: [markdown,goldmark,render]
|
||||
signature: [".RenderString MARKUP"]
|
||||
---
|
||||
|
||||
`.RenderString` is a method on `Page` that renders some markup to HTML using the content renderer defined for that page (if not set in the options).
|
||||
@@ -32,4 +29,4 @@ Some examples:
|
||||
{{ "/italic org mode/" | $p.RenderString $optOrg }}
|
||||
```
|
||||
|
||||
{{< new-in "0.93.0" >}} **Note**: [markdownify](/functions/transform/markdownify) uses this function in order to support [Render Hooks](/getting-started/configuration-markup/#markdown-render-hooks).
|
||||
{{< new-in "0.93.0" >}} **Note**: [markdownify](/functions/markdownify/) uses this function in order to support [Render Hooks](/getting-started/configuration-markup/#markdown-render-hooks).
|
||||
|
||||
@@ -1,36 +0,0 @@
|
||||
---
|
||||
title: .Unix
|
||||
description: Converts a time.Time value to the number of seconds elapsed since the Unix epoch, excluding leap seconds. The Unix epoch is 00:00:00 UTC on 1 January 1970.
|
||||
categories: [functions]
|
||||
menu:
|
||||
docs:
|
||||
parent: functions
|
||||
function:
|
||||
aliases: []
|
||||
returnType: int64
|
||||
signatures:
|
||||
- .Unix
|
||||
- .UnixMilli
|
||||
- .UnixMicro
|
||||
- .UnixNano
|
||||
relatedFunctions: []
|
||||
---
|
||||
|
||||
The `Milli`, `Micro`, and `Nano` variants return the number of milliseconds, microseconds, and nanoseconds (respectively) elapsed since the Unix epoch.
|
||||
|
||||
```go-html-template
|
||||
.Date.Unix → 1637259694
|
||||
.ExpiryDate.Unix → 1672559999
|
||||
.Lastmod.Unix → 1637361786
|
||||
.PublishDate.Unix → 1637421261
|
||||
|
||||
("1970-01-01T00:00:00-00:00" | time.AsTime).Unix → 0
|
||||
("1970-01-01T00:00:42-00:00" | time.AsTime).Unix → 42
|
||||
("1970-04-11T01:48:29-08:00" | time.AsTime).Unix → 8675309
|
||||
("2026-05-02T20:09:31-07:00" | time.AsTime).Unix → 1777777771
|
||||
|
||||
now.Unix → 1637447841
|
||||
now.UnixMilli → 1637447841347
|
||||
now.UnixMicro → 1637447841347378
|
||||
now.UnixNano → 1637447841347378799
|
||||
```
|
||||
@@ -1,3 +0,0 @@
|
||||
See Go's [text/template] documentation for more details.
|
||||
|
||||
[text/template]: https://pkg.go.dev/text/template
|
||||
@@ -1,3 +0,0 @@
|
||||
Localization of dates, currencies, numbers, and percentages is performed by the [gohugoio/locales] package. The language tag of the current site must match one of the listed locales.
|
||||
|
||||
[gohugoio/locales]: https://github.com/gohugoio/locales
|
||||
@@ -1,42 +0,0 @@
|
||||
Format a `time.Time` value based on [Go's reference time]:
|
||||
|
||||
[Go's reference time]: https://pkg.go.dev/time#pkg-constants
|
||||
|
||||
```text {copy=false}
|
||||
Mon Jan 2 15:04:05 MST 2006
|
||||
```
|
||||
|
||||
Create a format string using these components:
|
||||
|
||||
Description|Valid components
|
||||
:--|:--
|
||||
Year|`"2006" "06"`
|
||||
Month|`"Jan" "January" "01" "1"`
|
||||
Day of the week|`"Mon" "Monday"`
|
||||
Day of the month|`"2" "_2" "02"`
|
||||
Day of the year|`"__2" "002"`
|
||||
Hour|`"15" "3" "03"`
|
||||
Minute|`"4" "04"`
|
||||
Second|`"5" "05"`
|
||||
AM/PM mark|`"PM"`
|
||||
Time zone offsets|`"-0700" "-07:00" "-07" "-070000" "-07:00:00"`
|
||||
|
||||
Replace the sign in the format string with a Z to print Z instead of an offset for the UTC zone.
|
||||
|
||||
Description|Valid components
|
||||
:--|:--
|
||||
Time zone offsets|`"Z0700" "Z07:00" "Z07" "Z070000" "Z07:00:00"`
|
||||
|
||||
```go-html-template
|
||||
{{ $t := "2023-01-27T23:44:58-08:00" }}
|
||||
{{ $t = time.AsTime $t }}
|
||||
{{ $t = $t.Format "Jan 02, 2006 3:04 PM Z07:00" }}
|
||||
|
||||
{{ $t }} → Jan 27, 2023 11:44 PM -08:00
|
||||
```
|
||||
|
||||
Strings such as `PST` and `CET` are not time zones. They are time zone _abbreviations_.
|
||||
|
||||
Strings such as `-07:00` and `+01:00` are not time zones. They are time zone _offsets_.
|
||||
|
||||
A time zone is a geographic area with the same local time. For example, the time zone abbreviated by `PST` and `PDT` (depending on Daylight Savings Time) is `America/Los_Angeles`.
|
||||
+3
-13
@@ -1,22 +1,12 @@
|
||||
---
|
||||
title: urls.AbsLangURL
|
||||
linkTitle: absLangURL
|
||||
title: absLangURL
|
||||
description: Returns an absolute URL with a language prefix, if any.
|
||||
categories: [functions]
|
||||
keywords: []
|
||||
menu:
|
||||
docs:
|
||||
parent: functions
|
||||
function:
|
||||
aliases: [absLangURL]
|
||||
returnType: template.HTML
|
||||
signatures: [urls.AbsLangURL INPUT]
|
||||
relatedFunctions:
|
||||
- urls.AbsLangURL
|
||||
- urls.AbsURL
|
||||
- urls.RelLangURL
|
||||
- urls.RelURL
|
||||
aliases: [/functions/abslangurl]
|
||||
keywords: [urls, multilingual,i18n]
|
||||
signature: ["absLangURL INPUT"]
|
||||
---
|
||||
|
||||
Use this function with both monolingual and multilingual configurations. The URL returned by this function depends on:
|
||||
@@ -1,22 +1,12 @@
|
||||
---
|
||||
title: urls.AbsURL
|
||||
linkTitle: absURL
|
||||
title: absURL
|
||||
description: Returns an absolute URL.
|
||||
categories: [functions]
|
||||
keywords: []
|
||||
menu:
|
||||
docs:
|
||||
parent: functions
|
||||
function:
|
||||
aliases: [absURL]
|
||||
returnType: template.html
|
||||
signatures: [urls.AbsURL INPUT]
|
||||
relatedFunctions:
|
||||
- urls.AbsLangURL
|
||||
- urls.AbsURL
|
||||
- urls.RelLangURL
|
||||
- urls.RelURL
|
||||
aliases: [/functions/absurl]
|
||||
keywords: [urls]
|
||||
signature: ["absURL INPUT"]
|
||||
---
|
||||
|
||||
With multilingual configurations, use the [`absLangURL`] function instead. The URL returned by this function depends on:
|
||||
@@ -44,7 +34,7 @@ With `baseURL = https://example.org/docs/`
|
||||
{{ absURL "style.css" }} → https://example.org/docs/style.css
|
||||
```
|
||||
|
||||
#### Input begins with a slash
|
||||
### Input begins with a slash
|
||||
|
||||
If the input begins with a slash, the resulting URL will be incorrect when the `baseURL` includes a subdirectory. With a leading slash, the function returns a URL relative to the protocol+host section of the `baseURL`.
|
||||
|
||||
@@ -68,4 +58,4 @@ With `baseURL = https://example.org/docs/`
|
||||
The last three examples are not desirable in most situations. As a best practice, never include a leading slash when using this function.
|
||||
{{% /note %}}
|
||||
|
||||
[`absLangURL`]: /functions/urls/abslangurl/
|
||||
[`absLangURL`]: /functions/abslangurl/
|
||||
@@ -2,15 +2,12 @@
|
||||
title: .AddDate
|
||||
description: Returns the time corresponding to adding the given number of years, months, and days to the given time.Time value.
|
||||
categories: [functions]
|
||||
keywords: []
|
||||
menu:
|
||||
docs:
|
||||
parent: functions
|
||||
function:
|
||||
aliases: []
|
||||
returnType: time.Time
|
||||
signatures: [.AddDate YEARS MONTHS DAYS]
|
||||
relatedFunctions: []
|
||||
keywords: [dates,time]
|
||||
signature: [".AddDate YEARS MONTHS DAYS"]
|
||||
relatedfuncs: [now]
|
||||
---
|
||||
|
||||
```go-html-template
|
||||
+10
-18
@@ -1,24 +1,16 @@
|
||||
---
|
||||
title: collections.After
|
||||
linkTitle: after
|
||||
description: Slices an array to the items after the Nth item.
|
||||
title: after
|
||||
description: "`after` slices an array to only the items after the <em>N</em>th item."
|
||||
categories: [functions]
|
||||
keywords: []
|
||||
menu:
|
||||
docs:
|
||||
parent: functions
|
||||
function:
|
||||
aliases: [after]
|
||||
returnType: any
|
||||
signatures: [collections.After INDEX COLLECTION]
|
||||
relatedFunctions:
|
||||
- collections.After
|
||||
- collections.First
|
||||
- collections.Last
|
||||
aliases: [/functions/after]
|
||||
keywords: [iteration]
|
||||
signature: ["after INDEX COLLECTION"]
|
||||
relatedfuncs: [last,first,seq]
|
||||
---
|
||||
|
||||
The following shows `after` being used in conjunction with the [`slice`]function:
|
||||
The following shows `after` being used in conjunction with the [`slice` function][slice]:
|
||||
|
||||
```go-html-template
|
||||
{{ $data := slice "one" "two" "three" "four" }}
|
||||
@@ -30,7 +22,7 @@ The following shows `after` being used in conjunction with the [`slice`]function
|
||||
|
||||
## Example of `after` with `first`: 2nd–4th most recent articles
|
||||
|
||||
You can use `after` in combination with the [`first`] function and Hugo's [powerful sorting methods][lists]. Let's assume you have a list page at `example.com/articles`. You have 10 articles, but you want your templating for the [list/section page] to show only two rows:
|
||||
You can use `after` in combination with the [`first` function] and Hugo's [powerful sorting methods][lists]. Let's assume you have a list page at `example.com/articles`. You have 10 articles, but you want your templating for the [list/section page] to show only two rows:
|
||||
|
||||
1. The top row is titled "Featured" and shows only the most recently published article (i.e. by `publishdate` in the content files' front matter).
|
||||
2. The second row is titled "Recent Articles" and shows only the 2nd- to 4th-most recently published articles.
|
||||
@@ -60,7 +52,7 @@ You can use `after` in combination with the [`first`] function and Hugo's [power
|
||||
{{ end }}
|
||||
{{< /code >}}
|
||||
|
||||
[`first`]: /functions/collections/first
|
||||
[list/section page]: /templates/section-templates
|
||||
[`first` function]: /functions/first/
|
||||
[list/section page]: /templates/section-templates/
|
||||
[lists]: /templates/lists/#order-content
|
||||
[`slice`]: /functions/collections/slice/
|
||||
[slice]: /functions/slice/
|
||||
+5
-12
@@ -1,20 +1,13 @@
|
||||
---
|
||||
title: urls.Anchorize
|
||||
linkTitle: anchorize
|
||||
description: Takes a string and sanitizes it the same way as the [`defaultMarkdownHandler`](/getting-started/configuration-markup#default-configuration) does for markdown headers.
|
||||
title: anchorize
|
||||
description: Takes a string and sanitizes it the same way as the [`defaultMarkdownHandler`](/getting-started/configuration-markup#configure-markup) does for markdown headers.
|
||||
categories: [functions]
|
||||
keywords: []
|
||||
menu:
|
||||
docs:
|
||||
parent: functions
|
||||
function:
|
||||
aliases: [anchorize]
|
||||
returnType: string
|
||||
signatures: [urls.Anchorize INPUT]
|
||||
relatedFunctions:
|
||||
- urls.Anchorize
|
||||
- urls.URLize
|
||||
aliases: [/functions/anchorize]
|
||||
keywords: [markdown,strings]
|
||||
signature: ["anchorize INPUT"]
|
||||
relatedfuncs: [humanize]
|
||||
---
|
||||
|
||||
If [Goldmark](/getting-started/configuration-markup#goldmark) is set as `defaultMarkdownHandler`, the sanitizing logic adheres to the setting [`markup.goldmark.parser.autoHeadingIDType`](/getting-started/configuration-markup#goldmark).
|
||||
@@ -0,0 +1,37 @@
|
||||
---
|
||||
title: append
|
||||
description: "`append` appends one or more values to a slice and returns the resulting slice."
|
||||
categories: [functions]
|
||||
menu:
|
||||
docs:
|
||||
parent: functions
|
||||
keywords: [collections]
|
||||
signature: ["COLLECTION | append VALUE [VALUE]...", "COLLECTION | append COLLECTION"]
|
||||
relatedfuncs: [last,first,where,slice]
|
||||
---
|
||||
|
||||
An example appending single values:
|
||||
|
||||
```go-html-template
|
||||
{{ $s := slice "a" "b" "c" }}
|
||||
{{ $s = $s | append "d" "e" }}
|
||||
{{/* $s now contains a []string with elements "a", "b", "c", "d", and "e" */}}
|
||||
|
||||
```
|
||||
|
||||
The same example appending a slice to a slice:
|
||||
|
||||
```go-html-template
|
||||
{{ $s := slice "a" "b" "c" }}
|
||||
{{ $s = $s | append (slice "d" "e") }}
|
||||
```
|
||||
|
||||
If a slice contains other slices, further slices will be appended as values:
|
||||
|
||||
```go-html-template
|
||||
{{ $s := slice (slice "a" "b") (slice "c" "d") }}
|
||||
{{ $s = $s | append (slice "e" "f") (slice "g" "h") }}
|
||||
{{/* $s now contains a [][]string containing four slices: ["a" "b"], ["c" "d"], ["e" "f"], and ["g" "h"] */}}
|
||||
```
|
||||
|
||||
The `append` function works for all types, including `Pages`.
|
||||
@@ -0,0 +1,105 @@
|
||||
---
|
||||
title: apply
|
||||
description: Given an array or slice, `apply` returns a new slice with a function applied over it.
|
||||
categories: [functions]
|
||||
menu:
|
||||
docs:
|
||||
parent: functions
|
||||
keywords: [advanced]
|
||||
signature: ["apply COLLECTION FUNCTION [PARAM...]"]
|
||||
relatedfuncs: []
|
||||
---
|
||||
|
||||
`apply` expects at least three parameters, depending on the function being applied.
|
||||
|
||||
1. The first parameter is the sequence to operate on.
|
||||
2. The second parameter is the name of the function as a string, which must be the name of a valid [Hugo function][functions].
|
||||
3. After that, the parameters to the applied function are provided, with the string `"."` standing in for each element of the sequence the function is to be applied against.
|
||||
|
||||
Here is an example of a content file with `names:` as a front matter field:
|
||||
|
||||
{{< code-toggle file="content/example.md" fm=true copy=false >}}
|
||||
title: Example
|
||||
names: [ "Derek Perkins", "Joe Bergevin", "Tanner Linsley" ]
|
||||
{{< /code-toggle >}}
|
||||
|
||||
You can then use `apply` as follows:
|
||||
|
||||
```go-html-template
|
||||
{{ apply .Params.names "urlize" "." }}
|
||||
```
|
||||
|
||||
Which will result in the following:
|
||||
|
||||
```
|
||||
"derek-perkins", "joe-bergevin", "tanner-linsley"
|
||||
```
|
||||
|
||||
This is *roughly* equivalent to using the following with [range]:
|
||||
|
||||
```go-html-template
|
||||
{{ range .Params.names }}{{ . | urlize }}{{ end }}
|
||||
```
|
||||
|
||||
However, it is not possible to provide the output of a range to the [`delimit` function][delimit], so you need to `apply` it.
|
||||
|
||||
If you have `post-tag-list.html` and `post-tag-link.html` as [partials], you *could* use the following snippets, respectively:
|
||||
|
||||
{{< code file="layouts/partials/post-tag-list.html" copy=false >}}
|
||||
{{ with .Params.tags }}
|
||||
<div class="tags-list">
|
||||
Tags:
|
||||
{{ $len := len . }}
|
||||
{{ if eq $len 1 }}
|
||||
{{ partial "post-tag-link.html" (index . 0) }}
|
||||
{{ else }}
|
||||
{{ $last := sub $len 1 }}
|
||||
{{ range first $last . }}
|
||||
{{ partial "post-tag-link.html" . }},
|
||||
{{ end }}
|
||||
{{ partial "post-tag-link.html" (index . $last) }}
|
||||
{{ end }}
|
||||
</div>
|
||||
{{ end }}
|
||||
{{< /code >}}
|
||||
|
||||
{{< code file="layouts/partials/post-tag-link.html" copy=false >}}
|
||||
<a class="post-tag post-tag-{{ . | urlize }}" href="/tags/{{ . | urlize }}">{{ . }}</a>
|
||||
{{< /code >}}
|
||||
|
||||
This works, but the complexity of `post-tag-list.html` is fairly high. The Hugo template needs to perform special behavior for the case where there’s only one tag, and it has to treat the last tag as special. Additionally, the tag list will be rendered something like `Tags: tag1 , tag2 , tag3` because of the way that the HTML is generated and then interpreted by a browser.
|
||||
|
||||
This first version of `layouts/partials/post-tag-list.html` separates all of the operations for ease of reading. The combined and DRYer version is shown next:
|
||||
|
||||
```go-html-template
|
||||
{{ with .Params.tags }}
|
||||
<div class="tags-list">
|
||||
Tags:
|
||||
{{ $sort := sort . }}
|
||||
{{ $links := apply $sort "partial" "post-tag-link.html" "." }}
|
||||
{{ $clean := apply $links "chomp" "." }}
|
||||
{{ delimit $clean ", " }}
|
||||
</div>
|
||||
{{ end }}
|
||||
```
|
||||
|
||||
Now in the completed version, you can sort the tags, convert the tags to links with `layouts/partials/post-tag-link.html`, [chomp] off stray newlines, and join the tags together in a delimited list for presentation. Here is an even DRYer version of the preceding example:
|
||||
|
||||
{{< code file="layouts/partials/post-tag-list.html" >}}
|
||||
{{ with .Params.tags }}
|
||||
<div class="tags-list">
|
||||
Tags:
|
||||
{{ delimit (apply (apply (sort .) "partial" "post-tag-link.html" ".") "chomp" ".") ", " }}
|
||||
</div>
|
||||
{{ end }}
|
||||
{{< /code >}}
|
||||
|
||||
{{% note %}}
|
||||
`apply` does not work when receiving the sequence as an argument through a pipeline.
|
||||
{{% /note %}}
|
||||
|
||||
[chomp]: /functions/chomp/ "See documentation for the chomp function"
|
||||
[delimit]: /functions/delimit/ "See documentation for the delimit function"
|
||||
[functions]: /functions/ "See the full list of Hugo functions to see what can be passed as an argument to the apply function."
|
||||
[partials]: /templates/partials/
|
||||
[range]: /functions/range/ "Learn the importance of the range function, a fundamental keyword in both Hugo templates and the Go programming language."
|
||||
@@ -0,0 +1,28 @@
|
||||
---
|
||||
title: base64
|
||||
description: "`base64Encode` and `base64Decode` let you easily decode content with a base64 encoding and vice versa through pipes."
|
||||
categories: [functions]
|
||||
menu:
|
||||
docs:
|
||||
parent: functions
|
||||
keywords: []
|
||||
relatedfuncs: []
|
||||
signature: ["base64Decode INPUT", "base64Encode INPUT"]
|
||||
---
|
||||
|
||||
```go-html-template
|
||||
{{ "Hugo" | base64Encode }} → "SHVnbw=="
|
||||
{{ "SHVnbw==" | base64Decode }} → "Hugo"
|
||||
```
|
||||
|
||||
## `base64` with APIs
|
||||
|
||||
Using base64 to decode and encode becomes really powerful if we have to handle
|
||||
responses from APIs.
|
||||
|
||||
```go-html-template
|
||||
{{ $resp := getJSON "https://api.github.com/repos/gohugoio/hugo/readme" }}
|
||||
{{ $resp.content | base64Decode | markdownify }}
|
||||
```
|
||||
|
||||
The response of the GitHub API contains the base64-encoded version of the [README.md](https://github.com/gohugoio/hugo/blob/master/README.md) in the Hugo repository. Now we can decode it and parse the Markdown. The final output will look similar to the rendered version on GitHub.
|
||||
@@ -0,0 +1,20 @@
|
||||
---
|
||||
title: chomp
|
||||
toc: true
|
||||
description: Removes any trailing newline characters.
|
||||
categories: [functions]
|
||||
menu:
|
||||
docs:
|
||||
parent: functions
|
||||
keywords: [trim]
|
||||
signature:
|
||||
- "chomp INPUT"
|
||||
- "strings.Chomp INPUT"
|
||||
relatedfuncs: [truncate]
|
||||
---
|
||||
|
||||
Useful in a pipeline to remove newlines added by other processing (e.g., [`markdownify`](/functions/markdownify/)).
|
||||
|
||||
```go-html-template
|
||||
{{ chomp "<p>Blockhead</p>\n" }} → "<p>Blockhead</p>"
|
||||
```
|
||||
@@ -1,107 +0,0 @@
|
||||
---
|
||||
title: collections.Append
|
||||
linkTitle: append
|
||||
description: Appends one or more elements to a slice and returns the resulting slice.
|
||||
categories: [functions]
|
||||
keywords: []
|
||||
menu:
|
||||
docs:
|
||||
parent: functions
|
||||
function:
|
||||
aliases: [append]
|
||||
returnType: any
|
||||
signatures:
|
||||
- COLLECTION | collections.Append ELEMENT [ELEMENT]...
|
||||
- COLLECTION | collections.Append COLLECTION
|
||||
relatedFunctions:
|
||||
- collections.Append
|
||||
- collections.Merge
|
||||
- collections.Slice
|
||||
aliases: [/functions/append]
|
||||
---
|
||||
|
||||
This function appends all elements, excluding the last, to the last element. This allows [pipe](/getting-started/glossary/#pipeline) constructs as shown below.
|
||||
|
||||
Append a single element to a slice:
|
||||
|
||||
```go-html-template
|
||||
{{ $s := slice "a" "b" }}
|
||||
{{ $s }} → [a b]
|
||||
|
||||
{{ $s = $s | append "c" }}
|
||||
{{ $s }} → [a b c]
|
||||
```
|
||||
|
||||
Append two elements to a slice:
|
||||
|
||||
```go-html-template
|
||||
{{ $s := slice "a" "b" }}
|
||||
{{ $s }} → [a b]
|
||||
|
||||
{{ $s = $s | append "c" "d" }}
|
||||
{{ $s }} → [a b c d]
|
||||
```
|
||||
|
||||
Append two elements, as a slice, to a slice. This produces the same result as the previous example:
|
||||
|
||||
```go-html-template
|
||||
{{ $s := slice "a" "b" }}
|
||||
{{ $s }} → [a b]
|
||||
|
||||
{{ $s = $s | append (slice "c" "d") }}
|
||||
{{ $s }} → [a b c d]
|
||||
```
|
||||
|
||||
Start with an empty slice:
|
||||
|
||||
```go-html-template
|
||||
{{ $s := slice }}
|
||||
{{ $s }} → []
|
||||
|
||||
{{ $s = $s | append "a" }}
|
||||
{{ $s }} → [a]
|
||||
|
||||
{{ $s = $s | append "b" "c" }}
|
||||
{{ $s }} → [a b c]
|
||||
|
||||
{{ $s = $s | append (slice "d" "e") }}
|
||||
{{ $s }} → [a b c d e]
|
||||
```
|
||||
|
||||
If you start with a slice of a slice:
|
||||
|
||||
```go-html-template
|
||||
{{ $s := slice (slice "a" "b") }}
|
||||
{{ $s }} → [[a b]]
|
||||
|
||||
{{ $s = $s | append (slice "c" "d") }}
|
||||
{{ $s }} → [[a b] [c d]]
|
||||
```
|
||||
|
||||
To create a slice of slices, starting with an empty slice:
|
||||
|
||||
```go-html-template
|
||||
{{ $s := slice }}
|
||||
{{ $s }} → []
|
||||
|
||||
{{ $s = $s | append (slice (slice "a" "b")) }}
|
||||
{{ $s }} → [[a b]]
|
||||
|
||||
{{ $s = $s | append (slice "c" "d") }}
|
||||
{{ $s }} → [[a b] [c d]]
|
||||
```
|
||||
|
||||
Although the elements in the examples above are strings, you can use the `append` function with any data type, including Pages. For example, on the home page of a corporate site, to display links to the two most recent press releases followed by links to the four most recent articles:
|
||||
|
||||
```go-html-template
|
||||
{{ $p := where site.RegularPages "Type" "press-releases" | first 2 }}
|
||||
{{ $p = $p | append (where site.RegularPages "Type" "articles" | first 4) }}
|
||||
|
||||
{{ with $p }}
|
||||
<ul>
|
||||
{{ range . }}
|
||||
<li><a href="{{ .RelPermalink }}">{{ .LinkTitle }}</a></li>
|
||||
{{ end }}
|
||||
</ul>
|
||||
{{ end }}
|
||||
```
|
||||
@@ -1,37 +0,0 @@
|
||||
---
|
||||
title: collections.Apply
|
||||
linkTitle: apply
|
||||
description: Returns a new collection with each element transformed by the given function.
|
||||
categories: [functions]
|
||||
keywords: []
|
||||
menu:
|
||||
docs:
|
||||
parent: functions
|
||||
function:
|
||||
aliases: [apply]
|
||||
returnType: '[]any'
|
||||
signatures: [collections.Apply COLLECTION FUNCTION PARAM...]
|
||||
relatedFunctions:
|
||||
- collections.Apply
|
||||
- collections.Delimit
|
||||
- collections.In
|
||||
- collections.Reverse
|
||||
- collections.Seq
|
||||
- collections.Slice
|
||||
aliases: [/functions/apply]
|
||||
---
|
||||
|
||||
The `apply` function takes three or more arguments, depending on the function being applied to the collection elements.
|
||||
|
||||
The first argument is the collection itself, the second argument is the function name, and the remaining arguments are passed to the function, with the string `"."` representing the collection element.
|
||||
|
||||
|
||||
```go-html-template
|
||||
{{ $s := slice "hello" "world" }}
|
||||
|
||||
{{ $s = apply $s "strings.FirstUpper" "." }}
|
||||
{{ $s }} → [Hello World]
|
||||
|
||||
{{ $s = apply $s "strings.Replace" "." "l" "_" }}
|
||||
{{ $s }} → [He__o Wor_d]
|
||||
```
|
||||
@@ -1,40 +0,0 @@
|
||||
---
|
||||
title: collections.EchoParam
|
||||
linkTitle: echoParam
|
||||
description: Prints a parameter if it is set.
|
||||
categories: [functions]
|
||||
keywords: []
|
||||
menu:
|
||||
docs:
|
||||
parent: functions
|
||||
function:
|
||||
aliases: [echoParam]
|
||||
returnType: any
|
||||
signatures: [collections.EchoParam COLLECTION KEY]
|
||||
relatedFunctions: []
|
||||
aliases: [/functions/echoparam]
|
||||
---
|
||||
|
||||
For example, consider this site configuration:
|
||||
|
||||
{{< code-toggle file=hugo copy=false >}}
|
||||
[params.footer]
|
||||
poweredBy = 'Hugo'
|
||||
{{< /code-toggle >}}
|
||||
|
||||
To print the value of `poweredBy`:
|
||||
|
||||
```go-html-template
|
||||
{{ echoParam site.Params.footer "poweredby" }} → Hugo
|
||||
```
|
||||
|
||||
{{% note %}}
|
||||
When using the `echoParam` function you must reference the key using lower case. See the previous example.
|
||||
|
||||
The `echoParam` function will be deprecated in a future release. Instead, use either of the constructs below.
|
||||
{{% /note %}}
|
||||
|
||||
```go-html-template
|
||||
{{ site.Params.footer.poweredBy }} → Hugo
|
||||
{{ index site.Params.footer "poweredBy" }} → Hugo
|
||||
```
|
||||
@@ -1,40 +0,0 @@
|
||||
---
|
||||
title: collections.Group
|
||||
linkTitle: group
|
||||
description: Groups a list of pages.
|
||||
categories: [functions]
|
||||
keywords: []
|
||||
menu:
|
||||
docs:
|
||||
parent: functions
|
||||
function:
|
||||
aliases: [group]
|
||||
returnType: any
|
||||
signatures: [PAGES | collections.Group KEY]
|
||||
relatedFunctions:
|
||||
- collections.Dictionary
|
||||
- collections.Group
|
||||
- collections.Index
|
||||
- collections.IsSet
|
||||
- collections.Where
|
||||
aliases: [/functions/group]
|
||||
---
|
||||
|
||||
{{< code file="layouts/partials/groups.html" >}}
|
||||
{{ $new := .Site.RegularPages | first 10 | group "New" }}
|
||||
{{ $old := .Site.RegularPages | last 10 | group "Old" }}
|
||||
{{ $groups := slice $new $old }}
|
||||
{{ range $groups }}
|
||||
<h3>{{ .Key }}{{/* Prints "New", "Old" */}}</h3>
|
||||
<ul>
|
||||
{{ range .Pages }}
|
||||
<li>
|
||||
<a href="{{ .Permalink }}">{{ .Title }}</a>
|
||||
<div class="meta">{{ .Date.Format "Mon, Jan 2, 2006" }}</div>
|
||||
</li>
|
||||
{{ end }}
|
||||
</ul>
|
||||
{{ end }}
|
||||
{{< /code >}}
|
||||
|
||||
The page group you get from `group` is of the same type you get from the built-in [group methods](/templates/lists#group-content) in Hugo. The above example can be [paginated](/templates/pagination/#list-paginator-pages).
|
||||
@@ -1,38 +0,0 @@
|
||||
---
|
||||
title: collections.In
|
||||
linkTitle: in
|
||||
description: Reports whether an element is in an array or slice, or if a substring is in a string.
|
||||
keywords: []
|
||||
menu:
|
||||
docs:
|
||||
parent: functions
|
||||
function:
|
||||
aliases: [in]
|
||||
returnType: bool
|
||||
signatures: [collections.In SET ITEM]
|
||||
relatedFunctions:
|
||||
- collections.Slice
|
||||
aliases: [/functions/in]
|
||||
---
|
||||
|
||||
|
||||
|
||||
```go-html-template
|
||||
{{ $s := slice "a" "b" "c" }}
|
||||
{{ in $s "b" }} → true
|
||||
```
|
||||
|
||||
```go-html-template
|
||||
{{ $s := slice 1 2 3 }}
|
||||
{{ in $s 2 }} → true
|
||||
```
|
||||
|
||||
```go-html-template
|
||||
{{ $s := slice 1.11 2.22 3.33 }}
|
||||
{{ in $s 2.22 }} → true
|
||||
```
|
||||
|
||||
```go-html-template
|
||||
{{ $s := "abc" }}
|
||||
{{ in $s "b" }} → true
|
||||
```
|
||||
@@ -1,52 +0,0 @@
|
||||
---
|
||||
title: collections.IsSet
|
||||
linkTitle: isset
|
||||
description: Reports whether the key exists within the collection.
|
||||
categories: [functions]
|
||||
keywords: []
|
||||
menu:
|
||||
docs:
|
||||
parent: functions
|
||||
function:
|
||||
aliases: [isset]
|
||||
returnType: bool
|
||||
signatures: [collections.IsSet COLLECTION KEY]
|
||||
relatedFunctions:
|
||||
- collections.Dictionary
|
||||
- collections.Group
|
||||
- collections.Index
|
||||
- collections.IsSet
|
||||
- collections.Where
|
||||
aliases: [/functions/isset]
|
||||
---
|
||||
|
||||
For example, consider this site configuration:
|
||||
|
||||
{{< code-toggle file=hugo copy=false >}}
|
||||
[params]
|
||||
showHeroImage = false
|
||||
{{< /code-toggle >}}
|
||||
|
||||
It the value of `showHeroImage` is `true`, we can detect that it exists using either `if` or `with`:
|
||||
|
||||
```go-html-template
|
||||
{{ if site.Params.showHeroImage }}
|
||||
{{ site.Params.showHeroImage }} → true
|
||||
{{ end }}
|
||||
|
||||
{{ with site.Params.showHeroImage }}
|
||||
{{ . }} → true
|
||||
{{ end }}
|
||||
```
|
||||
|
||||
But if the value of `showHeroImage` is `false`, we can't use either `if` or `with` to detect its existence. In this case, you must use the `isset` function:
|
||||
|
||||
```go-html-template
|
||||
{{ if isset site.Params "showheroimage" }}
|
||||
<p>The showHeroImage parameter is set to {{ site.Params.showHeroImage }}.<p>
|
||||
{{ end }}
|
||||
```
|
||||
|
||||
{{% note %}}
|
||||
When using the `isset` function you must reference the key using lower case. See the previous example.
|
||||
{{% /note %}}
|
||||
@@ -1,45 +0,0 @@
|
||||
---
|
||||
title: collections.KeyVals
|
||||
linkTitle: keyVals
|
||||
description: Returns a KeyVals struct.
|
||||
categories: [functions]
|
||||
keywords: []
|
||||
menu:
|
||||
docs:
|
||||
parent: functions
|
||||
function:
|
||||
aliases: [keyVals]
|
||||
returnType: KeyValues
|
||||
signatures: [collections.KeyVals KEY VALUES...]
|
||||
relatedFunctions: []
|
||||
aliases: [/functions/keyvals]
|
||||
---
|
||||
|
||||
The primary application for this function is the definition of the `namedSlices` parameter in the options map passed to the `.Related` method on the `Page` object.
|
||||
|
||||
See [related content](/content-management/related).
|
||||
|
||||
```go-html-template
|
||||
{{ $kv := keyVals "foo" "a" "b" "c" }}
|
||||
```
|
||||
|
||||
The resulting data structure is:
|
||||
|
||||
```json
|
||||
{
|
||||
"Key": "foo",
|
||||
"Values": [
|
||||
"a",
|
||||
"b",
|
||||
"c"
|
||||
]
|
||||
}
|
||||
```
|
||||
|
||||
To extract the key and values:
|
||||
|
||||
```go-html-template
|
||||
|
||||
{{ $kv.Key }} → foo
|
||||
{{ $kv.Values }} → [a b c]
|
||||
```
|
||||
@@ -1,25 +0,0 @@
|
||||
---
|
||||
title: collections.Last
|
||||
linkTitle: last
|
||||
description: Slices an array to the last N elements.
|
||||
categories: [functions]
|
||||
keywords: []
|
||||
menu:
|
||||
docs:
|
||||
parent: functions
|
||||
function:
|
||||
aliases: [last]
|
||||
returnType: any
|
||||
signatures: [collections.Last INDEX COLLECTION]
|
||||
relatedFunctions:
|
||||
- collections.After
|
||||
- collections.First
|
||||
- collections.Last
|
||||
aliases: [/functions/last]
|
||||
---
|
||||
|
||||
```go-html-template
|
||||
{{ range last 10 .Pages }}
|
||||
{{ .Render "summary" }}
|
||||
{{ end }}
|
||||
```
|
||||
@@ -1,22 +0,0 @@
|
||||
---
|
||||
title: collections.NewScratch
|
||||
linkTitle: newScratch
|
||||
description: Creates a new Scratch which can be used to store values in a thread safe way.
|
||||
categories: [functions]
|
||||
keywords: []
|
||||
menu:
|
||||
docs:
|
||||
parent: functions
|
||||
function:
|
||||
aliases: [newScratch]
|
||||
returnType: Scratch
|
||||
signatures: [collections.NewScratch ]
|
||||
relatedFunctions: []
|
||||
---
|
||||
|
||||
```go-html-template
|
||||
{{ $scratch := newScratch }}
|
||||
{{ $scratch.Add "b" 2 }}
|
||||
{{ $scratch.Add "b" 2 }}
|
||||
{{ $scratch.Get "b" }} → 4
|
||||
```
|
||||
@@ -1,26 +0,0 @@
|
||||
---
|
||||
title: collections.Reverse
|
||||
description: Reverses the order of a collection.
|
||||
categories: [functions]
|
||||
keywords: []
|
||||
menu:
|
||||
docs:
|
||||
parent: functions
|
||||
function:
|
||||
aliases: []
|
||||
returnType: any
|
||||
signatures: [collections.Reverse COLLECTION]
|
||||
relatedFunctions:
|
||||
- collections.Apply
|
||||
- collections.Delimit
|
||||
- collections.In
|
||||
- collections.Reverse
|
||||
- collections.Seq
|
||||
- collections.Slice
|
||||
aliases: [/functions/collections.reverse]
|
||||
---
|
||||
|
||||
|
||||
```go-html-template
|
||||
{{ slice 2 1 3 | collections.Reverse }} → [3 1 2]
|
||||
```
|
||||
@@ -1,30 +0,0 @@
|
||||
---
|
||||
title: collections.Slice
|
||||
linkTitle: slice
|
||||
description: Creates a slice (array) of all passed arguments.
|
||||
categories: [functions]
|
||||
keywords: []
|
||||
menu:
|
||||
docs:
|
||||
parent: functions
|
||||
function:
|
||||
aliases: [slice]
|
||||
returnType: any
|
||||
signatures: [collections.Slice ITEM...]
|
||||
relatedFunctions:
|
||||
- collections.Append
|
||||
- collections.Apply
|
||||
- collections.Delimit
|
||||
- collections.In
|
||||
- collections.Reverse
|
||||
- collections.Seq
|
||||
- collections.Slice
|
||||
aliases: [/functions/slice]
|
||||
---
|
||||
|
||||
One use case is the concatenation of elements in combination with the [`delimit` function]:
|
||||
|
||||
```go-html-template
|
||||
{{ $s := slice "a" "b" "c" }}
|
||||
{{ $s }} → [a b c]
|
||||
```
|
||||
@@ -1,28 +0,0 @@
|
||||
---
|
||||
title: collections.SymDiff
|
||||
linkTitle: symdiff
|
||||
description: Returns the symmetric difference of two collections.
|
||||
categories: [functions]
|
||||
keywords: []
|
||||
menu:
|
||||
docs:
|
||||
parent: functions
|
||||
function:
|
||||
aliases: [symdiff]
|
||||
returnType: any
|
||||
signatures: [COLLECTION | collections.SymDiff COLLECTION]
|
||||
relatedFunctions:
|
||||
- collections.Complement
|
||||
- collections.Intersect
|
||||
- collections.SymDiff
|
||||
- collections.Union
|
||||
aliases: [/functions/symdiff]
|
||||
---
|
||||
|
||||
Example:
|
||||
|
||||
```go-html-template
|
||||
{{ slice 1 2 3 | symdiff (slice 3 4) }} → [1 2 4]
|
||||
```
|
||||
|
||||
Also see https://en.wikipedia.org/wiki/Symmetric_difference
|
||||
@@ -1,25 +0,0 @@
|
||||
---
|
||||
title: collections.Uniq
|
||||
linkTitle: uniq
|
||||
description: Takes in a slice or array and returns a slice with duplicate elements removed.
|
||||
categories: [functions]
|
||||
keywords: []
|
||||
menu:
|
||||
docs:
|
||||
parent: functions
|
||||
function:
|
||||
aliases: [uniq]
|
||||
returnType: any
|
||||
signatures: [collections.Uniq COLLECTION]
|
||||
relatedFunctions:
|
||||
- collections.Reverse
|
||||
- collections.Shuffle
|
||||
- collections.Sort
|
||||
- collections.Uniq
|
||||
aliases: [/functions/uniq]
|
||||
---
|
||||
|
||||
|
||||
```go-html-template
|
||||
{{ slice 1 3 2 1 | uniq }} → [1 3 2]
|
||||
```
|
||||
@@ -1,47 +0,0 @@
|
||||
---
|
||||
title: compare.Conditional
|
||||
linkTitle: cond
|
||||
description: Returns one of two arguments depending on the value of the control argument.
|
||||
categories: [functions]
|
||||
keywords: []
|
||||
menu:
|
||||
docs:
|
||||
parent: functions
|
||||
function:
|
||||
aliases: [cond]
|
||||
returnType: any
|
||||
signatures: [compare.Conditional CONTROL ARG1 ARG2]
|
||||
relatedFunctions:
|
||||
- compare.Conditional
|
||||
- compare.Default
|
||||
aliases: [/functions/cond]
|
||||
---
|
||||
|
||||
The CONTROL argument is a boolean value that indicates whether the function should return ARG1 or ARG2. If CONTROL is `true`, the function returns ARG1. Otherwise, the function returns ARG2.
|
||||
|
||||
```go-html-template
|
||||
{{ $qty := 42 }}
|
||||
{{ cond (le $qty 3) "few" "many" }} → "many"
|
||||
```
|
||||
|
||||
The CONTROL argument must be either `true` or `false`. To cast a non-boolean value to boolean, pass it through the `not` operator twice.
|
||||
|
||||
```go-html-template
|
||||
{{ cond (42 | not | not) "truthy" "falsy" }} → "truthy"
|
||||
{{ cond ("" | not | not) "truthy" "falsy" }} → "falsy"
|
||||
```
|
||||
|
||||
{{% note %}}
|
||||
Unlike [ternary operators] in other languages, the `cond` function does not perform [short-circuit evaluation]. The function evaluates both ARG1 and ARG2, regardless of the CONTROL value.
|
||||
|
||||
[short-circuit evaluation]: https://en.wikipedia.org/wiki/Short-circuit_evaluation
|
||||
[ternary operators]: https://en.wikipedia.org/wiki/Ternary_conditional_operator
|
||||
{{% /note %}}
|
||||
|
||||
|
||||
Due to the absence of short-circuit evaluation, these examples throw an error:
|
||||
|
||||
```go-html-template
|
||||
{{ cond true "true" (div 1 0) }}
|
||||
{{ cond false (div 1 0) "false" }}
|
||||
```
|
||||
+7
-14
@@ -1,22 +1,15 @@
|
||||
---
|
||||
title: collections.Complement
|
||||
linkTitle: complement
|
||||
title: complement
|
||||
description: Returns the elements of the last collection that are not in any of the others.
|
||||
categories: [functions]
|
||||
keywords: []
|
||||
menu:
|
||||
docs:
|
||||
parent: functions
|
||||
function:
|
||||
aliases: [complement]
|
||||
returnType: any
|
||||
signatures: ['collections.Complement COLLECTION [COLLECTION]...']
|
||||
relatedFunctions:
|
||||
- collections.Complement
|
||||
- collections.Intersect
|
||||
- collections.SymDiff
|
||||
- collections.Union
|
||||
aliases: [/functions/complement]
|
||||
keywords: [collections]
|
||||
signature:
|
||||
- "complement COLLECTION [COLLECTION]..."
|
||||
- "collections.Complement COLLECTION [COLLECTION]..."
|
||||
relatedfuncs: [intersect,symdiff,union]
|
||||
---
|
||||
|
||||
To find the elements within `$c3` that do not exist in `$c1` or `$c2`:
|
||||
@@ -64,7 +57,7 @@ To list everything except blog articles (`blog`) and frequently asked questions
|
||||
{{% note %}}
|
||||
Although the example above demonstrates the `complement` function, you could use the [`where`] function as well:
|
||||
|
||||
[`where`]: /functions/collections/where
|
||||
[`where`]: /functions/where/
|
||||
{{% /note %}}
|
||||
|
||||
```go-html-template
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user