Remove pages from backend list *and* update counter accordingly

I hidden some pages using 'parse_query' hook, but the count for ‘Published’ pages didn’t changed… Where I should hook to change it?

Update the page status count in admin

Read More

My code so far:

$query->query_vars['post__not_in'] = array(4);

Related posts

Leave a Reply

2 comments

  1. Yes, the count for pages in various statuses that you see above the list table is obtained running wp_count_posts but the pages in the table are obtained running a WP_Query and the 2 things are completely unrelated.

    If you want to also modify the count, you have to filter also the output of wp_count_posts using the 'wp_count_posts' filter hook.

    Also you should check the status of the page(s) you want to exclude from edit, because wp_count_posts count all the statuses separately.

    So we have 2 tasks:

    • remove the pages from the query
    • remove the pages from the count

    I’ll write 2 functions, for the 2 tasks, and in both I need to check if we are in admin and if the current user has the needed capability and finally if the current screen is the right one. I’ll write an addtional function that does these checks, to avoid writing same code 2 times:

    function in_pages_edit() {
      if ( ! is_admin() || ! current_user_can( 'edit_pages' ) ) return FALSE; 
      $s = get_current_screen();
      return ( $s instanceof WP_Screen && $s->id === 'edit-page' );
    }
    

    Now we can add the 2 hooks for out 2 tasks, I’ll add these 2 hooks inside a 'load-edit.php' action:

    function go_exclude_pages_from_edit() {
      if ( ! in_pages_edit() ) return;
      global $exclude_pages_from_edit;
      $exclude_pages_from_edit = array( 662 ); // <-- set here the page ids to exclude
      add_filter( 'wp_count_posts', 'change_pages_count', 10, 3 );
      add_action( 'pre_get_posts', 'exclude_pages_from_edit' );
    }
    
    add_action( 'load-edit.php', 'go_exclude_pages_from_edit' );
    

    Now we can remove the pages from being queried:

    function exclude_pages_from_edit( $query ) {
      if ( ! in_pages_edit() || ! $query->is_main_query() ) return;
      global $exclude_pages_from_edit;
      if ( ! empty($exclude_pages_from_edit) ) {
        $query->set( 'post__not_in', $exclude_pages_from_edit );
      }
    }
    

    and adjust the counts (see inline comments for explaination):

    function get_valid_page_from_post( $p ) {
      if ( $p instanceof WP_Post &&  $p->post_type === 'page' ) return $p;
    }
    
    function change_pages_count( $counts, $type, $perm  ) {
      // do nothing if not on right page
      if ( ! in_pages_edit() || $type !== 'page' ) return $counts;
      // do the work only once
      static $new_counts;
      if ( ! is_null( $new_counts ) ) return $new_counts;
      global $exclude_pages_from_edit;
      // get the pages objects and be sure they are valid pages
      $excluded = array_filter(
        array_map( 'get_post', $exclude_pages_from_edit ), 'get_valid_page_from_post'
      );
      // if no page object obtained do nothing
      if ( empty( $excluded ) ) return $counts;
      // count the statuses of the page objectt
      $statuses_excluded = array_count_values ( wp_list_pluck( $excluded, 'post_status' ) );
      // subtract from each status count the excluded pages status count
      foreach ( $statuses_excluded as $status => $num ) {
        if ( isset( $counts->$status ) ) {
          $counts->$status = (string) $counts->$status - $num;
        }       
      }
      // save the ajusted count for next running and return
      $new_counts = $counts;
      return $counts;
    }
    
  2. The post count uses the wp_count_posts() function, which ignores any query filters. You’ll need to tweak it manually with the use of the wp_count_posts filter:

    function wpse_139851_count_posts( $counts, $type ) {
        if ( $type === 'page' && ! empty( $counts->publish ) )
            $counts->publish--; // Decrease by 1
        return $counts; 
    }
    
    add_filter( 'wp_count_posts', 'wpse_139851_count_posts', 10, 2 );