I’m displaying a simple sitemap with wp_list_pages();
$args = array(
'sort_column' => 'menu_order',
'title_li' => '',
'post_status' => 'publish'
);
wp_list_pages( $args );
The problem is that by default this also shows the published children of draft pages, like so :
Page 1 (published) -> displayed
— Page 2 (draft) -> not displayed
—— Page 3 (published) -> displayed
What I would like to achieve is :
Page 1 (published) -> displayed
— Page 2 (draft) -> not displayed
—— Page 3 (published) -> not displayed
I suspect a custom Walker would do the trick, but I could never really understand how those work..
Is there a way to hide those child pages without having to set them all to draft ?
Edit:
To clarify, let’s try some imagery. So you have a tree with the complete hierarchy of your pages. We are climbing up the tree. The moment we encounter a a draft branch, we cut it down. Naturally all the other branches attached to it further along are also discarded (no matter if they are drafts or not). I hope that explains it better.
Here is an example with a somewhat deep hierarchy :
Page 1 (published) -> displayed
— Page 2 (draft) -> not displayed <- Cut here and exclude all further children
—— Page 3 (published) -> not displayed
——— Page 4 (published) -> not displayed
———— Page 5 (draft) -> not displayed
————— Page 6 (published) -> not displayed
4 s
Great answers above. I took on the challenge trying to find yet another way to solve this.
The exclude
parameter:
We could try:
'exclude' => wpse_exclude_drafts_branches()
where:
function wpse_exclude_drafts_branches()
{
global $wpdb;
$exclude = array();
$results = $wpdb->get_col( "SELECT ID FROM {$wpdb->posts} where post_status="draft" AND post_type="page" " );
$exclude = array_merge( $exclude, $results) ;
while ( $results ):
$results = $wpdb->get_col( "SELECT DISTINCT ID FROM {$wpdb->posts} WHERE post_type="page" AND post_status="publish" AND post_parent > 0 AND post_parent IN (" . join( ',', $results ) . ") " );
$exclude = array_merge( $exclude, $results) ;
endwhile;
return join( ',', $exclude );
}
and the number of queries depends on the tree depth.
Update:
The exclude_tree
parameter:
I just noticed the exclude_tree
parameter mentioned on the Codex page, so I wonder if this would work (untested) to exclude the whole of the draft nodes branches:
$exclude = get_posts(
array(
'post_type' => 'page',
'fields' => 'ids',
'post_status' => 'draft',
'posts_per_page' => -1,
)
);
and then use:
'exclude_tree' => join( ',', $exclude ),
with wp_list_pages()
.