Repository: gohugoio/hugo
Pull request #13832 (2025-07-04 08:56:43)

build(deps): bump github.com/alecthomas/chroma/v2 from 2.18.0 to 2.19.0
Bumps [github.com/alecthomas/chroma/v2](https://github.com/alecthomas/chroma) from 2.18.0 to 2.19.0.
<details>
<summary>Release notes</summary>
<p><em>Sourced from <a href="https://github.com/alecthomas/chroma/releases">github.com/alecthomas/chroma/v2's releases</a>.</em></p>
<blockquote>
<h2>v2.19.0</h2>
<h2>Changelog</h2>
<ul>
<li>adeac8f feat: WASM playground</li>
<li>484750a chore: add uv</li>
<li>a5ceb28 fix: add lexer compile time validation for group by</li>
<li>cd5c4a8 docs(readme): update go reference badge to point to v2 and new domain (<a href="https://redirect.github.com/alecthomas/chroma/issues/1087">#1087</a>)</li>
<li>970eacc Add MoonScript lexer (<a href="https://redirect.github.com/alecthomas/chroma/issues/1091">#1091</a>)</li>
<li>6ffb465 chore(deps): update all non-major dependencies (<a href="https://redirect.github.com/alecthomas/chroma/issues/1082">#1082</a>)</li>
<li>2c20473 Various lexer &amp; style fixes for RPGLE (<a href="https://redirect.github.com/alecthomas/chroma/issues/1086">#1086</a>)</li>
<li>c803d79 fix(zig): detect zig object notation files as zig (<a href="https://redirect.github.com/alecthomas/chroma/issues/1085">#1085</a>)</li>
<li>bc60826 Add Core lexer (<a href="https://redirect.github.com/alecthomas/chroma/issues/1083">#1083</a>)</li>
<li>ffedbf4 fix(kotlin): detect kotlin script files as kotlin (<a href="https://redirect.github.com/alecthomas/chroma/issues/1081">#1081</a>)</li>
</ul>
</blockquote>
</details>
<details>
<summary>Commits</summary>
<ul>
<li><a href="https://github.com/alecthomas/chroma/commit/adeac8f5dbfb6806a51bcf07eefd89fc8a0aee6a"><code>adeac8f</code></a> feat: WASM playground</li>
<li><a href="https://github.com/alecthomas/chroma/commit/484750a96fc430f49d6b69cc2a2a8b7a67691446"><code>484750a</code></a> chore: add uv</li>
<li><a href="https://github.com/alecthomas/chroma/commit/a5ceb288f9822b1955de579a820719e9d5a39161"><code>a5ceb28</code></a> fix: add lexer compile time validation for group by</li>
<li><a href="https://github.com/alecthomas/chroma/commit/cd5c4a8d02afadcd9b5c213b67c5baaef15e444d"><code>cd5c4a8</code></a> docs(readme): update go reference badge to point to v2 and new domain (<a href="https://redirect.github.com/alecthomas/chroma/issues/1087">#1087</a>)</li>
<li><a href="https://github.com/alecthomas/chroma/commit/970eacc4957f822b03ca169cf72ed0ed464db933"><code>970eacc</code></a> Add MoonScript lexer (<a href="https://redirect.github.com/alecthomas/chroma/issues/1091">#1091</a>)</li>
<li><a href="https://github.com/alecthomas/chroma/commit/6ffb4659a4583e296e609c8a8fa82db31159af97"><code>6ffb465</code></a> chore(deps): update all non-major dependencies (<a href="https://redirect.github.com/alecthomas/chroma/issues/1082">#1082</a>)</li>
<li><a href="https://github.com/alecthomas/chroma/commit/2c20473d3dc0e10a1a9a9d5aa714e6d00e087198"><code>2c20473</code></a> Various lexer &amp; style fixes for RPGLE (<a href="https://redirect.github.com/alecthomas/chroma/issues/1086">#1086</a>)</li>
<li><a href="https://github.com/alecthomas/chroma/commit/c803d7988d7261db3fbb5b209ac9c0f2932cc92a"><code>c803d79</code></a> fix(zig): detect zig object notation files as zig (<a href="https://redirect.github.com/alecthomas/chroma/issues/1085">#1085</a>)</li>
<li><a href="https://github.com/alecthomas/chroma/commit/bc608267c112833788175d1e09a54dbf1ede750c"><code>bc60826</code></a> Add Core lexer (<a href="https://redirect.github.com/alecthomas/chroma/issues/1083">#1083</a>)</li>
<li><a href="https://github.com/alecthomas/chroma/commit/ffedbf45448f864136753f432103267d1ae1dab5"><code>ffedbf4</code></a> fix(kotlin): detect kotlin script files as kotlin (<a href="https://redirect.github.com/alecthomas/chroma/issues/1081">#1081</a>)</li>
<li>See full diff in <a href="https://github.com/alecthomas/chroma/compare/v2.18.0...v2.19.0">compare view</a></li>
</ul>
</details>
<br />


[![Dependabot compatibility score](https://dependabot-badges.githubapp.com/badges/compatibility_score?dependency-name=github.com/alecthomas/chroma/v2&package-manager=go_modules&previous-version=2.18.0&new-version=2.19.0)](https://docs.github.com/en/github/managing-security-vulnerabilities/about-dependabot-security-updates#about-compatibility-scores)

Dependabot will resolve any conflicts with this PR as long as you don't alter it yourself. You can also trigger a rebase manually by commenting `@dependabot rebase`.

[//]: # (dependabot-automerge-start)
[//]: # (dependabot-automerge-end)

---

<details>
<summary>Dependabot commands and options</summary>
<br />

You can trigger Dependabot actions by commenting on this PR:
- `@dependabot rebase` will rebase this PR
- `@dependabot recreate` will recreate this PR, overwriting any edits that have been made to it
- `@dependabot merge` will merge this PR after your CI passes on it
- `@dependabot squash and merge` will squash and merge this PR after your CI passes on it
- `@dependabot cancel merge` will cancel a previously requested merge and block automerging
- `@dependabot reopen` will reopen this PR if it is closed
- `@dependabot close` will close this PR and stop Dependabot recreating it. You can achieve the same result by closing it manually
- `@dependabot show <dependency name> ignore conditions` will show all of the ignore conditions of the specified dependency
- `@dependabot ignore this major version` will close this PR and stop Dependabot creating any more for this major version (unless you reopen the PR or upgrade to it yourself)
- `@dependabot ignore this minor version` will close this PR and stop Dependabot creating any more for this minor version (unless you reopen the PR or upgrade to it yourself)
- `@dependabot ignore this dependency` will close this PR and stop Dependabot creating any more for this dependency (unless you reopen the PR or upgrade to it yourself)


</details>


Patch:
diff --git a/config/allconfig/allconfig.go b/config/allconfig/allconfig.go
index 0db0be1d8..3366defd7 100644
--- a/config/allconfig/allconfig.go
+++ b/config/allconfig/allconfig.go
@@ -20,6 +20,7 @@ import (
 	"fmt"
 	"reflect"
 	"regexp"
+	"slices"
 	"sort"
 	"strconv"
 	"strings"
@@ -32,7 +33,6 @@ import (
 	"github.com/gohugoio/hugo/common/loggers"
 	"github.com/gohugoio/hugo/common/maps"
 	"github.com/gohugoio/hugo/common/paths"
-	"github.com/gohugoio/hugo/common/types"
 	"github.com/gohugoio/hugo/common/urls"
 	"github.com/gohugoio/hugo/config"
 	"github.com/gohugoio/hugo/config/privacy"
@@ -42,6 +42,7 @@ import (
 	"github.com/gohugoio/hugo/helpers"
 	"github.com/gohugoio/hugo/hugolib/segments"
 	"github.com/gohugoio/hugo/langs"
+	gc "github.com/gohugoio/hugo/markup/goldmark/goldmark_config"
 	"github.com/gohugoio/hugo/markup/markup_config"
 	"github.com/gohugoio/hugo/media"
 	"github.com/gohugoio/hugo/minifiers"
@@ -399,7 +400,6 @@ func (c *Config) CompileConfig(logger loggers.Logger) error {
 		hugo.DeprecateWithLogger("site config key paginate", "Use pagination.pagerSize instead.", "v0.128.0", logger.Logger())
 		c.Pagination.PagerSize = c.Paginate
 	}
-
 	if c.PaginatePath != "" {
 		hugo.DeprecateWithLogger("site config key paginatePath", "Use pagination.path instead.", "v0.128.0", logger.Logger())
 		c.Pagination.Path = c.PaginatePath
@@ -410,12 +410,10 @@ func (c *Config) CompileConfig(logger loggers.Logger) error {
 		hugo.DeprecateWithLogger("site config key privacy.twitter.disable", "Use privacy.x.disable instead.", "v0.141.0", logger.Logger())
 		c.Privacy.X.Disable = c.Privacy.Twitter.Disable
 	}
-
 	if c.Privacy.Twitter.EnableDNT {
 		hugo.DeprecateWithLogger("site config key privacy.twitter.enableDNT", "Use privacy.x.enableDNT instead.", "v0.141.0", logger.Logger())
 		c.Privacy.X.EnableDNT = c.Privacy.Twitter.EnableDNT
 	}
-
 	if c.Privacy.Twitter.Simple {
 		hugo.DeprecateWithLogger("site config key privacy.twitter.simple", "Use privacy.x.simple instead.", "v0.141.0", logger.Logger())
 		c.Privacy.X.Simple = c.Privacy.Twitter.Simple
@@ -436,6 +434,45 @@ func (c *Config) CompileConfig(logger loggers.Logger) error {
 		hugo.DeprecateWithLogger("the \":slugorfilename\" permalink token", "Use \":slugorcontentbasename\" instead.", "0.144.0", logger.Logger())
 	}
 
+	// Legacy render hook values.
+	alternativeDetails := fmt.Sprintf(
+		"Set to %q if previous value was false, or set to %q if previous value was true.",
+		gc.RenderHookUseEmbeddedNever,
+		gc.RenderHookUseEmbeddedFallback,
+	)
+	if c.Markup.Goldmark.RenderHooks.Image.EnableDefault != nil {
+		alternative := "Use markup.goldmark.renderHooks.image.useEmbedded instead." + " " + alternativeDetails
+		hugo.DeprecateWithLogger("site config key markup.goldmark.renderHooks.image.enableDefault", alternative, "0.148.0", logger.Logger())
+		if *c.Markup.Goldmark.RenderHooks.Image.EnableDefault {
+			c.Markup.Goldmark.RenderHooks.Image.UseEmbedded = gc.RenderHookUseEmbeddedFallback
+		} else {
+			c.Markup.Goldmark.RenderHooks.Image.UseEmbedded = gc.RenderHookUseEmbeddedNever
+		}
+	}
+	if c.Markup.Goldmark.RenderHooks.Link.EnableDefault != nil {
+		alternative := "Use markup.goldmark.renderHooks.link.useEmbedded instead." + " " + alternativeDetails
+		hugo.DeprecateWithLogger("site config key markup.goldmark.renderHooks.link.enableDefault", alternative, "0.148.0", logger.Logger())
+		if *c.Markup.Goldmark.RenderHooks.Link.EnableDefault {
+			c.Markup.Goldmark.RenderHooks.Link.UseEmbedded = gc.RenderHookUseEmbeddedFallback
+		} else {
+			c.Markup.Goldmark.RenderHooks.Link.UseEmbedded = gc.RenderHookUseEmbeddedNever
+		}
+	}
+
+	// Validate render hook configuration.
+	renderHookUseEmbeddedModes := []string{
+		gc.RenderHookUseEmbeddedAlways,
+		gc.RenderHookUseEmbeddedAuto,
+		gc.RenderHookUseEmbeddedFallback,
+		gc.RenderHookUseEmbeddedNever,
+	}
+	if !slices.Contains(renderHookUseEmbeddedModes, c.Markup.Goldmark.RenderHooks.Image.UseEmbedded) {
+		return fmt.Errorf("site config markup.goldmark.renderHooks.image must be one of %s", helpers.StringSliceToList(renderHookUseEmbeddedModes, "or"))
+	}
+	if !slices.Contains(renderHookUseEmbeddedModes, c.Markup.Goldmark.RenderHooks.Link.UseEmbedded) {
+		return fmt.Errorf("site config markup.goldmark.renderHooks.link must be one of %s", helpers.StringSliceToList(renderHookUseEmbeddedModes, "or"))
+	}
+
 	c.C = &ConfigCompiled{
 		Timeout:             timeout,
 		BaseURL:             baseURL,
@@ -1082,13 +1119,11 @@ func fromLoadConfigResult(fs afero.Fs, logger loggers.Logger, res config.LoadCon
 
 			// Adjust Goldmark config defaults for multilingual, single-host sites.
 			if len(languagesConfig) > 1 && !isMultihost && !clone.Markup.Goldmark.DuplicateResourceFiles {
-				if !clone.Markup.Goldmark.DuplicateResourceFiles {
-					if clone.Markup.Goldmark.RenderHooks.Link.EnableDefault == nil {
-						clone.Markup.Goldmark.RenderHooks.Link.EnableDefault = types.NewBool(true)
-					}
-					if clone.Markup.Goldmark.RenderHooks.Image.EnableDefault == nil {
-						clone.Markup.Goldmark.RenderHooks.Image.EnableDefault = types.NewBool(true)
-					}
+				if clone.Markup.Goldmark.RenderHooks.Image.UseEmbedded == gc.RenderHookUseEmbeddedAuto {
+					clone.Markup.Goldmark.RenderHooks.Image.UseEmbedded = gc.RenderHookUseEmbeddedFallback
+				}
+				if clone.Markup.Goldmark.RenderHooks.Link.UseEmbedded == gc.RenderHookUseEmbeddedAuto {
+					clone.Markup.Goldmark.RenderHooks.Link.UseEmbedded = gc.RenderHookUseEmbeddedFallback
 				}
 			}
 
diff --git a/go.mod b/go.mod
index 4cddbc06b..d03999dc1 100644
--- a/go.mod
+++ b/go.mod
@@ -2,7 +2,7 @@ module github.com/gohugoio/hugo
 
 require (
 	github.com/BurntSushi/locker v0.0.0-20171006230638-a6e239ea1c69
-	github.com/alecthomas/chroma/v2 v2.18.0
+	github.com/alecthomas/chroma/v2 v2.19.0
 	github.com/armon/go-radix v1.0.1-0.20221118154546-54df44f2176c
 	github.com/aws/aws-sdk-go-v2 v1.36.4
 	github.com/aws/aws-sdk-go-v2/service/cloudfront v1.44.10
diff --git a/go.sum b/go.sum
index 94272ef25..d285f4a97 100644
--- a/go.sum
+++ b/go.sum
@@ -89,8 +89,8 @@ github.com/GoogleCloudPlatform/opentelemetry-operations-go/internal/resourcemapp
 github.com/GoogleCloudPlatform/opentelemetry-operations-go/internal/resourcemapping v0.50.0/go.mod h1:otE2jQekW/PqXk1Awf5lmfokJx4uwuqcj1ab5SpGeW0=
 github.com/alecthomas/assert/v2 v2.11.0 h1:2Q9r3ki8+JYXvGsDyBXwH3LcJ+WK5D0gc5E8vS6K3D0=
 github.com/alecthomas/assert/v2 v2.11.0/go.mod h1:Bze95FyfUr7x34QZrjL+XP+0qgp/zg8yS+TtBj1WA3k=
-github.com/alecthomas/chroma/v2 v2.18.0 h1:6h53Q4hW83SuF+jcsp7CVhLsMozzvQvO8HBbKQW+gn4=
-github.com/alecthomas/chroma/v2 v2.18.0/go.mod h1:RVX6AvYm4VfYe/zsk7mjHueLDZor3aWCNE14TFlepBk=
+github.com/alecthomas/chroma/v2 v2.19.0 h1:Im+SLRgT8maArxv81mULDWN8oKxkzboH07CHesxElq4=
+github.com/alecthomas/chroma/v2 v2.19.0/go.mod h1:RVX6AvYm4VfYe/zsk7mjHueLDZor3aWCNE14TFlepBk=
 github.com/alecthomas/repr v0.4.0 h1:GhI2A8MACjfegCPVq9f1FLvIBS+DrQ2KQBFZP1iFzXc=
 github.com/alecthomas/repr v0.4.0/go.mod h1:Fr0507jx4eOXV7AlPV6AVZLYrLIuIeSOWtW57eE/O/4=
 github.com/armon/go-radix v1.0.1-0.20221118154546-54df44f2176c h1:651/eoCRnQ7YtSjAnSzRucrJz+3iGEFt+ysraELS81M=
diff --git a/helpers/general.go b/helpers/general.go
index 76275a6b9..5c3af9712 100644
--- a/helpers/general.go
+++ b/helpers/general.go
@@ -255,6 +255,27 @@ func SliceToLower(s []string) []string {
 	return l
 }
 
+// StringSliceToList formats a string slice into a human-readable list.
+// It joins the elements of the slice s with commas, using an Oxford comma,
+// and precedes the final element with the conjunction c.
+func StringSliceToList(s []string, c string) string {
+	const defaultConjunction = "and"
+
+	if c == "" {
+		c = defaultConjunction
+	}
+	if len(s) == 0 {
+		return ""
+	}
+	if len(s) == 1 {
+		return s[0]
+	}
+	if len(s) == 2 {
+		return fmt.Sprintf("%s %s %s", s[0], c, s[1])
+	}
+	return fmt.Sprintf("%s, %s %s", strings.Join(s[:len(s)-1], ", "), c, s[len(s)-1])
+}
+
 // IsWhitespace determines if the given rune is whitespace.
 func IsWhitespace(r rune) bool {
 	return r == ' ' || r == '\t' || r == '\n' || r == '\r'
diff --git a/hugolib/page__per_output.go b/hugolib/page__per_output.go
index 1f7f3411e..15e9a890c 100644
--- a/hugolib/page__per_output.go
+++ b/hugolib/page__per_output.go
@@ -29,6 +29,7 @@ import (
 	"github.com/spf13/cast"
 
 	"github.com/gohugoio/hugo/markup/converter/hooks"
+	gc "github.com/gohugoio/hugo/markup/goldmark/goldmark_config"
 	"github.com/gohugoio/hugo/markup/tableofcontents"
 
 	"github.com/gohugoio/hugo/markup/converter"
@@ -304,12 +305,17 @@ func (pco *pageContentOutput) initRenderHooks() error {
 			}
 
 			renderHookConfig := pco.po.p.s.conf.Markup.Goldmark.RenderHooks
-			var ignoreInternal bool
+			var ignoreEmbedded bool
+
+			// For multilingual single-host sites, "auto" becomes "fallback"
+			// earlier in the process.
 			switch layoutDescriptor.Variant1 {
 			case "link":
-				ignoreInternal = !renderHookConfig.Link.IsEnableDefault()
+				ignoreEmbedded = renderHookConfig.Link.UseEmbedded == gc.RenderHookUseEmbeddedNever ||
+					renderHookConfig.Link.UseEmbedded == gc.RenderHookUseEmbeddedAuto
 			case "image":
-				ignoreInternal = !renderHookConfig.Image.IsEnableDefault()
+				ignoreEmbedded = renderHookConfig.Image.UseEmbedded == gc.RenderHookUseEmbeddedNever ||
+					renderHookConfig.Image.UseEmbedded == gc.RenderHookUseEmbeddedAuto
 			}
 
 			candidates := pco.po.p.s.renderFormats
@@ -323,8 +329,8 @@ func (pco *pageContentOutput) initRenderHooks() error {
 					return false
 				}
 
-				if ignoreInternal && candidate.SubCategory() == tplimpl.SubCategoryEmbedded {
-					// Don't consider the internal hook templates.
+				if ignoreEmbedded && candidate.SubCategory() == tplimpl.SubCategoryEmbedded {
+					// Don't consider the embedded hook templates.
 					return false
 				}
 
diff --git a/hugolib/site.go b/hugolib/site.go
index acd3b5410..e37dbd5ef 100644
--- a/hugolib/site.go
+++ b/hugolib/site.go
@@ -406,6 +406,7 @@ func newHugoSites(cfg deps.DepsCfg, d *deps.Deps, pageTrees *pageTrees, sites []
 					MediaTypes:             s.conf.MediaTypes.Config,
 					DefaultOutputFormat:    s.conf.DefaultOutputFormat,
 					TaxonomySingularPlural: s.conf.Taxonomies,
+					RenderHooks:            s.conf.Markup.Goldmark.RenderHooks,
 				}, tplimpl.SiteOptions{
 					Site:          s,
 					TemplateFuncs: tplimplinit.CreateFuncMap(s.Deps),
diff --git a/markup/goldmark/goldmark_config/config.go b/markup/goldmark/goldmark_config/config.go
index 04eb371d9..168a3b8fa 100644
--- a/markup/goldmark/goldmark_config/config.go
+++ b/markup/goldmark/goldmark_config/config.go
@@ -15,9 +15,13 @@
 package goldmark_config
 
 const (
-	AutoIDTypeGitHub      = "github"
-	AutoIDTypeGitHubAscii = "github-ascii"
-	AutoIDTypeBlackfriday = "blackfriday"
+	AutoIDTypeBlackfriday         = "blackfriday"
+	AutoIDTypeGitHub              = "github"
+	AutoIDTypeGitHubAscii         = "github-ascii"
+	RenderHookUseEmbeddedAlways   = "always"
+	RenderHookUseEmbeddedAuto     = "auto"
+	RenderHookUseEmbeddedFallback = "fallback"
+	RenderHookUseEmbeddedNever    = "never"
 )
 
 // Default holds the default Goldmark configuration.
@@ -87,6 +91,14 @@ var Default = Config{
 			Block: false,
 		},
 	},
+	RenderHooks: RenderHooks{
+		Image: ImageRenderHook{
+			UseEmbedded: RenderHookUseEmbeddedAuto,
+		},
+		Link: LinkRenderHook{
+			UseEmbedded: RenderHookUseEmbeddedAuto,
+		},
+	},
 }
 
 // Config configures Goldmark.
@@ -118,22 +130,24 @@ type RenderHooks struct {
 type ImageRenderHook struct {
 	// Enable the default image render hook.
 	// We need to know if it is set or not, hence the pointer.
+	// Deprecated: Use UseEmbedded instead.
 	EnableDefault *bool
-}
 
-func (h ImageRenderHook) IsEnableDefault() bool {
-	return h.EnableDefault != nil && *h.EnableDefault
+	// When to use the embedded image render hook.
+	// One of auto, never, always, or fallback. Default is auto.
+	UseEmbedded string
 }
 
 // LinkRenderHook contains configuration for the link render hook.
 type LinkRenderHook struct {
 	// Disable the default image render hook.
 	// We need to know if it is set or not, hence the pointer.
+	// Deprecated: Use UseEmbedded instead.
 	EnableDefault *bool
-}
 
-func (h LinkRenderHook) IsEnableDefault() bool {
-	return h.EnableDefault != nil && *h.EnableDefault
+	// When to use the embedded link render hook.
+	// One of auto, never, always, or fallback. Default is auto.
+	UseEmbedded string
 }
 
 type Extensions struct {
diff --git a/resources/page/page_paths.go b/resources/page/page_paths.go
index 6b2c8e8b1..354292e1a 100644
--- a/resources/page/page_paths.go
+++ b/resources/page/page_paths.go
@@ -140,11 +140,17 @@ func CreateTargetPaths(d TargetPathDescriptor) (tp TargetPaths) {
 
 	pb.isUgly = (d.UglyURLs || d.Type.Ugly) && !d.Type.NoUgly
 	pb.baseNameSameAsType = !d.Path.IsBundle() && d.BaseName != "" && d.BaseName == d.Type.BaseName
+	indexIsUglyKind := d.Kind == kinds.KindHome || d.Kind == kinds.KindSection || d.Kind == kinds.KindTaxonomy
+	indexIsUglyKind = indexIsUglyKind && pb.isUgly
 
 	if d.ExpandedPermalink == "" && pb.baseNameSameAsType {
 		pb.isUgly = true
 	}
 
+	if d.Type.Path != "" {
+		pb.Add(d.Type.Path)
+	}
+
 	if d.Type == output.HTTPStatus404HTMLFormat || d.Type == output.SitemapFormat || d.Type == output.RobotsTxtFormat {
 		pb.noSubResources = true
 	} else if d.Kind != kinds.KindPage && d.URL == "" && d.Section.Base() != "/" {
@@ -156,10 +162,6 @@ func CreateTargetPaths(d TargetPathDescriptor) (tp TargetPaths) {
 		needsBase = false
 	}
 
-	if d.Type.Path != "" {
-		pb.Add(d.Type.Path)
-	}
-
 	if d.Kind != kinds.KindHome && d.URL != "" {
 		pb.Add(paths.FieldsSlash(d.URL)...)
 
@@ -233,13 +235,13 @@ func CreateTargetPaths(d TargetPathDescriptor) (tp TargetPaths) {
 
 		needsBase = needsBase && d.Addends == ""
 
-		if needsBase || !pb.isUgly {
+		if needsBase || (!pb.isUgly || indexIsUglyKind) {
 			pb.Add(d.Type.BaseName + pb.fullSuffix)
 		} else {
 			pb.ConcatLast(pb.fullSuffix)
 		}
 
-		if pb.IsHtmlIndex() {
+		if !indexIsUglyKind && pb.IsHtmlIndex() {
 			pb.linkUpperOffset = 1
 		}
 
@@ -261,6 +263,7 @@ func CreateTargetPaths(d TargetPathDescriptor) (tp TargetPaths) {
 	}
 
 	link := pb.Link()
+
 	pagePath := pb.PathFile()
 
 	tp.TargetFilename = filepath.FromSlash(pagePath)
diff --git a/resources/page/pagemeta/page_frontmatter.go b/resources/page/pagemeta/page_frontmatter.go
index fd4f7759b..9018acb71 100644
--- a/resources/page/pagemeta/page_frontmatter.go
+++ b/resources/page/pagemeta/page_frontmatter.go
@@ -457,26 +457,43 @@ func (f FrontMatterHandler) IsDateKey(key string) bool {
 	return f.allDateKeys[key]
 }
 
-// A Zero date is a signal that the name can not be parsed.
-// This follows the format as outlined in Jekyll, https://jekyllrb.com/docs/posts/:
-// "Where YEAR is a four-digit number, MONTH and DAY are both two-digit numbers"
-func dateAndSlugFromBaseFilename(location *time.Location, name string) (time.Time, string) {
-	withoutExt, _ := paths.FileAndExt(name)
-
-	if len(withoutExt) < 10 {
-		// This can not be a date.
+// dateAndSlugFromBaseFilename returns a time.Time value (resolved to the
+// default system location) and a slug, extracted by parsing the provided path.
+// Parsing supports YYYY-MM-DD-HH-MM-SS and YYYY-MM-DD date/time formats.
+// Within the YYYY-MM-DD-HH-MM-SS format, the date and time values may be
+// separated by any character including a space (e.g., YYYY-MM-DD HH-MM-SS).
+func dateAndSlugFromBaseFilename(location *time.Location, path string) (time.Time, string) {
+	base, _ := paths.FileAndExt(path)
+
+	if len(base) < 10 {
+		// Not long enough to start with a YYYY-MM-DD date.
 		return time.Time{}, ""
 	}
 
-	d, err := htime.ToTimeInDefaultLocationE(withoutExt[:10], location)
-	if err != nil {
-		return time.Time{}, ""
+	// Delimiters allowed between the date and the slug.
+	delimiters := " -_"
+
+	if len(base) >= 19 {
+		// Attempt to parse a YYYY-MM-DD-HH-MM-SS date-time prefix.
+		ds := base[:10]
+		ts := strings.ReplaceAll(base[11:19], "-", ":")
+
+		d, err := htime.ToTimeInDefaultLocationE(ds+"T"+ts, location)
+		if err == nil {
+			return d, strings.Trim(base[19:], delimiters)
+		}
 	}
 
-	// Be a little lenient with the format here.
-	slug := strings.Trim(withoutExt[10:], " -_")
+	// Attempt to parse a YYYY-MM-DD date prefix.
+	ds := base[:10]
+
+	d, err := htime.ToTimeInDefaultLocationE(ds, location)
+	if err == nil {
+		return d, strings.Trim(base[10:], delimiters)
+	}
 
-	return d, slug
+	// If no date is defined, return the zero time instant.
+	return time.Time{}, ""
 }
 
 type frontMatterFieldHandler func(d *FrontMatterDescriptor) (bool, error)


Test patch:
diff --git a/config/allconfig/allconfig_integration_test.go b/config/allconfig/allconfig_integration_test.go
index 8f6cacf84..79d2299de 100644
--- a/config/allconfig/allconfig_integration_test.go
+++ b/config/allconfig/allconfig_integration_test.go
@@ -2,12 +2,14 @@ package allconfig_test
 
 import (
 	"path/filepath"
+	"strings"
 	"testing"
 
 	qt "github.com/frankban/quicktest"
 	"github.com/gohugoio/hugo/common/hugo"
 	"github.com/gohugoio/hugo/config/allconfig"
 	"github.com/gohugoio/hugo/hugolib"
+	gc "github.com/gohugoio/hugo/markup/goldmark/goldmark_config"
 	"github.com/gohugoio/hugo/media"
 )
 
@@ -379,3 +381,28 @@ weight = 3
 
 	b.Assert(len(b.H.Sites), qt.Equals, 1)
 }
+
+// Issue 13535
+// We changed enablement of the embedded link and image render hooks from
+// booleans to enums in v0.148.0.
+func TestLegacyEmbeddedRenderHookEnablement(t *testing.T) {
+	files := `
+-- hugo.toml --
+[markup.goldmark.renderHooks.image]
+#KEY_VALUE
+
+[markup.goldmark.renderHooks.link]
+#KEY_VALUE
+`
+	f := strings.ReplaceAll(files, "#KEY_VALUE", "enableDefault = false")
+	b := hugolib.Test(t, f)
+	c := b.H.Configs.Base.Markup.Goldmark.RenderHooks
+	b.Assert(c.Link.UseEmbedded, qt.Equals, gc.RenderHookUseEmbeddedNever)
+	b.Assert(c.Image.UseEmbedded, qt.Equals, gc.RenderHookUseEmbeddedNever)
+
+	f = strings.ReplaceAll(files, "#KEY_VALUE", "enableDefault = true")
+	b = hugolib.Test(t, f)
+	c = b.H.Configs.Base.Markup.Goldmark.RenderHooks
+	b.Assert(c.Link.UseEmbedded, qt.Equals, gc.RenderHookUseEmbeddedFallback)
+	b.Assert(c.Image.UseEmbedded, qt.Equals, gc.RenderHookUseEmbeddedFallback)
+}
diff --git a/helpers/general_test.go b/helpers/general_test.go
index 686e95ded..6d2a78e02 100644
--- a/helpers/general_test.go
+++ b/helpers/general_test.go
@@ -18,9 +18,8 @@ import (
 	"strings"
 	"testing"
 
-	"github.com/gohugoio/hugo/helpers"
-
 	qt "github.com/frankban/quicktest"
+	"github.com/gohugoio/hugo/helpers"
 )
 
 func TestResolveMarkup(t *testing.T) {
@@ -304,3 +303,26 @@ func BenchmarkUniqueStrings(b *testing.B) {
 		}
 	})
 }
+
+func TestStringSliceToList(t *testing.T) {
+	for _, tt := range []struct {
+		slice       []string
+		conjunction string
+		want        string
+	}{
+		{[]string{}, "", ""},
+		{[]string{"foo"}, "", "foo"},
+		{[]string{"foo"}, "and", "foo"},
+		{[]string{"foo", "bar"}, "", "foo and bar"},
+		{[]string{"foo", "bar"}, "and", "foo and bar"},
+		{[]string{"foo", "bar"}, "or", "foo or bar"},
+		{[]string{"foo", "bar", "baz"}, "", "foo, bar, and baz"},
+		{[]string{"foo", "bar", "baz"}, "and", "foo, bar, and baz"},
+		{[]string{"foo", "bar", "baz"}, "or", "foo, bar, or baz"},
+	} {
+		got := helpers.StringSliceToList(tt.slice, tt.conjunction)
+		if got != tt.want {
+			t.Errorf("StringSliceToList() got: %q, want: %q", got, tt.want)
+		}
+	}
+}
diff --git a/hugolib/site_test.go b/hugolib/site_test.go
index 199c878cd..7e3452b1c 100644
--- a/hugolib/site_test.go
+++ b/hugolib/site_test.go
@@ -511,12 +511,13 @@ func TestSectionNaming(t *testing.T) {
 func doTestSectionNaming(t *testing.T, canonify, uglify, pluralize bool) {
 	c := qt.New(t)
 
-	var expectedPathSuffix string
-
-	if uglify {
-		expectedPathSuffix = ".html"
-	} else {
-		expectedPathSuffix = "/index.html"
+	expectedPathSuffix := func(kind string) string {
+		isUgly := uglify && (kind == kinds.KindPage || kind == kinds.KindTerm)
+		if isUgly {
+			return ".html"
+		} else {
+			return "/index.html"
+		}
 	}
 
 	sources := [][2]string{
@@ -554,12 +555,12 @@ func doTestSectionNaming(t *testing.T, canonify, uglify, pluralize bool) {
 		pluralAware bool
 		expected    string
 	}{
-		{filepath.FromSlash(fmt.Sprintf("sect/doc1%s", expectedPathSuffix)), false, "doc1"},
-		{filepath.FromSlash(fmt.Sprintf("sect%s", expectedPathSuffix)), true, "Sect"},
-		{filepath.FromSlash(fmt.Sprintf("fish-and-chips/doc2%s", expectedPathSuffix)), false, "doc2"},
-		{filepath.FromSlash(fmt.Sprintf("fish-and-chips%s", expectedPathSuffix)), true, "Fish and Chips"},
-		{filepath.FromSlash(fmt.Sprintf("ラーメン/doc3%s", expectedPathSuffix)), false, "doc3"},
-		{filepath.FromSlash(fmt.Sprintf("ラーメン%s", expectedPathSuffix)), true, "ラーメン"},
+		{filepath.FromSlash(fmt.Sprintf("sect/doc1%s", expectedPathSuffix(kinds.KindPage))), false, "doc1"},
+		{filepath.FromSlash(fmt.Sprintf("sect%s", expectedPathSuffix(kinds.KindSection))), true, "Sect"},
+		{filepath.FromSlash(fmt.Sprintf("fish-and-chips/doc2%s", expectedPathSuffix(kinds.KindPage))), false, "doc2"},
+		{filepath.FromSlash(fmt.Sprintf("fish-and-chips%s", expectedPathSuffix(kinds.KindSection))), true, "Fish and Chips"},
+		{filepath.FromSlash(fmt.Sprintf("ラーメン/doc3%s", expectedPathSuffix(kinds.KindPage))), false, "doc3"},
+		{filepath.FromSlash(fmt.Sprintf("ラーメン%s", expectedPathSuffix(kinds.KindSection))), true, "ラーメン"},
 	}
 
 	for _, test := range tests {
diff --git a/hugolib/taxonomy_test.go b/hugolib/taxonomy_test.go
index 7aeaa780c..272735367 100644
--- a/hugolib/taxonomy_test.go
+++ b/hugolib/taxonomy_test.go
@@ -65,151 +65,6 @@ YAML frontmatter with tags and categories taxonomy.`
 	}
 }
 
-func TestTaxonomiesWithAndWithoutContentFile(t *testing.T) {
-	for _, uglyURLs := range []bool{false, true} {
-		uglyURLs := uglyURLs
-		t.Run(fmt.Sprintf("uglyURLs=%t", uglyURLs), func(t *testing.T) {
-			t.Parallel()
-			doTestTaxonomiesWithAndWithoutContentFile(t, uglyURLs)
-		})
-	}
-}
-
-func doTestTaxonomiesWithAndWithoutContentFile(t *testing.T, uglyURLs bool) {
-	t.Helper()
-
-	siteConfig := `
-baseURL = "http://example.com/blog"
-titleCaseStyle = "firstupper"
-uglyURLs = %t
-defaultContentLanguage = "en"
-[pagination]
-pagerSize = 1
-[Taxonomies]
-tag = "tags"
-category = "categories"
-other = "others"
-empty = "empties"
-permalinked = "permalinkeds"
-[permalinks]
-permalinkeds = "/perma/:slug/"
-`
-
-	pageTemplate := `---
-title: "%s"
-tags:
-%s
-categories:
-%s
-others:
-%s
-permalinkeds:
-%s
----
-# Doc
-`
-
-	siteConfig = fmt.Sprintf(siteConfig, uglyURLs)
-
-	b := newTestSitesBuilder(t).WithConfigFile("toml", siteConfig)
-
-	b.WithContent(
-		"p1.md", fmt.Sprintf(pageTemplate, "t1/c1", "- Tag1", "- cAt1", "- o1", "- Pl1"),
-		"p2.md", fmt.Sprintf(pageTemplate, "t2/c1", "- tag2", "- cAt1", "- o1", "- Pl1"),
-		"p3.md", fmt.Sprintf(pageTemplate, "t2/c12", "- tag2", "- cat2", "- o1", "- Pl1"),
-		"p4.md", fmt.Sprintf(pageTemplate, "Hello World", "", "", "- \"Hello Hugo world\"", "- Pl1"),
-		"categories/_index.md", newTestPage("Category Terms", "2017-01-01", 10),
-		"tags/Tag1/_index.md", newTestPage("Tag1 List", "2017-01-01", 10),
-		// https://github.com/gohugoio/hugo/issues/5847
-		"/tags/not-used/_index.md", newTestPage("Unused Tag List", "2018-01-01", 10),
-	)
-
-	b.Build(BuildCfg{})
-
-	// So what we have now is:
-	// 1. categories with terms content page, but no content page for the only c1 category
-	// 2. tags with no terms content page, but content page for one of 2 tags (tag1)
-	// 3. the "others" taxonomy with no content pages.
-	// 4. the "permalinkeds" taxonomy with permalinks configuration.
-
-	pathFunc := func(s string) string {
-		if uglyURLs {
-			return strings.Replace(s, "/index.html", ".html", 1)
-		}
-		return s
-	}
-
-	// 1.
-	b.AssertFileContent(pathFunc("public/categories/cat1/index.html"), "List", "CAt1")
-	b.AssertFileContent(pathFunc("public/categories/index.html"), "Taxonomy Term Page", "Category Terms")
-
-	// 2.
-	b.AssertFileContent(pathFunc("public/tags/tag2/index.html"), "List", "tag2")
-	b.AssertFileContent(pathFunc("public/tags/tag1/index.html"), "List", "Tag1")
-	b.AssertFileContent(pathFunc("public/tags/index.html"), "Taxonomy Term Page", "Tags")
-
-	// 3.
-	b.AssertFileContent(pathFunc("public/others/o1/index.html"), "List", "o1")
-	b.AssertFileContent(pathFunc("public/others/index.html"), "Taxonomy Term Page", "Others")
-
-	// 4.
-	b.AssertFileContent(pathFunc("public/perma/pl1/index.html"), "List", "Pl1")
-
-	// This looks kind of funky, but the taxonomy terms do not have a permalinks definition,
-	// for good reasons.
-	b.AssertFileContent(pathFunc("public/permalinkeds/index.html"), "Taxonomy Term Page", "Permalinkeds")
-
-	s := b.H.Sites[0]
-
-	// Make sure that each kinds.KindTaxonomyTerm page has an appropriate number
-	// of kinds.KindTaxonomy pages in its Pages slice.
-	taxonomyTermPageCounts := map[string]int{
-		"tags":         3,
-		"categories":   2,
-		"others":       2,
-		"empties":      0,
-		"permalinkeds": 1,
-	}
-
-	for taxonomy, count := range taxonomyTermPageCounts {
-		msg := qt.Commentf(taxonomy)
-		term := s.getPageOldVersion(kinds.KindTaxonomy, taxonomy)
-		b.Assert(term, qt.Not(qt.IsNil), msg)
-		b.Assert(len(term.Pages()), qt.Equals, count, msg)
-
-		for _, p := range term.Pages() {
-			b.Assert(p.Kind(), qt.Equals, kinds.KindTerm)
-		}
-	}
-
-	cat1 := s.getPageOldVersion(kinds.KindTerm, "categories", "cat1")
-	b.Assert(cat1, qt.Not(qt.IsNil))
-	if uglyURLs {
-		b.Assert(cat1.RelPermalink(), qt.Equals, "/blog/categories/cat1.html")
-	} else {
-		b.Assert(cat1.RelPermalink(), qt.Equals, "/blog/categories/cat1/")
-	}
-
-	pl1 := s.getPageOldVersion(kinds.KindTerm, "permalinkeds", "pl1")
-	permalinkeds := s.getPageOldVersion(kinds.KindTaxonomy, "permalinkeds")
-	b.Assert(pl1, qt.Not(qt.IsNil))
-	b.Assert(permalinkeds, qt.Not(qt.IsNil))
-	if uglyURLs {
-		b.Assert(pl1.RelPermalink(), qt.Equals, "/blog/perma/pl1.html")
-		b.Assert(permalinkeds.RelPermalink(), qt.Equals, "/blog/permalinkeds.html")
-	} else {
-		b.Assert(pl1.RelPermalink(), qt.Equals, "/blog/perma/pl1/")
-		b.Assert(permalinkeds.RelPermalink(), qt.Equals, "/blog/permalinkeds/")
-	}
-
-	helloWorld := s.getPageOldVersion(kinds.KindTerm, "others", "hello-hugo-world")
-	b.Assert(helloWorld, qt.Not(qt.IsNil))
-	b.Assert(helloWorld.Title(), qt.Equals, "Hello Hugo world")
-
-	// Issue #2977
-	b.AssertFileContent(pathFunc("public/empties/index.html"), "Taxonomy Term Page", "Empties")
-}
-
 // https://github.com/gohugoio/hugo/issues/5513
 // https://github.com/gohugoio/hugo/issues/5571
 func TestTaxonomiesPathSeparation(t *testing.T) {
diff --git a/resources/page/pagemeta/pagemeta_test.go b/resources/page/pagemeta/pagemeta_test.go
index f205c74f8..80c19d07f 100644
--- a/resources/page/pagemeta/pagemeta_test.go
+++ b/resources/page/pagemeta/pagemeta_test.go
@@ -102,27 +102,46 @@ func TestDateAndSlugFromBaseFilename(t *testing.T) {
 		date string
 		slug string
 	}{
-		{"page.md", "0001-01-01", ""},
-		{"2012-09-12-page.md", "2012-09-12", "page"},
-		{"2018-02-28-page.md", "2018-02-28", "page"},
-		{"2018-02-28_page.md", "2018-02-28", "page"},
-		{"2018-02-28 page.md", "2018-02-28", "page"},
-		{"2018-02-28page.md", "2018-02-28", "page"},
-		{"2018-02-28-.md", "2018-02-28", ""},
-		{"2018-02-28-.md", "2018-02-28", ""},
-		{"2018-02-28.md", "2018-02-28", ""},
-		{"2018-02-28-page", "2018-02-28", "page"},
-		{"2012-9-12-page.md", "0001-01-01", ""},
-		{"asdfasdf.md", "0001-01-01", ""},
+		// date
+		{"2025-07-04 page.md", "2025-07-04T00:00:00+02:00", "page"},
+		{"2025-07-04-page.md", "2025-07-04T00:00:00+02:00", "page"},
+		{"2025-07-04_page.md", "2025-07-04T00:00:00+02:00", "page"},
+		{"2025-07-04page.md", "2025-07-04T00:00:00+02:00", "page"},
+		{"2025-07-04", "2025-07-04T00:00:00+02:00", ""},
+		{"2025-07-04-.md", "2025-07-04T00:00:00+02:00", ""},
+		{"2025-07-04.md", "2025-07-04T00:00:00+02:00", ""},
+		// date and time
+		{"2025-07-04-22-17-13 page.md", "2025-07-04T22:17:13+02:00", "page"},
+		{"2025-07-04-22-17-13-page.md", "2025-07-04T22:17:13+02:00", "page"},
+		{"2025-07-04-22-17-13_page.md", "2025-07-04T22:17:13+02:00", "page"},
+		{"2025-07-04-22-17-13page.md", "2025-07-04T22:17:13+02:00", "page"},
+		{"2025-07-04-22-17-13", "2025-07-04T22:17:13+02:00", ""},
+		{"2025-07-04-22-17-13-.md", "2025-07-04T22:17:13+02:00", ""},
+		{"2025-07-04-22-17-13.md", "2025-07-04T22:17:13+02:00", ""},
+		// date and time with other separators between the two
+		{"2025-07-04T22-17-13.md", "2025-07-04T22:17:13+02:00", ""},
+		{"2025-07-04 22-17-13.md", "2025-07-04T22:17:13+02:00", ""},
+		// no date or time
+		{"something.md", "0001-01-01T00:00:00+00:00", ""},                // 9 chars
+		{"some-thing-.md", "0001-01-01T00:00:00+00:00", ""},              // 10 chars
+		{"somethingsomething.md", "0001-01-01T00:00:00+00:00", ""},       // 18 chars
+		{"something-something.md", "0001-01-01T00:00:00+00:00", ""},      // 19 chars
+		{"something-something-else.md", "0001-01-01T00:00:00+00:00", ""}, // 27 chars
+		// invalid
+		{"2025-07-4-page.md", "0001-01-01T00:00:00+00:00", ""},
+		{"2025-07-4-22-17-13-page.md", "0001-01-01T00:00:00+00:00", ""},
+		{"asdfasdf.md", "0001-01-01T00:00:00+00:00", ""},
 	}
 
+	location, err := time.LoadLocation("Europe/Oslo")
+	if err != nil {
+		t.Error("Unable to determine location from given time zone")
+	}
 	for _, test := range tests {
-		expecteFDate, err := time.Parse("2006-01-02", test.date)
-		c.Assert(err, qt.IsNil)
 
-		gotDate, gotSlug := dateAndSlugFromBaseFilename(time.UTC, test.name)
+		gotDate, gotSlug := dateAndSlugFromBaseFilename(location, test.name)
 
-		c.Assert(gotDate, qt.Equals, expecteFDate)
+		c.Assert(gotDate.Format("2006-01-02T15:04:05-07:00"), qt.Equals, test.date)
 		c.Assert(gotSlug, qt.Equals, test.slug)
 
 	}
diff --git a/resources/page/path_integration_test.go b/resources/page/path_integration_test.go
index a1aa1d406..3bd8ccf1f 100644
--- a/resources/page/path_integration_test.go
+++ b/resources/page/path_integration_test.go
@@ -14,6 +14,7 @@
 package page_test
 
 import (
+	"strings"
 	"testing"
 
 	"github.com/gohugoio/hugo/hugolib"
@@ -53,3 +54,103 @@ title: p#2
 
 	b.AssertFileContentExact("public/index.html", "/|/s1/p%231/|/s2/p%232/|/tags/test%23tag%23/|")
 }
+
+// Issues: 13829, 4428, 7497.
+func TestMiscPathIssues(t *testing.T) {
+	t.Parallel()
+
+	filesTemplate := `
+-- hugo.toml --
+uglyURLs = false
+
+[outputFormats.print]
+isPlainText = true
+mediaType = 'text/plain'
+path = 'print'
+
+[outputs]
+home = ['html','print']
+page = ['html','print']
+section = ['html','print']
+taxonomy = ['html','print']
+term = ['html','print']
+
+[taxonomies]
+tag = 'tags'
+-- content/_index.md --
+---
+title: home
+---
+-- content/s1/_index.md --
+---
+title: s1
+---
+-- content/s1/p1.md --
+---
+title: p1
+tags: ['red']
+---
+-- content/tags/_index.md --
+---
+title: tags
+---
+-- content/tags/red/_index.md --
+---
+title: red
+---
+`
+
+	templates := []string{
+		"layouts/home.html",
+		"layouts/home.print.txt",
+		"layouts/page.html",
+		"layouts/page.print.txt",
+		"layouts/section.html",
+		"layouts/section.print.txt",
+		"layouts/taxonomy.html",
+		"layouts/taxonomy.print.txt",
+		"layouts/term.html",
+		"layouts/term.print.txt",
+	}
+
+	const code string = "TITLE: {{ .Title }} | AOFRP: {{ range .AlternativeOutputFormats }}{{ .RelPermalink }}{{ end }} | TEMPLATE: {{ templates.Current.Name }}"
+
+	for _, template := range templates {
+		filesTemplate += "-- " + template + " --\n" + code + "\n"
+	}
+
+	files := filesTemplate
+
+	b := hugolib.Test(t, files)
+
+	// uglyURLs: false, outputFormat: html
+	b.AssertFileContent("public/index.html", "TITLE: home | AOFRP: /print/index.txt | TEMPLATE: home.html")
+	b.AssertFileContent("public/s1/index.html", "TITLE: s1 | AOFRP: /print/s1/index.txt | TEMPLATE: section.html")
+	b.AssertFileContent("public/s1/p1/index.html", "TITLE: p1 | AOFRP: /print/s1/p1/index.txt | TEMPLATE: page.html")
+	b.AssertFileContent("public/tags/index.html", "TITLE: tags | AOFRP: /print/tags/index.txt | TEMPLATE: taxonomy.html")
+	b.AssertFileContent("public/tags/red/index.html", "TITLE: red | AOFRP: /print/tags/red/index.txt | TEMPLATE: term.html")
+
+	// uglyURLs: false, outputFormat: print
+	b.AssertFileContent("public/print/index.txt", "TITLE: home | AOFRP: / | TEMPLATE: home.print.txt")
+	b.AssertFileContent("public/print/s1/index.txt", "TITLE: s1 | AOFRP: /s1/ | TEMPLATE: section.print.txt")
+	b.AssertFileContent("public/print/s1/p1/index.txt", "TITLE: p1 | AOFRP: /s1/p1/ | TEMPLATE: page.print.txt")
+	b.AssertFileContent("public/print/tags/index.txt", "TITLE: tags | AOFRP: /tags/ | TEMPLATE: taxonomy.print.txt")
+	b.AssertFileContent("public/print/tags/red/index.txt", "TITLE: red | AOFRP: /tags/red/ | TEMPLATE: term.print.txt")
+
+	files = strings.ReplaceAll(filesTemplate, "uglyURLs = false", "uglyURLs = true")
+	b = hugolib.Test(t, files)
+
+	// uglyURLs: true, outputFormat: html
+	b.AssertFileContent("public/index.html", "TITLE: home | AOFRP: /print/index.txt | TEMPLATE: home.html")
+	b.AssertFileContent("public/s1/index.html", "TITLE: s1 | AOFRP: /print/s1/index.txt | TEMPLATE: section.html")
+	b.AssertFileContent("public/s1/p1.html", "TITLE: p1 | AOFRP: /print/s1/p1.txt | TEMPLATE: page.html")
+	b.AssertFileContent("public/tags/index.html", "TITLE: tags | AOFRP: /print/tags/index.txt | TEMPLATE: taxonomy.html")
+	b.AssertFileContent("public/tags/red.html", "TITLE: red | AOFRP: /print/tags/red.txt | TEMPLATE: term.html")
+
+	// uglyURLs: true, outputFormat: print
+	b.AssertFileContent("public/print/index.txt", "TITLE: home | AOFRP: /index.html | TEMPLATE: home.print.txt")
+	b.AssertFileContent("public/print/s1/index.txt", "TITLE: s1 | AOFRP: /s1/index.html | TEMPLATE: section.print.txt")
+	b.AssertFileContent("public/print/s1/p1.txt", "TITLE: p1 | AOFRP: /s1/p1.html | TEMPLATE: page.print.txt")
+	b.AssertFileContent("public/print/tags/index.txt", "TITLE: tags | AOFRP: /tags/index.html | TEMPLATE: taxonomy.print.txt")
+	b.AssertFileContent("public/print/tags/red.txt", "TITLE: red | AOFRP: /tags/red.html | TEMPLATE: term.print.txt")
+}
diff --git a/tpl/tplimpl/render_hook_integration_test.go b/tpl/tplimpl/render_hook_integration_test.go
index 45c6cced1..e67701594 100644
--- a/tpl/tplimpl/render_hook_integration_test.go
+++ b/tpl/tplimpl/render_hook_integration_test.go
@@ -192,3 +192,115 @@ iVBORw0KGgoAAAANSUhEUgAAAAEAAAABCAYAAAAfFcSJAAAADUlEQVR42mNkYPhfDwAChwGA60e6kgAA
 		`<img src="/dir/p1/pixel.png" alt="alt4" id="&#34;&gt;&lt;script&gt;alert()&lt;/script&gt;">`,
 	)
 }
+
+// Issue 13535
+func TestEmbeddedLinkAndImageRenderHookConfig(t *testing.T) {
+	t.Parallel()
+
+	files := `
+-- hugo.toml --
+disableKinds = ['home','rss','section','sitemap','taxonomy','term']
+
+[markup.goldmark]
+duplicateResourceFiles = false
+
+[markup.goldmark.renderHooks.image]
+#KEY_VALUE
+
+[markup.goldmark.renderHooks.link]
+#KEY_VALUE
+
+#LANGUAGES
+-- content/s1/p1/index.md --
+---
+title: p1
+---
+[p2](p2)
+
+[a](a.txt)
+
+![b](b.jpg)
+-- content/s1/p1/a.txt --
+-- content/s1/p1/b.jpg --
+-- content/s1/p2.md --
+---
+title: p2
+---
+-- layouts/all.html --
+{{ .Content }}
+`
+
+	const customHooks string = `
+-- layouts/s1/_markup/render-link.html --
+custom link render hook: {{ .Text }}|{{ .Destination }}
+-- layouts/s1/_markup/render-image.html --
+custom image render hook: {{ .Text }}|{{ .Destination }}
+`
+
+	const languages string = `
+[languages.en]
+[languages.fr]
+`
+
+	const (
+		fileToCheck         = "public/s1/p1/index.html"
+		wantCustom   string = "<p>custom link render hook: p2|p2</p>\n<p>custom link render hook: a|a.txt</p>\n<p>custom image render hook: b|b.jpg</p>"
+		wantEmbedded string = "<p><a href=\"/s1/p2/\">p2</a></p>\n<p><a href=\"/s1/p1/a.txt\">a</a></p>\n<p><img src=\"/s1/p1/b.jpg\" alt=\"b\"></p>"
+		wantGoldmark string = "<p><a href=\"p2\">p2</a></p>\n<p><a href=\"a.txt\">a</a></p>\n<p><img src=\"b.jpg\" alt=\"b\"></p>"
+	)
+
+	tests := []struct {
+		id             string // the test id
+		isMultilingual bool   // whether the site is multilingual single-host
+		hasCustomHooks bool   // whether the site has custom link and image render hooks
+		keyValuePair   string // the enableDefault (deprecated in v0.148.0) or useEmbedded key-value pair
+		want           string // the expected content of public/s1/p1/index.html
+	}{
+		{"01", false, false, "", wantGoldmark},                         // monolingual
+		{"02", false, false, "enableDefault = false", wantGoldmark},    // monolingual, enableDefault = false
+		{"03", false, false, "enableDefault = true", wantEmbedded},     // monolingual, enableDefault = true
+		{"04", false, false, "useEmbedded = 'always'", wantEmbedded},   // monolingual, useEmbedded = 'always'
+		{"05", false, false, "useEmbedded = 'auto'", wantGoldmark},     // monolingual, useEmbedded = 'auto'
+		{"06", false, false, "useEmbedded = 'fallback'", wantEmbedded}, // monolingual, useEmbedded = 'fallback'
+		{"07", false, false, "useEmbedded = 'never'", wantGoldmark},    // monolingual, useEmbedded = 'never'
+		{"08", false, true, "", wantCustom},                            // monolingual, with custom hooks
+		{"09", false, true, "enableDefault = false", wantCustom},       // monolingual, with custom hooks, enableDefault = false
+		{"10", false, true, "enableDefault = true", wantCustom},        // monolingual, with custom hooks, enableDefault = true
+		{"11", false, true, "useEmbedded = 'always'", wantEmbedded},    // monolingual, with custom hooks, useEmbedded = 'always'
+		{"12", false, true, "useEmbedded = 'auto'", wantCustom},        // monolingual, with custom hooks, useEmbedded = 'auto'
+		{"13", false, true, "useEmbedded = 'fallback'", wantCustom},    // monolingual, with custom hooks, useEmbedded = 'fallback'
+		{"14", false, true, "useEmbedded = 'never'", wantCustom},       // monolingual, with custom hooks, useEmbedded = 'never'
+		{"15", true, false, "", wantEmbedded},                          // multilingual
+		{"16", true, false, "enableDefault = false", wantGoldmark},     // multilingual, enableDefault = false
+		{"17", true, false, "enableDefault = true", wantEmbedded},      // multilingual, enableDefault = true
+		{"18", true, false, "useEmbedded = 'always'", wantEmbedded},    // multilingual, useEmbedded = 'always'
+		{"19", true, false, "useEmbedded = 'auto'", wantEmbedded},      // multilingual, useEmbedded = 'auto'
+		{"20", true, false, "useEmbedded = 'fallback'", wantEmbedded},  // multilingual, useEmbedded = 'fallback'
+		{"21", true, false, "useEmbedded = 'never'", wantGoldmark},     // multilingual, useEmbedded = 'never'
+		{"22", true, true, "", wantCustom},                             // multilingual, with custom hooks
+		{"23", true, true, "enableDefault = false", wantCustom},        // multilingual, with custom hooks, enableDefault = false
+		{"24", true, true, "enableDefault = true", wantCustom},         // multilingual, with custom hooks, enableDefault = true
+		{"25", true, true, "useEmbedded = 'always'", wantEmbedded},     // multilingual, with custom hooks, useEmbedded = 'always'
+		{"26", true, true, "useEmbedded = 'auto'", wantCustom},         // multilingual, with custom hooks, useEmbedded = 'auto'
+		{"27", true, true, "useEmbedded = 'fallback'", wantCustom},     // multilingual, with custom hooks, useEmbedded = 'fallback'
+		{"28", true, true, "useEmbedded = 'never'", wantCustom},        // multilingual, with custom hooks, useEmbedded = 'never'
+	}
+
+	for _, tt := range tests {
+		t.Run(tt.id, func(t *testing.T) {
+			t.Parallel()
+
+			f := files
+			if tt.isMultilingual {
+				f = strings.ReplaceAll(f, "#LANGUAGES", languages)
+			}
+			if tt.hasCustomHooks {
+				f = f + customHooks
+			}
+			f = strings.ReplaceAll(f, "#KEY_VALUE", tt.keyValuePair)
+
+			b := hugolib.Test(t, f)
+			b.AssertFileContent(fileToCheck, tt.want)
+		})
+	}
+}
diff --git a/tpl/tplimpl/templatestore.go b/tpl/tplimpl/templatestore.go
index 23c821cac..008b743c7 100644
--- a/tpl/tplimpl/templatestore.go
+++ b/tpl/tplimpl/templatestore.go
@@ -44,6 +44,7 @@ import (
 	"github.com/gohugoio/hugo/hugofs/files"
 	"github.com/gohugoio/hugo/hugolib/doctree"
 	"github.com/gohugoio/hugo/identity"
+	gc "github.com/gohugoio/hugo/markup/goldmark/goldmark_config"
 	"github.com/gohugoio/hugo/media"
 	"github.com/gohugoio/hugo/metrics"
 	"github.com/gohugoio/hugo/output"
@@ -202,6 +203,9 @@ type StoreOptions struct {
 	// Whether we are in watch or server mode.
 	Watching bool
 
+	// The render hook configuration.
+	RenderHooks gc.RenderHooks
+
 	// compiled.
 	legacyMappingTaxonomy map[string]legacyOrdinalMapping
 	legacyMappingTerm     map[string]legacyOrdinalMapping
@@ -1422,20 +1426,36 @@ func (s *TemplateStore) insertTemplates(include func(fi hugofs.FileMetaInfo) boo
 
 		var ti *TemplInfo
 		var err error
-		if pi.Type() == paths.TypeShortcode {
-			ti, err = s.insertShortcode(pi, fi, partialRebuild, s.treeShortcodes)
-			if err != nil || ti == nil {
-				return err
+		var insertFunc func() (*TemplInfo, error)
+
+		insertFunc = func() (*TemplInfo, error) {
+			return s.insertTemplate(pi, fi, SubCategoryMain, partialRebuild, s.treeMain)
+		}
+
+		switch pi.Type() {
+		case paths.TypeShortcode:
+			insertFunc = func() (*TemplInfo, error) {
+				return s.insertShortcode(pi, fi, partialRebuild, s.treeShortcodes)
 			}
-		} else {
-			ti, err = s.insertTemplate(pi, fi, SubCategoryMain, partialRebuild, s.treeMain)
+		case paths.TypeMarkup:
+			skipImageRenderHook := pi.Name() == "render-image.html" && s.opts.RenderHooks.Image.UseEmbedded == "always"
+			skipLinkRenderHook := pi.Name() == "render-link.html" && s.opts.RenderHooks.Link.UseEmbedded == "always"
+			if skipImageRenderHook || skipLinkRenderHook {
+				insertFunc = nil
+			}
+		}
+
+		if insertFunc != nil {
+			ti, err = insertFunc()
 			if err != nil || ti == nil {
 				return err
 			}
 		}
 
-		if err := s.tns.readTemplateInto(ti); err != nil {
-			return err
+		if ti != nil {
+			if err := s.tns.readTemplateInto(ti); err != nil {
+				return err
+			}
 		}
 
 		return nil