wp_list_pages() but only show children on the branch you are on
-
16-04-2021 - |
Вопрос
Lets say I have this menu:
Top
|___ Sub 1
|___ Sub Sub 1
|___ Sub Sub 2
|___ Sub Sub 3
|___ Sub Sub 4
|___ Sub 2
|___ Sub Sub 1
|___ Sub Sub 2
|___ Sub Sub 3
|___ Sub Sub 4
|___ Sub 3
|___ Sub Sub 1
|___ Sub Sub 2
|___ Sub Sub 3
|___ Sub Sub 4
|___ Sub 4
|___ Sub Sub 1
|___ Sub Sub 2
|___ Sub Sub 3
|___ Sub Sub 4
I can list that menu using this:
if( 0 == $post->post_parent && 0 == count( $children ) )
return;
if( 0 == $post->post_parent )
{
$child_of = $post->ID;
}
else {
$parents = get_post_ancestors( $post->ID );
$child_of = end( $parents );
}
$args = array
(
'child_of' => $child_of,
'echo' => 0,
'title_li' => ''
);
$pages = wp_list_pages( $args );
This is fine but I don't want to show all page items. What I want is that only imediate children of the page you are on is shown.
So if I'm on page Top
the menu should appear like so:
Top
|___ Sub 1
|___ Sub 2
|___ Sub 3
|___ Sub 4
If I'm on page Top/Sub 3
the menu should appear like so:
Top
|___ Sub 1
|___ Sub 2
|___ Sub 3
|___ Sub Sub 1
|___ Sub Sub 2
|___ Sub Sub 3
|___ Sub Sub 4
|___ Sub 4
And so on, so that it can work to any depth.
Rarst put up a nice answer but this was for when using WordPress menus. I'm looking for the same for wp_list_pages(). Looking for an answer that uses a Walker or filters/hooks. I know how to solve this problem with CSS but this doesn't fix the problem of unnecessary HTML being sent to the browser.
Решение
I have come up with my own solution but I'm not convinced it's the best.
$parents = array( $post->ID );
if( 0 != $post->post_parent )
{
$parents = array_merge( $parents, get_post_ancestors( $post->ID ) );
}
$child_of = end( $parents );
$args = array
(
'child_of' => $child_of,
'echo' => 0,
'title_li' => '',
'walker' => new chg_Sub_Page_Navigation_Walker( $parents )
);
$pages = wp_list_pages( $args );
Walker:
class chg_Sub_Page_Navigation_Walker extends Walker_Page
{
var $parents = array();
function __construct( $parents )
{
$this->parents = $parents;
}
function start_el( &$output, $page, $depth, $args, $current_page )
{
if( in_array( $page->post_parent, $this->parents ) )
parent::start_el( &$output, $page, $depth, $args, $current_page );
}
function end_el( &$output, $page, $depth )
{
if( in_array( $page->post_parent, $this->parents ) )
parent::end_el( &$output, $page, $depth );
}
}
Другие советы
You can consider using a mixture of get_children() for the children of the page and page siblings and get_post_ancestors() for the ancestors:
global $post;
$pages =& get_children(array(
'post_type' => 'page',
'post_parent' => $post->ID,
));
$siblings = get_children(array(
'post_type' => 'page',
'post_parent' => $post->post_parent,
));
$ancestors = get_post_ancestors($post->ID);
Edit - a quick demonstration of the idea which can use some clean up:
<ul>
<?php
global $post;
$children =& get_children(array(
'post_type' => 'page',
'post_parent' => $post->ID,
));
$siblings = get_children(array(
'post_type' => 'page',
'post_parent' => $post->post_parent,
));
$ancestors = get_post_ancestors($post->ID);
if(!empty($ancestors)):
$ancestors = array_reverse($ancestors);
foreach($ancestors as $aid):
$p = get_post($aid);
?>
<li>
<?php echo $p->post_title ?>
<ul>
<?php endforeach?>
<?php if(!empty($siblings)): ?>
<?php foreach($siblings as $sibling): ?>
<li>
<?php echo $sibling->post_title?>
<?php if($sibling->ID == $post->ID && !empty($children)): ?>
<ul>
<?php foreach($children as $child): ?>
<li><?php echo $child->ID ?></li>
<?php endforeach?>
</ul>
<?php endif ?>
</li>
<?php endforeach ?>
<?php endif ?>
<?php foreach ($ancestors as $aid):?>
</ul></li>
<?php endforeach ?>
<?php endif ?>
</ul>
Considere use the argument "depth"
Example:
wp_list_pages( 'sort_column=menu_order&title_li=&child_of=' . $post->ID . '&echo=0&depth=1'