Skip to content

Commit 25e22b9

Browse files
committed
Use index page titles for auto-generated section names
When the 'nav' configuration is not explicitly set, MkDocs generates navigation sections from directory names. This change updates those auto-generated section titles to use the index page's title instead of the raw directory name when an index page exists in the section. For example, an 'about/' directory with 'about/index.md' whose title is 'About this Project' will now show 'About this Project' as the section name instead of 'about'. This only applies after pages have been read/rendered (titles are resolved from metadata or headings), and only affects sections that contain an index page. Fixes #3656, #3356
1 parent ca20a77 commit 25e22b9

3 files changed

Lines changed: 67 additions & 2 deletions

File tree

mkdocs/commands/build.py

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,11 @@
2020
get_files,
2121
set_exclusions,
2222
)
23-
from mkdocs.structure.nav import Navigation, get_navigation
23+
from mkdocs.structure.nav import (
24+
Navigation,
25+
_set_section_titles_from_index_pages,
26+
get_navigation,
27+
)
2428
from mkdocs.structure.pages import Page
2529
from mkdocs.utils import DuplicateFilter # noqa: F401 - legacy re-export
2630
from mkdocs.utils import templates
@@ -351,6 +355,9 @@ def build(
351355
+ "\n - ".join(excluded)
352356
)
353357

358+
# Update auto-generated section titles from index page titles.
359+
_set_section_titles_from_index_pages(nav.items)
360+
354361
# Run `env` plugin events.
355362
env = config.plugins.on_env(env, config=config, files=files)
356363

mkdocs/structure/nav.py

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -265,3 +265,26 @@ def _add_previous_and_next_links(pages: list[Page]) -> None:
265265
zipped = zip(bookended[:-2], pages, bookended[2:])
266266
for page0, page1, page2 in zipped:
267267
page1.previous_page, page1.next_page = page0, page2
268+
269+
270+
def _set_section_titles_from_index_pages(items: list[StructureItem]) -> None:
271+
"""
272+
For auto-generated navigation, update section titles to use the index
273+
page's title instead of the directory name.
274+
275+
When `nav` is not explicitly configured, MkDocs generates section names
276+
from directory names (e.g. "about" for an "about/" directory). If the
277+
section contains an index page (e.g. "about/index.md"), this function
278+
uses that page's title as the section title instead.
279+
280+
This only applies when `page.title` is not None (i.e. the page has
281+
been read/rendered, so its title is known from metadata or headings).
282+
"""
283+
for item in items:
284+
if not item.is_section:
285+
continue
286+
for child in item.children:
287+
if child.is_page and child.is_index and child.title is not None:
288+
item.title = child.title
289+
break
290+
_set_section_titles_from_index_pages(item.children)

mkdocs/tests/structure/nav_tests.py

Lines changed: 36 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,12 @@
44
import unittest
55

66
from mkdocs.structure.files import File, Files, set_exclusions
7-
from mkdocs.structure.nav import Section, _get_by_type, get_navigation
7+
from mkdocs.structure.nav import (
8+
Section,
9+
_get_by_type,
10+
_set_section_titles_from_index_pages,
11+
get_navigation,
12+
)
813
from mkdocs.structure.pages import Page
914
from mkdocs.tests.base import dedent, load_config
1015

@@ -608,3 +613,33 @@ def test_get_by_type_nested_sections(self):
608613
files = Files(fs)
609614
site_navigation = get_navigation(files, cfg)
610615
self.assertEqual(len(_get_by_type(site_navigation, Section)), 2)
616+
617+
def test_smart_section_titles_from_index_pages(self):
618+
"""Section titles use index page titles instead of directory names."""
619+
cfg = load_config(site_url="http://example.com/")
620+
fs = [
621+
"index.md",
622+
"about/index.md",
623+
"about/license.md",
624+
"api-guide/index.md",
625+
"api-guide/running.md",
626+
]
627+
files = Files(
628+
[File(s, cfg.docs_dir, cfg.site_dir, cfg.use_directory_urls) for s in fs]
629+
)
630+
site_navigation = get_navigation(files, cfg)
631+
632+
# Before update: sections use directory names
633+
about_section = site_navigation.items[1]
634+
api_section = site_navigation.items[2]
635+
self.assertEqual(about_section.title, "About")
636+
self.assertEqual(api_section.title, "Api guide")
637+
638+
# Set titles on index pages (as if they were read/rendered)
639+
about_section.children[0].title = "About This Project"
640+
api_section.children[0].title = "API Reference"
641+
642+
_set_section_titles_from_index_pages(site_navigation.items)
643+
644+
self.assertEqual(about_section.title, "About This Project")
645+
self.assertEqual(api_section.title, "API Reference")

0 commit comments

Comments
 (0)