WordPress开发需求:获取当前顶级父页面的所有子页面菜单
Alright, let's solve this menu problem you're stuck on. From what you've described, you need a dynamic menu that shows the full child/grandchild hierarchy of the current top-level parent page whenever you're on that parent or any of its nested pages. I'll cover two common scenarios—WordPress (since page hierarchies are core there) and a vanilla JS/static site approach.
WordPress Solution
If you're using WordPress, this is straightforward with built-in functions. Here's a tested snippet you can drop into your theme's template files (like page.php or a custom sidebar template):
<?php // Grab the currently viewed page $current_page = get_queried_object(); // Traverse up to find the top-level parent (the one with no parent page) $top_parent_id = $current_page->ID; while ($current_page->post_parent !== 0) { $current_page = get_post($current_page->post_parent); $top_parent_id = $current_page->ID; } // Fetch all child pages (including grandchildren) of the top parent $child_pages = get_pages([ 'child_of' => $top_parent_id, 'sort_column' => 'menu_order', 'sort_order' => 'ASC' ]); // Only render the menu if there are child pages to show if (!empty($child_pages)) { echo '<nav class="subpage-hierarchy-menu">'; echo '<ul>'; foreach ($child_pages as $page) { // Check if current page is this page OR a descendant of it $active_class = (is_page($page->ID) || is_page_descendant($page->ID)) ? 'class="active"' : ''; echo "<li {$active_class}>"; echo '<a href="' . get_permalink($page->ID) . '">' . esc_html(get_the_title($page->ID)) . '</a>'; echo '</li>'; } echo '</ul>'; echo '</nav>'; } // Helper function to check if current page is a descendant of a given page function is_page_descendant($parent_id) { global $post; $ancestors = get_post_ancestors($post->ID); return in_array((string)$parent_id, $ancestors); } ?>
How this works:
- Find the top parent: We start at the current page and climb up the parent chain until we hit a page with no parent (the top-level page in the hierarchy).
- Fetch all descendants: Using
get_pages()withchild_ofpulls every page nested under that top parent—regardless of how deep they are. - Active state highlighting: The
is_page_descendant()helper checks if the current page is nested under the menu item, so we can add an "active" class to highlight where the user is.
Vanilla JavaScript/Static Site Solution
If you're not using WordPress, here's a client-side approach that works with a defined page hierarchy. You'd typically generate the hierarchy object server-side, but for demonstration, we'll hardcode it:
<!-- Menu container --> <nav class="subpage-menu"> <ul id="dynamicSubmenu"></ul> </nav> <script> // Define your page structure (replace with data from your CMS/static generator) const sitePages = { home: { id: 1, parent: 0, title: "首页" }, pageA: { id: 2, parent: 0, title: "Page A", children: [ { id: 3, parent: 2, title: "Subpage A1" }, { id: 4, parent: 2, title: "Subpage A2", children: [ { id: 5, parent: 4, title: "Sub-subpage A2-1" }, { id: 6, parent: 4, title: "Sub-subpage A2-2" } ]} ] }, pageB: { id: 7, parent: 0, title: "Page B", children: [] }, // Add your child pages here subpageC: { id: 8, parent: 0, title: "Subpage C" } }; // Get current page ID (replace with logic to detect current page, e.g., from URL) const currentPageId = 5; // Example: user is on Sub-subpage A2-1 // Helper: Find a page by ID recursively function findPageById(id, pages = sitePages) { for (const key in pages) { const page = pages[key]; if (page.id === id) return { ...page, key }; if (page.children) { const found = findPageById(id, page.children); if (found) return found; } } return null; } // Helper: Get the top-level parent ID of a page function getTopParentId(pageId) { let currentId = pageId; while (true) { const page = findPageById(currentId); if (page.parent === 0) return currentId; currentId = page.parent; } } // Helper: Get all descendants of a parent page function getAllDescendants(parentId, pages = sitePages) { let descendants = []; for (const key in pages) { const page = pages[key]; if (page.parent === parentId) { descendants.push({ ...page, key }); if (page.children) descendants = descendants.concat(getAllDescendants(parentId, page.children)); } if (page.children) descendants = descendants.concat(getAllDescendants(parentId, page.children)); } // Remove duplicates from nested traversal return [...new Map(descendants.map(p => [p.id, p])).values()]; } // Helper: Check if current page is a descendant of a given page function isDescendant(pageId, parentId) { let currentId = pageId; while (currentId !== 0) { const page = findPageById(currentId); if (page.parent === parentId) return true; currentId = page.parent; } return false; } // Build the menu const topParentId = getTopParentId(currentPageId); const menuItems = getAllDescendants(topParentId); const menuElement = document.getElementById('dynamicSubmenu'); menuItems.forEach(item => { const li = document.createElement('li'); const link = document.createElement('a'); link.href = `/${item.key}`; // Generate URL based on page key (adjust as needed) link.textContent = item.title; // Add active class if current page is this item or its descendant if (item.id === currentPageId || isDescendant(currentPageId, item.id)) { li.classList.add('active'); } li.appendChild(link); menuElement.appendChild(li); }); </script>
How this works:
- Define the hierarchy: We start with an object representing all pages and their parent/child relationships.
- Locate the top parent: Same logic as the WordPress version—climb up from the current page to find the top-level parent.
- Fetch all descendants: A recursive function grabs every page nested under the top parent.
- Render the menu: We dynamically create list items and links, adding an active class to highlight the current position.
Both solutions will show exactly what you need: when on Page A or any of its children/grandchildren, the menu displays Subpage A1, Subpage A2, Sub-subpage A2-1, and Sub-subpage A2-2.
内容的提问来源于stack exchange,提问作者bezkitu

