In my custom theme I want to show all parent pages but for a few of those parent pages I don't want to show their subpages.

I know you can add all these subpages to the 'exclude' argument of the wp_list_pages function but I want to make sure that whenever someone adds a new subpage that that one also wouldn't be shown.

Exclude tree could be a possibility but that one also ignores the parent page.

My code:

$subtitle_walker = new Subtitle_Walker();

$args = array(
    'authors'      => '',
    'child_of'     => 0,
    'date_format'  => get_option('date_format'),
    'depth'        => 2,
    'echo'         => 1,
    'exclude'      => '',
    'exclude_tree' => '',
    'include'      => '',
    'link_after'   => '',
    'link_before'  => '',
    'post_type'    => 'page',
    'post_status'  => 'publish',
    'show_date'    => '',
    'sort_column'  => 'menu_order',
    'title_li'     => '', 
    'walker'       => new Subtitle_Walker

  • So you basically want a whitelist of pages that have subpages attached?
    – kaiser
    Commented Oct 17, 2014 at 11:06
  • @kaiser Indeed, all the other pages on the blacklist should not have their subpages shown.
    – Dragon54
    Commented Oct 17, 2014 at 11:09

1 Answer 1


The easiest thing to whitelist page IDs for wp_list_pages() is to use a self removing/single time running filter callback inside get_pages(), which is the function retrieving the data from either Cache or from a fresh query to the DB.

You have several options in there:

Filter the final DB result

To filter the list of returned pages, you can build yourself a quick plugin with a filter callback which you can use in your templates:

/** Plugin Name: WPSE (#165677) Whitelist pages Callback */
function wpse165677_whitelist_pages( $pages, $arguments )
    if ( empty( $pages ) )
        return $pages;

    // Remove instantly
    remove_filter( current_filter(), __FUNCTION__, 10 );

    // whitelist: loop through pages and build your return array of allowed pages

    return $pages;

Then, in your template:

add_filter( 'get_pages', 'wpse165677_whitelist_pages', 10, 2 );
wp_list_pages( [
    // your arguments
] );

This queries some unnecessary pages, but it's a quick solution and might not hurt performance unless you have hundreds of pages.

Ignore not-whitelisted pages in the MarkUp

Simply build a custom walker that only builds subpage MarkUp for your whitelisted pages.

Pre fetch and exclude pages

You could do a query for only the ID

    "SELECT id 
    WHERE {$wpdb->posts}.post_type = 'page' 
        AND {$wpdb->posts}.id IN (%s)",
    join( ",", [ /* IDs Array */ ] ),

where you then simply diff that return value against all page post type returned IDs to build a blacklist. Then return that inside a callback on the wp_list_pages_excludes, which is used to fill the exclude argument. You can use wp_parse_id_list() to make it easier to build the list.

add_filter( 'wp_list_pages_excludes', function( $blacklist )
    // logic to build blacklist
    return $blacklist;

Pass along arguments

Neither in the docBlock, nor in Codex wp_list_pages() is explained that there is no filter running on that functions arguments before they get passed to get_pages(). So the include argument works on this function as well. Keep in mind that this argument can not be used together with 'child_of', 'parent', 'exclude', 'meta_key', 'meta_value', or 'hierarchical'.


As often, the task you are facing can get solved using a lot of different ways. What you finally use is up to you and depends on your very specific requirements.

  • Thanks for the extensive amount of possible solutions. I'd wish to use your plugin solution but I don't know how to correctly implement this with a whitelist. I've also seen that you state a 4th argument in your remove_filter method. What does that '2' do?
    – Dragon54
    Commented Oct 21, 2014 at 13:05
  • The 4th argument is the number of arguments. It's shouldn't be/doesn't exist on remove_filter() and I'll edit the answer.
    – kaiser
    Commented Oct 21, 2014 at 13:20

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.