I'm trying to modify an admin query where I need to exclude a few pages based on two conditions:

  1. Exclude based on certain titles
  2. Exclude based on certain pages, including its children pages

To understand what I need to accomplish, the idea is the following. I have these pages:

  • PageA
  • PageB
  • Parent1
    • Child1
    • Child2
  • Parent2
    • Child3
    • Child4
  • Parent3
    • Child5
    • Child6
  • PageY
  • PageZ

Now, my actual code allows me to exclude "PageB" and "PageZ" based on its title. What I'm trying to do is to exclude "Parent1" and "Parent3" and its corresponding children.

The code I'm running now is this one:

add_action('pre_get_posts', 'filter_dummy_pages');
function filter_dummy_pages($query) {
  if (function_exists('get_current_screen')) {
    $screen = get_current_screen();
    if (is_admin() and !current_user_can('manage_options') and $screen->post_type == 'page') {
      $query->set('post__not_in', get_dummy_pages());

function get_dummy_pages() {
  $result = array();
  $pages_query = array(

  foreach ($pages_query as $page) {
    $result[] = get_page_by_title($page)->ID;

  return $result;

I have tried to make a WP_Query inside get_dummy_pages(), but I get a white page, so I assume the issue is related to attepmt a query inside an actual query.

I have also tried poking the post_parent, post_parent__in and post_parent__not_in options, but I get to exclude way more pages than I want.

Which options should I consider for this use case?

  • Re the white page, please turn on WP_DEBUG - it'll tell you what you're doing wrong and will make it a heck of a lot easier to debug :)
    – Tim Malone
    Jul 8, 2016 at 3:14
  • I have WP_DEBUG and WP_DEBUG_LOG activated, but now I activated WP_DEBUG_DISPLAY and got what seems to be an infinite loop when trying to run a WP_Query in the get_dummy_pages function. Jul 8, 2016 at 14:29

1 Answer 1


Turns out that it is possible to run a WP_Query inside a pre_get_posts action keeping in mind two simple principles:

  1. pre_get_posts action will alter every query that you make, so you need to contain its action specifying which queries you need to alter. In this case, this containment is done with this line:

    if (
      and !current_user_can('manage_options')
      and $screen->post_type == 'page'
    ) {

    This means that I'm altering only the query that happens when you load edit.php?post_type=page in Administration Panel.

  2. Because of the former, pre_get_posts will alter the main query of the page, which is "query all pages". My question attempted to run a WP_Query inside an action that alters every query, so this action was also altering my "sub-queries". So, as the first principle tells us, we need to contain the action to act only on the main query, because if we don't contain it, we'll get an infinite loop. So, our "containment" line needs to know if what we're altering is actually the main query:

    if (
      and !current_user_can('manage_options')
      and $screen->post_type == 'page'
      and $query->is_main_query()  // This contains only the main query
    ) {

    So now we can run whatever WP_Query we want in the get_dummy_pages() function.

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.