Repository: gohugoio/hugo (language: go)

Issue:
logos are in the same name and missing width and height settings
hugo version 0.146.4, 0.146.5 and 0.146.6 

I have 2 logos, one for header and the other is for footer.  When I upgraded from 0.146.3 to the latest version 0.146.4 to 0.146.6, the logos are displayed abnormal.

After checking the public/index.html and learnt that the header and footer logos are in the same name and there are missing "width" and "height" settings.





Discussion / hints:
>After checking the public/index.html and learnt that the header and footer logos are in the same name and there are missing "width" and "height" settings.

Can you elaborate a little about what you mean by "same name" here? It's not obvious to me what you mean.
I have two logos, one for header and the other for footer; the name of them are "logo-header.png" and "logo-footer.png" respectively.  However, the the content of index.html are both the same as ```"<img src="logo-header.png" />"``` without "logo-footer.png" for the footer logo.
Your description still leaves me guessing ... Can you point me to the site source on GitHub?
Sounds like #13596
I'm closing this as duplicate of #13596

Fix patch:
diff --git a/common/paths/pathparser.go b/common/paths/pathparser.go
index c04f2022e4f..b0a2f9fc4d0 100644
--- a/common/paths/pathparser.go
+++ b/common/paths/pathparser.go
@@ -124,14 +124,15 @@ func (pp *PathParser) parseIdentifier(component, s string, p *Path, i, lastDot i
 	if p.posContainerHigh != -1 {
 		return
 	}
-	mayHaveLang := pp.LanguageIndex != nil
+	mayHaveLang := p.posIdentifierLanguage == -1 && pp.LanguageIndex != nil
 	mayHaveLang = mayHaveLang && (component == files.ComponentFolderContent || component == files.ComponentFolderLayouts)
 	mayHaveOutputFormat := component == files.ComponentFolderLayouts
-	mayHaveKind := mayHaveOutputFormat
+	mayHaveKind := p.posIdentifierKind == -1 && mayHaveOutputFormat
+	mayHaveLayout := component == files.ComponentFolderLayouts
 
 	var found bool
 	var high int
-	if len(p.identifiers) > 0 {
+	if len(p.identifiersKnown) > 0 {
 		high = lastDot
 	} else {
 		high = len(p.s)
@@ -139,9 +140,9 @@ func (pp *PathParser) parseIdentifier(component, s string, p *Path, i, lastDot i
 	id := types.LowHigh[string]{Low: i + 1, High: high}
 	sid := p.s[id.Low:id.High]
 
-	if len(p.identifiers) == 0 {
+	if len(p.identifiersKnown) == 0 {
 		// The first is always the extension.
-		p.identifiers = append(p.identifiers, id)
+		p.identifiersKnown = append(p.identifiersKnown, id)
 		found = true
 
 		// May also be the output format.
@@ -164,8 +165,8 @@ func (pp *PathParser) parseIdentifier(component, s string, p *Path, i, lastDot i
 			}
 			found = langFound
 			if langFound {
-				p.identifiers = append(p.identifiers, id)
-				p.posIdentifierLanguage = len(p.identifiers) - 1
+				p.identifiersKnown = append(p.identifiersKnown, id)
+				p.posIdentifierLanguage = len(p.identifiersKnown) - 1
 
 			}
 		}
@@ -177,28 +178,33 @@ func (pp *PathParser) parseIdentifier(component, s string, p *Path, i, lastDot i
 			// false positives on the form css.html.
 			if pp.IsOutputFormat(sid, p.Ext()) {
 				found = true
-				p.identifiers = append(p.identifiers, id)
-				p.posIdentifierOutputFormat = len(p.identifiers) - 1
+				p.identifiersKnown = append(p.identifiersKnown, id)
+				p.posIdentifierOutputFormat = len(p.identifiersKnown) - 1
 			}
 		}
 
 		if !found && mayHaveKind {
 			if kinds.GetKindMain(sid) != "" {
 				found = true
-				p.identifiers = append(p.identifiers, id)
-				p.posIdentifierKind = len(p.identifiers) - 1
+				p.identifiersKnown = append(p.identifiersKnown, id)
+				p.posIdentifierKind = len(p.identifiersKnown) - 1
 			}
 		}
 
 		if !found && sid == identifierBaseof {
 			found = true
-			p.identifiers = append(p.identifiers, id)
-			p.posIdentifierBaseof = len(p.identifiers) - 1
+			p.identifiersKnown = append(p.identifiersKnown, id)
+			p.posIdentifierBaseof = len(p.identifiersKnown) - 1
+		}
+
+		if !found && mayHaveLayout {
+			p.identifiersKnown = append(p.identifiersKnown, id)
+			p.posIdentifierLayout = len(p.identifiersKnown) - 1
+			found = true
 		}
 
 		if !found {
-			p.identifiers = append(p.identifiers, id)
-			p.identifiersUnknown = append(p.identifiersUnknown, len(p.identifiers)-1)
+			p.identifiersUnknown = append(p.identifiersUnknown, id)
 		}
 
 	}
@@ -252,13 +258,13 @@ func (pp *PathParser) doParse(component, s string, p *Path) (*Path, error) {
 		}
 	}
 
-	if len(p.identifiers) > 0 {
+	if len(p.identifiersKnown) > 0 {
 		isContentComponent := p.component == files.ComponentFolderContent || p.component == files.ComponentFolderArchetypes
 		isContent := isContentComponent && pp.IsContentExt(p.Ext())
-		id := p.identifiers[len(p.identifiers)-1]
+		id := p.identifiersKnown[len(p.identifiersKnown)-1]
 
-		if id.High > p.posContainerHigh {
-			b := p.s[p.posContainerHigh:id.High]
+		if id.Low > p.posContainerHigh {
+			b := p.s[p.posContainerHigh : id.Low-1]
 			if isContent {
 				switch b {
 				case "index":
@@ -294,6 +300,16 @@ func (pp *PathParser) doParse(component, s string, p *Path) (*Path, error) {
 		}
 	}
 
+	if p.pathType == TypeShortcode && p.posIdentifierLayout != -1 {
+		// myshortcode or myshortcode.html, no layout.
+		if len(p.identifiersKnown) <= 2 {
+			p.posIdentifierLayout = -1
+		} else {
+			// First is always the name.
+			p.posIdentifierLayout--
+		}
+	}
+
 	return p, nil
 }
 
@@ -350,13 +366,14 @@ type Path struct {
 	component string
 	pathType  Type
 
-	identifiers []types.LowHigh[string]
+	identifiersKnown   []types.LowHigh[string]
+	identifiersUnknown []types.LowHigh[string]
 
 	posIdentifierLanguage     int
 	posIdentifierOutputFormat int
 	posIdentifierKind         int
+	posIdentifierLayout       int
 	posIdentifierBaseof       int
-	identifiersUnknown        []int
 	disabled                  bool
 
 	trimLeadingSlash bool
@@ -388,10 +405,11 @@ func (p *Path) reset() {
 	p.posSectionHigh = -1
 	p.component = ""
 	p.pathType = 0
-	p.identifiers = p.identifiers[:0]
+	p.identifiersKnown = p.identifiersKnown[:0]
 	p.posIdentifierLanguage = -1
 	p.posIdentifierOutputFormat = -1
 	p.posIdentifierKind = -1
+	p.posIdentifierLayout = -1
 	p.posIdentifierBaseof = -1
 	p.disabled = false
 	p.trimLeadingSlash = false
@@ -479,7 +497,7 @@ func (p *Path) Name() string {
 // Name returns the last element of path without any extension.
 func (p *Path) NameNoExt() string {
 	if i := p.identifierIndex(0); i != -1 {
-		return p.s[p.posContainerHigh : p.identifiers[i].Low-1]
+		return p.s[p.posContainerHigh : p.identifiersKnown[i].Low-1]
 	}
 	return p.s[p.posContainerHigh:]
 }
@@ -491,7 +509,7 @@ func (p *Path) NameNoLang() string {
 		return p.Name()
 	}
 
-	return p.s[p.posContainerHigh:p.identifiers[i].Low-1] + p.s[p.identifiers[i].High:]
+	return p.s[p.posContainerHigh:p.identifiersKnown[i].Low-1] + p.s[p.identifiersKnown[i].High:]
 }
 
 // BaseNameNoIdentifier returns the logical base name for a resource without any identifier (e.g. no extension).
@@ -510,15 +528,15 @@ func (p *Path) NameNoIdentifier() string {
 }
 
 func (p *Path) nameLowHigh() types.LowHigh[string] {
-	if len(p.identifiers) > 0 {
-		lastID := p.identifiers[len(p.identifiers)-1]
+	if len(p.identifiersKnown) > 0 {
+		lastID := p.identifiersKnown[len(p.identifiersKnown)-1]
 		if p.posContainerHigh == lastID.Low {
 			// The last identifier is the name.
 			return lastID
 		}
 		return types.LowHigh[string]{
 			Low:  p.posContainerHigh,
-			High: p.identifiers[len(p.identifiers)-1].Low - 1,
+			High: p.identifiersKnown[len(p.identifiersKnown)-1].Low - 1,
 		}
 	}
 	return types.LowHigh[string]{
@@ -566,7 +584,7 @@ func (p *Path) PathNoIdentifier() string {
 
 // PathBeforeLangAndOutputFormatAndExt returns the path up to the first identifier that is not a language or output format.
 func (p *Path) PathBeforeLangAndOutputFormatAndExt() string {
-	if len(p.identifiers) == 0 {
+	if len(p.identifiersKnown) == 0 {
 		return p.norm(p.s)
 	}
 	i := p.identifierIndex(0)
@@ -582,7 +600,7 @@ func (p *Path) PathBeforeLangAndOutputFormatAndExt() string {
 		return p.norm(p.s)
 	}
 
-	id := p.identifiers[i]
+	id := p.identifiersKnown[i]
 	return p.norm(p.s[:id.Low-1])
 }
 
@@ -633,11 +651,11 @@ func (p *Path) BaseNoLeadingSlash() string {
 }
 
 func (p *Path) base(preserveExt, isBundle bool) string {
-	if len(p.identifiers) == 0 {
+	if len(p.identifiersKnown) == 0 {
 		return p.norm(p.s)
 	}
 
-	if preserveExt && len(p.identifiers) == 1 {
+	if preserveExt && len(p.identifiersKnown) == 1 {
 		// Preserve extension.
 		return p.norm(p.s)
 	}
@@ -659,7 +677,7 @@ func (p *Path) base(preserveExt, isBundle bool) string {
 	}
 
 	// For txt files etc. we want to preserve the extension.
-	id := p.identifiers[0]
+	id := p.identifiersKnown[0]
 
 	return p.norm(p.s[:high] + p.s[id.Low-1:id.High])
 }
@@ -676,6 +694,10 @@ func (p *Path) Kind() string {
 	return p.identifierAsString(p.posIdentifierKind)
 }
 
+func (p *Path) Layout() string {
+	return p.identifierAsString(p.posIdentifierLayout)
+}
+
 func (p *Path) Lang() string {
 	return p.identifierAsString(p.posIdentifierLanguage)
 }
@@ -689,8 +711,8 @@ func (p *Path) Disabled() bool {
 }
 
 func (p *Path) Identifiers() []string {
-	ids := make([]string, len(p.identifiers))
-	for i, id := range p.identifiers {
+	ids := make([]string, len(p.identifiersKnown))
+	for i, id := range p.identifiersKnown {
 		ids[i] = p.s[id.Low:id.High]
 	}
 	return ids
@@ -699,7 +721,7 @@ func (p *Path) Identifiers() []string {
 func (p *Path) IdentifiersUnknown() []string {
 	ids := make([]string, len(p.identifiersUnknown))
 	for i, id := range p.identifiersUnknown {
-		ids[i] = p.s[p.identifiers[id].Low:p.identifiers[id].High]
+		ids[i] = p.s[id.Low:id.High]
 	}
 	return ids
 }
@@ -735,12 +757,12 @@ func (p *Path) identifierAsString(i int) string {
 		return ""
 	}
 
-	id := p.identifiers[i]
+	id := p.identifiersKnown[i]
 	return p.s[id.Low:id.High]
 }
 
 func (p *Path) identifierIndex(i int) int {
-	if i < 0 || i >= len(p.identifiers) {
+	if i < 0 || i >= len(p.identifiersKnown) {
 		return -1
 	}
 	return i


Test patch:
diff --git a/common/paths/pathparser_test.go b/common/paths/pathparser_test.go
index fd1590c73e0..a6194e756d2 100644
--- a/common/paths/pathparser_test.go
+++ b/common/paths/pathparser_test.go
@@ -171,22 +171,25 @@ func TestParse(t *testing.T) {
 			"/a/b.a.b.no.txt",
 			func(c *qt.C, p *Path) {
 				c.Assert(p.Name(), qt.Equals, "b.a.b.no.txt")
-				c.Assert(p.NameNoIdentifier(), qt.Equals, "b")
+				c.Assert(p.NameNoIdentifier(), qt.Equals, "b.a.b")
 				c.Assert(p.NameNoLang(), qt.Equals, "b.a.b.txt")
-				c.Assert(p.Identifiers(), qt.DeepEquals, []string{"txt", "no", "b", "a", "b"})
+				c.Assert(p.Identifiers(), qt.DeepEquals, []string{"txt", "no"})
 				c.Assert(p.IdentifiersUnknown(), qt.DeepEquals, []string{"b", "a", "b"})
-				c.Assert(p.Base(), qt.Equals, "/a/b.txt")
-				c.Assert(p.BaseNoLeadingSlash(), qt.Equals, "a/b.txt")
+				c.Assert(p.Base(), qt.Equals, "/a/b.a.b.txt")
+				c.Assert(p.BaseNoLeadingSlash(), qt.Equals, "a/b.a.b.txt")
 				c.Assert(p.Path(), qt.Equals, "/a/b.a.b.no.txt")
-				c.Assert(p.PathNoLang(), qt.Equals, "/a/b.txt")
+				c.Assert(p.PathNoLang(), qt.Equals, "/a/b.a.b.txt")
 				c.Assert(p.Ext(), qt.Equals, "txt")
-				c.Assert(p.PathNoIdentifier(), qt.Equals, "/a/b")
+				c.Assert(p.PathNoIdentifier(), qt.Equals, "/a/b.a.b")
 			},
 		},
 		{
 			"Home branch cundle",
 			"/_index.md",
 			func(c *qt.C, p *Path) {
+				c.Assert(p.Identifiers(), qt.DeepEquals, []string{"md"})
+				c.Assert(p.IsBranchBundle(), qt.IsTrue)
+				c.Assert(p.IsBundle(), qt.IsTrue)
 				c.Assert(p.Base(), qt.Equals, "/")
 				c.Assert(p.BaseReTyped("foo"), qt.Equals, "/foo")
 				c.Assert(p.Path(), qt.Equals, "/_index.md")
@@ -206,7 +209,8 @@ func TestParse(t *testing.T) {
 				c.Assert(p.ContainerDir(), qt.Equals, "")
 				c.Assert(p.Dir(), qt.Equals, "/a")
 				c.Assert(p.Ext(), qt.Equals, "md")
-				c.Assert(p.Identifiers(), qt.DeepEquals, []string{"md", "index"})
+				c.Assert(p.IdentifiersUnknown(), qt.DeepEquals, []string{"index"})
+				c.Assert(p.Identifiers(), qt.DeepEquals, []string{"md"})
 				c.Assert(p.IsBranchBundle(), qt.IsFalse)
 				c.Assert(p.IsBundle(), qt.IsTrue)
 				c.Assert(p.IsLeafBundle(), qt.IsTrue)
@@ -228,7 +232,7 @@ func TestParse(t *testing.T) {
 				c.Assert(p.ContainerDir(), qt.Equals, "/a")
 				c.Assert(p.Dir(), qt.Equals, "/a/b")
 				c.Assert(p.Ext(), qt.Equals, "md")
-				c.Assert(p.Identifiers(), qt.DeepEquals, []string{"md", "no", "index"})
+				c.Assert(p.Identifiers(), qt.DeepEquals, []string{"md", "no"})
 				c.Assert(p.IsBranchBundle(), qt.IsFalse)
 				c.Assert(p.IsBundle(), qt.IsTrue)
 				c.Assert(p.IsLeafBundle(), qt.IsTrue)
@@ -250,7 +254,7 @@ func TestParse(t *testing.T) {
 				c.Assert(p.Container(), qt.Equals, "b")
 				c.Assert(p.ContainerDir(), qt.Equals, "/a")
 				c.Assert(p.Ext(), qt.Equals, "md")
-				c.Assert(p.Identifiers(), qt.DeepEquals, []string{"md", "no", "_index"})
+				c.Assert(p.Identifiers(), qt.DeepEquals, []string{"md", "no"})
 				c.Assert(p.IsBranchBundle(), qt.IsTrue)
 				c.Assert(p.IsBundle(), qt.IsTrue)
 				c.Assert(p.IsLeafBundle(), qt.IsFalse)
@@ -289,7 +293,7 @@ func TestParse(t *testing.T) {
 			func(c *qt.C, p *Path) {
 				c.Assert(p.Base(), qt.Equals, "/a/b/index.txt")
 				c.Assert(p.Ext(), qt.Equals, "txt")
-				c.Assert(p.Identifiers(), qt.DeepEquals, []string{"txt", "no", "index"})
+				c.Assert(p.Identifiers(), qt.DeepEquals, []string{"txt", "no"})
 				c.Assert(p.IsLeafBundle(), qt.IsFalse)
 				c.Assert(p.PathNoIdentifier(), qt.Equals, "/a/b/index")
 			},
@@ -372,7 +376,7 @@ func TestParse(t *testing.T) {
 	}
 	for _, test := range tests {
 		c.Run(test.name, func(c *qt.C) {
-			if test.name != "Basic Markdown file" {
+			if test.name != "Home branch cundle" {
 				// return
 			}
 			test.assert(c, testParser.Parse(files.ComponentFolderContent, test.path))
@@ -401,10 +405,58 @@ func TestParseLayouts(t *testing.T) {
 			"/list.no.html",
 			func(c *qt.C, p *Path) {
 				c.Assert(p.Identifiers(), qt.DeepEquals, []string{"html", "no", "list"})
+				c.Assert(p.IdentifiersUnknown(), qt.DeepEquals, []string{})
 				c.Assert(p.Base(), qt.Equals, "/list.html")
 				c.Assert(p.Lang(), qt.Equals, "no")
 			},
 		},
+		{
+			"Kind",
+			"/section.no.html",
+			func(c *qt.C, p *Path) {
+				c.Assert(p.Kind(), qt.Equals, kinds.KindSection)
+				c.Assert(p.Identifiers(), qt.DeepEquals, []string{"html", "no", "section"})
+				c.Assert(p.IdentifiersUnknown(), qt.DeepEquals, []string{})
+				c.Assert(p.Base(), qt.Equals, "/section.html")
+				c.Assert(p.Lang(), qt.Equals, "no")
+			},
+		},
+		{
+			"Layout",
+			"/list.section.no.html",
+			func(c *qt.C, p *Path) {
+				c.Assert(p.Layout(), qt.Equals, "list")
+				c.Assert(p.Identifiers(), qt.DeepEquals, []string{"html", "no", "section", "list"})
+				c.Assert(p.IdentifiersUnknown(), qt.DeepEquals, []string{})
+				c.Assert(p.Base(), qt.Equals, "/list.html")
+				c.Assert(p.Lang(), qt.Equals, "no")
+			},
+		},
+		{
+			"Layout multiple",
+			"/maylayout.list.section.no.html",
+			func(c *qt.C, p *Path) {
+				c.Assert(p.Layout(), qt.Equals, "maylayout")
+				c.Assert(p.Identifiers(), qt.DeepEquals, []string{"html", "no", "section", "list", "maylayout"})
+				c.Assert(p.IdentifiersUnknown(), qt.DeepEquals, []string{})
+				c.Assert(p.Base(), qt.Equals, "/maylayout.html")
+				c.Assert(p.Lang(), qt.Equals, "no")
+			},
+		},
+		{
+			"Layout shortcode",
+			"/_shortcodes/myshort.list.no.html",
+			func(c *qt.C, p *Path) {
+				c.Assert(p.Layout(), qt.Equals, "list")
+			},
+		},
+		{
+			"Layout baseof",
+			"/baseof.list.no.html",
+			func(c *qt.C, p *Path) {
+				c.Assert(p.Layout(), qt.Equals, "list")
+			},
+		},
 		{
 			"Lang and output format",
 			"/list.no.amp.not.html",
@@ -429,6 +481,20 @@ func TestParseLayouts(t *testing.T) {
 				c.Assert(p.OutputFormat(), qt.Equals, "html")
 			},
 		},
+		{
+			"Shortcode with layout",
+			"/_shortcodes/myshortcode.list.html",
+			func(c *qt.C, p *Path) {
+				c.Assert(p.Base(), qt.Equals, "/_shortcodes/myshortcode.html")
+				c.Assert(p.Type(), qt.Equals, TypeShortcode)
+				c.Assert(p.Identifiers(), qt.DeepEquals, []string{"html", "list", "myshortcode"})
+				c.Assert(p.PathNoIdentifier(), qt.Equals, "/_shortcodes/myshortcode")
+				c.Assert(p.PathBeforeLangAndOutputFormatAndExt(), qt.Equals, "/_shortcodes/myshortcode.list")
+				c.Assert(p.Lang(), qt.Equals, "")
+				c.Assert(p.Kind(), qt.Equals, "")
+				c.Assert(p.OutputFormat(), qt.Equals, "html")
+			},
+		},
 		{
 			"Sub dir",
 			"/pages/home.html",
@@ -445,7 +511,7 @@ func TestParseLayouts(t *testing.T) {
 			"/pages/baseof.list.section.fr.amp.html",
 			func(c *qt.C, p *Path) {
 				c.Assert(p.Identifiers(), qt.DeepEquals, []string{"html", "amp", "fr", "section", "list", "baseof"})
-				c.Assert(p.IdentifiersUnknown(), qt.DeepEquals, []string{"list"})
+				c.Assert(p.IdentifiersUnknown(), qt.DeepEquals, []string{})
 				c.Assert(p.Kind(), qt.Equals, kinds.KindSection)
 				c.Assert(p.Lang(), qt.Equals, "fr")
 				c.Assert(p.OutputFormat(), qt.Equals, "amp")
@@ -501,6 +567,9 @@ func TestParseLayouts(t *testing.T) {
 
 	for _, test := range tests {
 		c.Run(test.name, func(c *qt.C) {
+			if test.name != "Baseof" {
+				// return
+			}
 			test.assert(c, testParser.Parse(files.ComponentFolderLayouts, test.path))
 		})
 	}
diff --git a/common/paths/paths_integration_test.go b/common/paths/paths_integration_test.go
index 62d40f52702..f5ea3066ac9 100644
--- a/common/paths/paths_integration_test.go
+++ b/common/paths/paths_integration_test.go
@@ -78,3 +78,26 @@ disablePathToLower = true
 	b.AssertFileContent("public/en/mysection/mybundle/index.html", "en|Single")
 	b.AssertFileContent("public/fr/MySection/MyBundle/index.html", "fr|Single")
 }
+
+func TestIssue13596(t *testing.T) {
+	t.Parallel()
+
+	files := `
+-- hugo.toml --
+disableKinds = ['home','rss','section','sitemap','taxonomy','term']
+-- content/p1/index.md --
+---
+title: p1
+---
+-- content/p1/a.1.txt --
+-- content/p1/a.2.txt --
+-- layouts/all.html --
+{{ range .Resources.Match "*" }}{{ .Name }}|{{ end }}
+`
+
+	b := hugolib.Test(t, files)
+
+	b.AssertFileContent("public/p1/index.html", "a.1.txt|a.2.txt|")
+	b.AssertFileExists("public/p1/a.1.txt", true)
+	b.AssertFileExists("public/p1/a.2.txt", true) // fails
+}
diff --git a/hugolib/collections_test.go b/hugolib/collections_test.go
index a8c817becac..f62d4c60455 100644
--- a/hugolib/collections_test.go
+++ b/hugolib/collections_test.go
@@ -39,6 +39,8 @@ title: "Page"
 `)
 	b.CreateSites().Build(BuildCfg{})
 
+	// b.H.TemplateStore.PrintDebug("", tplimpl.CategoryLayout, os.Stdout)
+
 	c.Assert(len(b.H.Sites), qt.Equals, 1)
 	c.Assert(len(b.H.Sites[0].RegularPages()), qt.Equals, 2)
 
diff --git a/hugolib/content_render_hooks_test.go b/hugolib/content_render_hooks_test.go
index 56ae0a052ab..c4e15a5c674 100644
--- a/hugolib/content_render_hooks_test.go
+++ b/hugolib/content_render_hooks_test.go
@@ -464,8 +464,6 @@ title: "Home"
 `
 	b := Test(t, files)
 
-	// b.DebugPrint("", tplimpl.CategoryShortcode)
-
 	b.AssertFileContentExact("public/index.xml", "My shortcode XML.")
 	b.AssertFileContentExact("public/index.html", "My shortcode HTML.")
 	s := b.H.Sites[0]
diff --git a/hugolib/site_test.go b/hugolib/site_test.go
index a9fe977cf5e..4d68602e51c 100644
--- a/hugolib/site_test.go
+++ b/hugolib/site_test.go
@@ -978,7 +978,7 @@ func TestRefLinking(t *testing.T) {
 		{".", "", true, "/level2/level3/"},
 		{"./", "", true, "/level2/level3/"},
 
-		{"embedded.dot.md", "", true, "/level2/level3/embedded/"},
+		{"embedded.dot.md", "", true, "/level2/level3/embedded.dot/"},
 
 		// test empty link, as well as fragment only link
 		{"", "", true, ""},
diff --git a/tpl/tplimpl/templatestore.go b/tpl/tplimpl/templatestore.go
index 5be65f874f2..dba89760895 100644
--- a/tpl/tplimpl/templatestore.go
+++ b/tpl/tplimpl/templatestore.go
@@ -654,7 +654,7 @@ func (s *TemplateStore) PrintDebug(prefix string, category Category, w io.Writer
 			return
 		}
 		s := strings.ReplaceAll(strings.TrimSpace(vv.content), "\n", " ")
-		ts := fmt.Sprintf("kind: %q layout: %q content: %.30s", vv.D.Kind, vv.D.LayoutFromTemplate, s)
+		ts := fmt.Sprintf("kind: %q layout: %q lang: %q content: %.30s", vv.D.Kind, vv.D.LayoutFromTemplate, vv.D.Lang, s)
 		fmt.Fprintf(w, "%s%s %s\n", strings.Repeat(" ", level), key, ts)
 	}
 	s.treeMain.WalkPrefix(prefix, func(key string, v map[nodeKey]*TemplInfo) (bool, error) {
@@ -1126,7 +1126,7 @@ func (s *TemplateStore) insertTemplate2(
 
 	if !replace {
 		if v, found := m[nk]; found {
-			if len(pi.IdentifiersUnknown()) >= len(v.PathInfo.IdentifiersUnknown()) {
+			if len(pi.Identifiers()) >= len(v.PathInfo.Identifiers()) {
 				// e.g. /pages/home.foo.html and  /pages/home.html where foo may be a valid language name in another site.
 				return nil, nil
 			}
@@ -1261,7 +1261,10 @@ func (s *TemplateStore) insertTemplates(include func(fi hugofs.FileMetaInfo) boo
 			)
 
 			base := piOrig.PathBeforeLangAndOutputFormatAndExt()
-			identifiers := pi.IdentifiersUnknown()
+			identifiers := []string{}
+			if pi.Layout() != "" {
+				identifiers = append(identifiers, pi.Layout())
+			}
 			if pi.Kind() != "" {
 				identifiers = append(identifiers, pi.Kind())
 			}
@@ -1576,24 +1579,12 @@ func (s *TemplateStore) toKeyCategoryAndDescriptor(p *paths.Path) (string, strin
 	outputFormat, mediaType := s.resolveOutputFormatAndOrMediaType(p.OutputFormat(), p.Ext())
 	nameNoIdentifier := p.NameNoIdentifier()
 
-	var layout string
-	unknownids := p.IdentifiersUnknown()
-	if p.Type() == paths.TypeShortcode {
-		if len(unknownids) > 1 {
-			// The name is the last identifier.
-			layout = unknownids[len(unknownids)-2]
-		}
-	} else if len(unknownids) > 0 {
-		// Pick the last, closest to the base name.
-		layout = unknownids[len(unknownids)-1]
-	}
-
 	d := TemplateDescriptor{
 		Lang:               p.Lang(),
 		OutputFormat:       p.OutputFormat(),
 		MediaType:          mediaType.Type,
 		Kind:               p.Kind(),
-		LayoutFromTemplate: layout,
+		LayoutFromTemplate: p.Layout(),
 		IsPlainText:        outputFormat.IsPlainText,
 	}
 
@@ -1633,6 +1624,7 @@ func (s *TemplateStore) toKeyCategoryAndDescriptor(p *paths.Path) (string, strin
 
 	if category == CategoryShortcode {
 		k1 = p.PathNoIdentifier()
+
 		parts := strings.Split(k1, "/"+containerShortcodes+"/")
 		k1 = parts[0]
 		if len(parts) > 1 {
diff --git a/tpl/tplimpl/templatestore_integration_test.go b/tpl/tplimpl/templatestore_integration_test.go
index 06cb00212b1..bd00f82b7b2 100644
--- a/tpl/tplimpl/templatestore_integration_test.go
+++ b/tpl/tplimpl/templatestore_integration_test.go
@@ -1056,7 +1056,7 @@ All.
 
 	b := hugolib.Test(t, files, hugolib.TestOptWarn())
 
-	b.AssertLogContains("Duplicate content path")
+	b.AssertLogContains("! Duplicate content path")
 }
 
 // Issue #13577.